# HG changeset patch # User bpb # Date 1477512022 25200 # Wed Oct 26 13:00:22 2016 -0700 # Node ID 660b9155a42b921dccf264ac90688702c7e48aa8 # Parent 544828ab2a9b3ebb443f82f84d89ca682c750069 8164750: TIFF reading fails when ignoring metadata with BaselineTIFFTagSet removed Summary: Disallow not adding to metadata fields which are critical to reading the image data even when the BaselineTIFFTagSet has been removed from the TIFFImageReadParam and the ignoreMetadata flag is set. Reviewed-by: XXX diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java @@ -49,6 +49,52 @@ private long stripOrTileOffsetsPosition = -1; private long lastPosition = -1; + // + // A set of tag numbers corresponding to tags essential to decoding + // the image and metadata required to interpret its samples. + // + private static volatile Set essentialTags = null; + + private static void initializeEssentialTags() { + Set tags = essentialTags; + if (tags == null) { + essentialTags = tags = Set.of( + BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE, + BaselineTIFFTagSet.TAG_COLOR_MAP, + BaselineTIFFTagSet.TAG_COMPRESSION, + BaselineTIFFTagSet.TAG_EXTRA_SAMPLES, + BaselineTIFFTagSet.TAG_FILL_ORDER, + BaselineTIFFTagSet.TAG_ICC_PROFILE, + BaselineTIFFTagSet.TAG_IMAGE_LENGTH, + BaselineTIFFTagSet.TAG_IMAGE_WIDTH, + BaselineTIFFTagSet.TAG_JPEG_AC_TABLES, + BaselineTIFFTagSet.TAG_JPEG_DC_TABLES, + BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT, + BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, + BaselineTIFFTagSet.TAG_JPEG_PROC, + BaselineTIFFTagSet.TAG_JPEG_Q_TABLES, + BaselineTIFFTagSet.TAG_JPEG_RESTART_INTERVAL, + BaselineTIFFTagSet.TAG_JPEG_TABLES, + BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION, + BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION, + BaselineTIFFTagSet.TAG_PREDICTOR, + BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE, + BaselineTIFFTagSet.TAG_ROWS_PER_STRIP, + BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL, + BaselineTIFFTagSet.TAG_SAMPLE_FORMAT, + BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS, + BaselineTIFFTagSet.TAG_STRIP_OFFSETS, + BaselineTIFFTagSet.TAG_T4_OPTIONS, + BaselineTIFFTagSet.TAG_T6_OPTIONS, + BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS, + BaselineTIFFTagSet.TAG_TILE_LENGTH, + BaselineTIFFTagSet.TAG_TILE_OFFSETS, + BaselineTIFFTagSet.TAG_TILE_WIDTH, + BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS, + BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING + ); + } + } /** * Converts a {@code TIFFDirectory} to a {@code TIFFIFD}. @@ -507,6 +553,15 @@ List tagSetList = getTagSetList(); + boolean ensureEssentialTags = false; + TIFFTagSet baselineTagSet = null; + if (isPrimaryIFD && ignoreUnknownFields + && !tagSetList.contains(BaselineTIFFTagSet.getInstance())) { + ensureEssentialTags = true; + initializeEssentialTags(); + baselineTagSet = BaselineTIFFTagSet.getInstance(); + } + List entries = new ArrayList<>(); Object[] entryData = new Object[1]; // allocate once for later reuse. @@ -530,6 +585,11 @@ // Get the associated TIFFTag. TIFFTag tag = getTag(tagNumber, tagSetList); + if (tag == null && ensureEssentialTags + && essentialTags.contains(tagNumber)) { + tag = baselineTagSet.getTag(tagNumber); + } + // Ignore unknown fields, fields with unknown type, and fields // with count out of int range. if((tag == null && ignoreUnknownFields) diff --git a/test/javax/imageio/plugins/tiff/ReadWithoutBaselineTagSet.java b/test/javax/imageio/plugins/tiff/ReadWithoutBaselineTagSet.java new file mode 100644 --- /dev/null +++ b/test/javax/imageio/plugins/tiff/ReadWithoutBaselineTagSet.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8164750 + * @summary Verify reader does not fail when the BaselineTIFFTagSet is + * removed via the TIFFImageReadParam both when ignoring and + * not ignoring metadata. + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.plugins.tiff.BaselineTIFFTagSet; +import javax.imageio.plugins.tiff.TIFFImageReadParam; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; + +public class ReadWithoutBaselineTagSet { + private static final int WIDTH = 47; + private static final int HEIGHT = 53; + + private static final Map typeToCompression = + Map.of(BufferedImage.TYPE_3BYTE_BGR, + new String[] {null, "LZW", "JPEG", "ZLib", "PackBits"}, + BufferedImage.TYPE_BYTE_BINARY, + new String[] {null, "CCITT RLE", "CCITT T.4", "CCITT T.6", + "LZW", "PackBits"}, + BufferedImage.TYPE_BYTE_GRAY, + new String[] {null, "LZW", "JPEG", "ZLib", "PackBits"}, + BufferedImage.TYPE_USHORT_GRAY, + new String[] {null, "LZW", "ZLib", "PackBits"}); + + public static void main(String[] args) throws IOException { + test(); + } + + private static void test() throws IOException { + int failures = 0; + + for (int imageType : typeToCompression.keySet()) { + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, imageType); + System.out.println("Image: " + image.toString()); + + for (String compression : typeToCompression.get(imageType)) { + System.out.println("Compression: " + + (compression == null ? "None" : compression)); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + ImageOutputStream ios = new MemoryCacheImageOutputStream(output); + ImageWriter writer = + ImageIO.getImageWritersByFormatName("TIFF").next(); + ImageWriteParam wparam = writer.getDefaultWriteParam(); + if (compression == null) { + wparam.setCompressionMode(ImageWriteParam.MODE_DEFAULT); + } else { + wparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + wparam.setCompressionType(compression); + } + writer.setOutput(ios); + writer.write(null, new IIOImage(image, null, null), wparam); + ios.flush(); + + ImageReader reader = + ImageIO.getImageReadersByFormatName("TIFF").next(); + ByteArrayInputStream input + = new ByteArrayInputStream(output.toByteArray()); + ImageInputStream iis = new MemoryCacheImageInputStream(input); + iis.mark(); + + TIFFImageReadParam rparam = new TIFFImageReadParam(); + rparam.removeAllowedTagSet(BaselineTIFFTagSet.getInstance()); + + reader.setInput(iis, false, false); + BufferedImage resultFalse = reader.read(0, rparam); + if (resultFalse.getWidth() != WIDTH + || resultFalse.getHeight() != HEIGHT) { + System.err.printf("Read image dimensions != %d x %d%n", + WIDTH, HEIGHT); + failures++; + } else { + System.out.println("ignoreMetadata == false test passed"); + } + + iis.reset(); + reader.setInput(iis, false, true); + BufferedImage resultTrue; + try { + resultTrue = reader.read(0, rparam); + if (resultTrue.getWidth() != WIDTH + || resultTrue.getHeight() != HEIGHT) { + System.err.printf("Read image dimensions != %d x %d%n", + WIDTH, HEIGHT); + failures++; + } else { + System.out.println("ignoreMetadata == true test passed"); + } + } catch (Exception e) { + e.printStackTrace(); + failures++; + } + } + } + + if (failures != 0) { + throw new RuntimeException("Test failed with " + + failures + " errors!"); + } + } +}