# HG changeset patch # User bpb # Date 1481659357 28800 # Node ID 91fb907a87326ef5d98e9de1dae7f6698a48c4c0 # Parent fca460b63839af0e1ec99b1b62a3182f869e53ab 8154058: [TIFF] ignoreMetadata parameter of TIFFImageReader's setInput() method affects TIFFImageReadParam in non-obvious way Summary: Add readUnknownTags to TIFFImageReadParam and add ReadParamTest Reviewed-by: prr diff -r fca460b63839 -r 91fb907a8732 jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java Tue Dec 13 12:02:37 2016 -0800 @@ -541,10 +541,10 @@ } // Stream position initially at beginning, left at end - // if ignoreUnknownFields is true, do not load fields for which + // if readUnknownTags is false, do not load fields for which // a tag cannot be found in an allowed TagSet. public void initialize(ImageInputStream stream, boolean isPrimaryIFD, - boolean ignoreUnknownFields) throws IOException { + boolean ignoreMetadata, boolean readUnknownTags) throws IOException { removeTIFFFields(); @@ -553,10 +553,16 @@ List tagSetList = getTagSetList(); + // Configure essential tag variables if this is the primary IFD and + // either all metadata are being ignored, or metadata are not being + // ignored but both unknown tags are being ignored and the tag set + // list does not contain the baseline tags. boolean ensureEssentialTags = false; TIFFTagSet baselineTagSet = null; - if (isPrimaryIFD && ignoreUnknownFields - && !tagSetList.contains(BaselineTIFFTagSet.getInstance())) { + if (isPrimaryIFD && + (ignoreMetadata || + (!readUnknownTags && + !tagSetList.contains(BaselineTIFFTagSet.getInstance())))) { ensureEssentialTags = true; initializeEssentialTags(); baselineTagSet = BaselineTIFFTagSet.getInstance(); @@ -590,9 +596,12 @@ tag = baselineTagSet.getTag(tagNumber); } - // Ignore unknown fields, fields with unknown type, and fields + // Ignore non-essential fields, unknown fields unless forcibly + // being read, fields with unknown type, and fields // with count out of int range. - if((tag == null && ignoreUnknownFields) + if((ignoreMetadata && + (!ensureEssentialTags || !essentialTags.contains(tagNumber))) + || (tag == null && !readUnknownTags) || (tag != null && !tag.isDataTypeOK(type)) || longCount > Integer.MAX_VALUE) { // Skip the value/offset so as to leave the stream @@ -701,7 +710,8 @@ tagSets.add(tag.getTagSet()); TIFFIFD subIFD = new TIFFIFD(tagSets); - subIFD.initialize(stream, false, ignoreUnknownFields); + subIFD.initialize(stream, false, ignoreMetadata, + readUnknownTags); TIFFField f = new TIFFField(tag, type, e.offset, subIFD); addTIFFField(f); } else { diff -r fca460b63839 -r 91fb907a8732 jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java Tue Dec 13 12:02:37 2016 -0800 @@ -82,9 +82,10 @@ } public void initializeFromStream(ImageInputStream stream, - boolean ignoreUnknownFields) + boolean ignoreMetadata, + boolean readUnknownTags) throws IOException { - rootIFD.initialize(stream, true, ignoreUnknownFields); + rootIFD.initialize(stream, true, ignoreMetadata, readUnknownTags); } public void addShortOrLongField(int tagNumber, long value) { diff -r fca460b63839 -r 91fb907a8732 jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Tue Dec 13 12:02:37 2016 -0800 @@ -305,16 +305,19 @@ try { // Create an object to store the image metadata List tagSets; + boolean readUnknownTags = false; if (imageReadParam instanceof TIFFImageReadParam) { - tagSets - = ((TIFFImageReadParam) imageReadParam).getAllowedTagSets(); + TIFFImageReadParam tp = (TIFFImageReadParam)imageReadParam; + tagSets = tp.getAllowedTagSets(); + readUnknownTags = tp.getReadUnknownTags(); } else { tagSets = new ArrayList(1); tagSets.add(BaselineTIFFTagSet.getInstance()); } this.imageMetadata = new TIFFImageMetadata(tagSets); - imageMetadata.initializeFromStream(stream, ignoreMetadata); + imageMetadata.initializeFromStream(stream, ignoreMetadata, + readUnknownTags); } catch (IIOException iioe) { throw iioe; } catch (IOException ioe) { diff -r fca460b63839 -r 91fb907a8732 jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java Tue Dec 13 12:02:37 2016 -0800 @@ -3015,7 +3015,7 @@ List tagSets = new ArrayList(1); tagSets.add(BaselineTIFFTagSet.getInstance()); TIFFIFD rootIFD = new TIFFIFD(tagSets); - rootIFD.initialize(stream, true, true); + rootIFD.initialize(stream, true, false, false); stream.reset(); return rootIFD; diff -r fca460b63839 -r 91fb907a8732 jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html --- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html Tue Dec 13 12:02:37 2016 -0800 @@ -216,22 +216,27 @@

Metadata Issues

-By default all fields in the TIFF image file directory (IFD) are loaded into -the native image metadata object. In cases where the IFD includes fields which -contain large amounts of data this could be very inefficient. Which fields -are loaded may be controlled by setting which TIFF tags the reader is allowed -to recognize and whether it is ignoring metadata. The reader is informed to -disregard metadata as usual via the ignoreMetadata parameter of +By default all recognized fields in the TIFF image file directory (IFD) are +loaded into the native image metadata object. Which fields are loaded may be +controlled by setting which TIFF tags the reader is allowed to recognize, +whether to read fields with unrecognized tags, and whether to ignore all +metadata. The reader is informed to disregard all metadata as usual via the +ignoreMetadata parameter of ImageReader.setInput(Object,boolean,boolean). It is informed of which TIFFTags to recognize or not to recognize via -TIFFImageReadParam.addAllowedTagSet(TIFFTagSet) -and +TIFFImageReadParam.addAllowedTagSet(TIFFTagSet) and TIFFImageReadParam.removeAllowedTagSet(TIFFTagSet). -If ignoreMetadata is true, then the reader will -load into the native image metadata object only those fields which have a -TIFFTag contained in the one of the allowed -TIFFTagSets. +If ignoreMetadata is true, then only metadata +essential to reading the image will be loaded into the native image metadata +object. If ignoreMetadata is false, then the reader +will by default load into the native image metadata object only those fields +which are either essential to reading the image or have a TIFFTag +contained in the one of the allowed TIFFTagSets. Reading of +fields with tags not in the allowed TIFFTagSets may be forced +by passing in a TIFFImageReadParam on which +TIFFImageReadParam.setReadUnknownTags(boolean) has been +invoked with parameter true.

Use of a TIFFDirectory object may simplify gaining access to metadata values. An instance of diff -r fca460b63839 -r 91fb907a8732 jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java Tue Dec 13 12:02:37 2016 -0800 @@ -46,6 +46,10 @@ * {@code ExifParentTIFFTagSet}, and {@code GeoTIFFTagSet} * are included. * + *

Forcing reading of fields corresponding to {@code TIFFTag}s + * not in any of the allowed {@code TIFFTagSet}s may be effected via + * {@link #setReadUnknownTags setReadUnknownTags}. + * * @since 9 */ public final class TIFFImageReadParam extends ImageReadParam { @@ -53,6 +57,8 @@ private final List allowedTagSets = new ArrayList(4); + private boolean readUnknownTags = false; + /** * Constructs a {@code TIFFImageReadParam}. Tags defined by * the {@code TIFFTagSet}s {@code BaselineTIFFTagSet}, @@ -117,4 +123,27 @@ public List getAllowedTagSets() { return allowedTagSets; } + + /** + * Set whether to read fields corresponding to {@code TIFFTag}s not in + * the allowed {@code TIFFTagSet}s. The default setting is {@code false}. + * If the TIFF {@code ImageReader} is ignoring metadata, then a setting + * of {@code true} is overridden as all metadata are ignored except those + * essential to reading the image itself. + * + * @param readUnknownTags Whether to read fields of unrecognized tags + */ + public void setReadUnknownTags(boolean readUnknownTags) { + this.readUnknownTags = readUnknownTags; + } + + /** + * Retrieve the setting of whether to read fields corresponding to unknown + * {@code TIFFTag}s. + * + * @return Whether to read fields of unrecognized tags + */ + public boolean getReadUnknownTags() { + return readUnknownTags; + } } diff -r fca460b63839 -r 91fb907a8732 jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java --- a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java Tue Dec 13 12:02:37 2016 -0800 @@ -223,7 +223,7 @@ ImageReader reader = getTIFFReader(); ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); - reader.setInput(s, false, true); + reader.setInput(s, false, false); int ni = reader.getNumImages(true); check(ni == 2, "invalid number of images"); diff -r fca460b63839 -r 91fb907a8732 jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java Tue Dec 13 12:02:37 2016 -0800 @@ -0,0 +1,269 @@ +/* + * 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 8154058 + * @author a.stepanov + * @summary Some checks for ignoring metadata + * @run main ReadUnknownTagsTest + */ + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import javax.imageio.*; +import javax.imageio.metadata.*; + +import javax.imageio.stream.*; +import javax.imageio.plugins.tiff.*; + + +public class ReadUnknownTagsTest { + + private final static int SZ = 50; + private final static Color C = Color.RED; + + private final static int DESCRIPTION_TAG = + BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION; + private final static String DESCRIPTION = "A Test Image"; + + private final static int FAX_TAG = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA; + private final static short FAX_DATA = + FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED; + + private final boolean ignoreMetadata; + private final boolean readUnknownTags; + + public ReadUnknownTagsTest(boolean ignoreMetadata, + boolean readUnknownTags) { + this.ignoreMetadata = ignoreMetadata; + this.readUnknownTags = readUnknownTags; + } + + private ImageWriter getTIFFWriter() { + + java.util.Iterator writers = + ImageIO.getImageWritersByFormatName("TIFF"); + if (!writers.hasNext()) { + throw new RuntimeException("No writers available for TIFF format"); + } + return writers.next(); + } + + private ImageReader getTIFFReader() { + + java.util.Iterator readers = + ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { + throw new RuntimeException("No readers available for TIFF format"); + } + return readers.next(); + } + + + private void writeImage() throws Exception { + + String fn = "test-" + ignoreMetadata + ".tiff"; + OutputStream s = new BufferedOutputStream(new FileOutputStream(fn)); + try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) { + + ImageWriter writer = getTIFFWriter(); + writer.setOutput(ios); + + BufferedImage img = new BufferedImage(SZ, SZ, + BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(C); + g.fillRect(0, 0, SZ, SZ); + g.dispose(); + + ImageWriteParam param = writer.getDefaultWriteParam(); + + IIOMetadata md = writer.getDefaultImageMetadata( + new ImageTypeSpecifier(img), param); + + TIFFDirectory dir = TIFFDirectory.createFromMetadata(md); + + TIFFTag descTag = + BaselineTIFFTagSet.getInstance().getTag(DESCRIPTION_TAG); + dir.addTIFFField(new TIFFField(descTag, TIFFTag.TIFF_ASCII, 1, + new String[] {DESCRIPTION})); + + TIFFTag faxTag = FaxTIFFTagSet.getInstance().getTag(FAX_TAG); + dir.addTIFFField(new TIFFField(faxTag, FAX_DATA)); + + writer.write(new IIOImage(img, null, dir.getAsMetadata())); + + ios.flush(); + writer.dispose(); + } + s.close(); + } + + private void readAndCheckImage() throws Exception { + + ImageReader reader = getTIFFReader(); + + String fn = "test-" + ignoreMetadata + ".tiff"; + ImageInputStream s = ImageIO.createImageInputStream(new File(fn)); + + reader.setInput(s, false, ignoreMetadata); + + int ni = reader.getNumImages(true); + check(ni == 1, "invalid number of images"); + + + TIFFImageReadParam param = new TIFFImageReadParam(); + // fax data are allowed by default + param.removeAllowedTagSet(FaxTIFFTagSet.getInstance()); + + // readUnknownTags setting + if (param.getReadUnknownTags()) { + throw new RuntimeException("Default readUnknownTags is not false"); + } + param.setReadUnknownTags(readUnknownTags); + if (param.getReadUnknownTags() != readUnknownTags) { + throw new RuntimeException("Incorrect readUnknownTags setting " + + "\"" + readUnknownTags + "\""); + } + + // read images and metadata + IIOImage i = reader.readAll(0, param); + BufferedImage bi = (BufferedImage) i.getRenderedImage(); + + check(bi.getWidth() == SZ, "invalid width"); + check(bi.getHeight() == SZ, "invalid height"); + Color c = new Color(bi.getRGB(SZ / 2, SZ / 2)); + check(c.equals(C), "invalid color"); + + IIOMetadata metadata = i.getMetadata(); + + // + // Verify presence of image metadata + // + if (metadata == null) { + throw new RuntimeException("No image metadata retrieved"); + } + + TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata); + + // + // Verify presence of essential ImageWidth field regardless of + // settings of ignoreMetadata and readUnknownTags + // + int failures = 0; + if (!dir.containsTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH)) { + System.err.println("Metadata is missing essential ImageWidth tag"); + failures++; + } else { + TIFFField widthField = + dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH); + System.out.printf("ImageWidth: %d%n", widthField.getAsLong(0)); + } + + // + // Verify presence of non-essential baseline ImageDescription field + // if and only if ignoreMetadata == false + // + boolean hasDescription = dir.containsTIFFField(DESCRIPTION_TAG); + System.out.println("ImageDescription (" + !ignoreMetadata + "): " + + hasDescription); + if (ignoreMetadata && hasDescription) { + System.err.println + ("Description metadata present despite ignoreMetadata"); + failures++; + } else if (!ignoreMetadata && !hasDescription) { + System.err.println + ("Description metadata absent despite !ignoreMetadata"); + failures++; + } + + // + // Verify presence of CleanFaxData field if and only if + // ignoreMetadata == false and readUnknownTags == true + // + boolean shouldHaveFaxField = !ignoreMetadata && readUnknownTags; + boolean hasFaxField = dir.containsTIFFField(FAX_TAG); + System.out.println("CleanFaxData (" + shouldHaveFaxField + "): " + + hasFaxField); + + if (ignoreMetadata) { + if (hasFaxField) { + System.err.println + ("Fax metadata present despite ignoreMetadata"); + failures++; + } + } else { // !ignoreMetadata + if (!readUnknownTags && hasFaxField) { + System.err.println + ("Fax metadata present despite !readUnknownTags"); + failures++; + } else if (readUnknownTags && !hasFaxField) { + System.err.println + ("Fax metadata absent despite readUnknownTags"); + failures++; + } + } + + if (failures > 0) { + throw new RuntimeException("Test failed for ignoreMetadata " + + ignoreMetadata + " and readUnknownTags " + readUnknownTags); + } + } + + public void run() { + try { + writeImage(); + readAndCheckImage(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + public static void main(String[] args) { + int failures = 0; + + System.out.println(); + for (boolean ignoreMetadata : new boolean[] {false, true}) { + for (boolean readUnknownTags : new boolean[] {false, true}) { + try { + System.out.printf + ("ignoreMetadata: %s, readUnknownTags: %s%n", + ignoreMetadata, readUnknownTags); + (new ReadUnknownTagsTest(ignoreMetadata, + readUnknownTags)).run(); + } catch (Exception e) { + e.printStackTrace(); + failures++; + } finally { + System.out.println(); + } + } + } + } +} diff -r fca460b63839 -r 91fb907a8732 jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java --- a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java Mon Dec 12 20:54:41 2016 -0800 +++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java Tue Dec 13 12:02:37 2016 -0800 @@ -159,7 +159,7 @@ ImageReader reader = getTIFFReader(); ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME)); - reader.setInput(s, false, true); + reader.setInput(s, false, false); int ni = reader.getNumImages(true); check(ni == 1, "invalid number of images: " + ni);