From bcfb267efe55f42e272344aef88f4723195959f5 Mon Sep 17 00:00:00 2001
From: Brian Burkhalter
Date: Tue, 13 Dec 2016 12:02:37 -0800
Subject: [PATCH] 8154058: [TIFF] ignoreMetadata parameter of TIFFImageReader's
setInput() method affects TIFFImageReadParam in non-obvious way
Add readUnknownTags to TIFFImageReadParam and add ReadParamTest
Reviewed-by: prr
---
.../com/sun/imageio/plugins/tiff/TIFFIFD.java | 24 +-
.../plugins/tiff/TIFFImageMetadata.java | 5 +-
.../imageio/plugins/tiff/TIFFImageReader.java | 9 +-
.../imageio/plugins/tiff/TIFFImageWriter.java | 2 +-
.../metadata/doc-files/tiff_metadata.html | 29 +-
.../plugins/tiff/TIFFImageReadParam.java | 29 ++
.../tiff/MultiPageImageTIFFFieldTest.java | 2 +-
.../plugins/tiff/ReadUnknownTagsTest.java | 269 ++++++++++++++++++
.../plugins/tiff/TIFFImageReadParamTest.java | 2 +-
9 files changed, 344 insertions(+), 27 deletions(-)
create mode 100644 jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java
diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java
index 1c194fb3b95..2b94d15317f 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java
@@ -541,10 +541,10 @@ public class TIFFIFD extends TIFFDirectory {
}
// 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 @@ public class TIFFIFD extends TIFFDirectory {
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 @@ public class TIFFIFD extends TIFFDirectory {
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 @@ public class TIFFIFD extends TIFFDirectory {
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 --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
index 22e1c59b1b2..ef68d134892 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
@@ -82,9 +82,10 @@ public class TIFFImageMetadata extends IIOMetadata {
}
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 --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java
index 91778e7e097..3ccc3cd9233 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java
@@ -305,16 +305,19 @@ public class TIFFImageReader extends ImageReader {
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 --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
index 8e0942d75b7..6d27c01bb93 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
@@ -3015,7 +3015,7 @@ public class TIFFImageWriter extends ImageWriter {
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 --git a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html
index 045a1025f08..5cff3659bf3 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html
@@ -216,22 +216,27 @@ second on the inferred color space.
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 --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java
index e6af9dfe887..0abf60219e7 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java
@@ -46,6 +46,10 @@ import javax.imageio.ImageReadParam;
* {@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 @@ public final class TIFFImageReadParam extends ImageReadParam {
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 final class TIFFImageReadParam extends ImageReadParam {
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 --git a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java
index 14a5741cbf8..c24ebe21320 100644
--- a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java
+++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java
@@ -223,7 +223,7 @@ public class MultiPageImageTIFFFieldTest {
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 --git a/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java
new file mode 100644
index 00000000000..3734b865adb
--- /dev/null
+++ b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java
@@ -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 --git a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java
index 34fd5ed8983..6cd71e27872 100644
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java
@@ -159,7 +159,7 @@ public class TIFFImageReadParamTest {
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);