From 13bea2355045174aaf5a3de9069d9a24e5c7db7d Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Tue, 9 Aug 2016 11:47:25 +0200 Subject: [PATCH] #276 Fix DHT inconsistency --- .../jpeg/JPEGImage10MetadataCleaner.java | 11 +- .../jpeg/JPEGImage10MetadataCleanerTest.java | 96 ++++++++++++++++++ .../src/test/resources/jpeg/5dhtsegments.jpg | Bin 0 -> 9322 bytes .../src/test/resources/jpeg/6dhtsegments.jpg | Bin 0 -> 3851 bytes 4 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleanerTest.java create mode 100644 imageio/imageio-jpeg/src/test/resources/jpeg/5dhtsegments.jpg create mode 100644 imageio/imageio-jpeg/src/test/resources/jpeg/6dhtsegments.jpg diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleaner.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleaner.java index 420bd1b4..d78e091d 100644 --- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleaner.java +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleaner.java @@ -197,9 +197,7 @@ final class JPEGImage10MetadataCleaner { IIOMetadataNode unknown = new IIOMetadataNode("unknown"); unknown.setAttribute("MarkerTag", Integer.toString(segment.marker() & 0xff)); - DataInputStream stream = new DataInputStream(segment.data()); - - try { + try (DataInputStream stream = new DataInputStream(segment.data())) { String identifier = segment.identifier(); int off = identifier != null ? identifier.length() + 1 : 0; @@ -213,9 +211,6 @@ final class JPEGImage10MetadataCleaner { unknown.setUserObject(data); } - finally { - stream.close(); - } if (next == null) { // To be semi-compatible with the functionality in mergeTree, @@ -271,12 +266,12 @@ final class JPEGImage10MetadataCleaner { dht.getParentNode().insertBefore(acTables, dht.getNextSibling()); // Split into 2 dht nodes, one for AC and one for DC - for (int i = 0; i < dhtables.getLength(); i++) { + for (int i = dhtables.getLength() - 1; i >= 0 ; i--) { Element dhtable = (Element) dhtables.item(i); String tableClass = dhtable.getAttribute("class"); if ("1".equals(tableClass)) { dht.removeChild(dhtable); - acTables.appendChild(dhtable); + acTables.insertBefore(dhtable, acTables.getFirstChild()); } } } diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleanerTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleanerTest.java new file mode 100644 index 00000000..00145da9 --- /dev/null +++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImage10MetadataCleanerTest.java @@ -0,0 +1,96 @@ +package com.twelvemonkeys.imageio.plugins.jpeg; + +import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi; +import org.junit.Test; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * JPEGImage10MetadataCleanerTest. + * + * @author Harald Kuhr + * @author last modified by $Author: harald.kuhr$ + * @version $Id: JPEGImage10MetadataCleanerTest.java,v 1.0 08/08/16 harald.kuhr Exp$ + */ +public class JPEGImage10MetadataCleanerTest { + + static { + IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi()); + ImageIO.setUseCache(false); + } + + protected static final JPEGImageReaderSpi SPI = new JPEGImageReaderSpi(lookupDelegateProvider()); + + protected static ImageReaderSpi lookupDelegateProvider() { + return JPEGImageReaderSpi.lookupDelegateProvider(IIORegistry.getDefaultInstance()); + } + + // Unit/regression test for #276 + @Test + public void cleanMetadataMoreThan4DHTSegments() throws Exception { + List testData = Arrays.asList("/jpeg/5dhtsegments.jpg", "/jpeg/6dhtsegments.jpg"); + + for (String data : testData) { + try (ImageInputStream origInput = ImageIO.createImageInputStream(getClass().getResource(data)); + ImageInputStream input = ImageIO.createImageInputStream(getClass().getResource(data))) { + + ImageReader origReader = SPI.delegateProvider.createReaderInstance(); + origReader.setInput(origInput); + + ImageReader reader = SPI.createReaderInstance(); + reader.setInput(input); + + IIOMetadata original = origReader.getImageMetadata(0); + IIOMetadataNode origTree = (IIOMetadataNode) original.getAsTree(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0); + + JPEGImage10MetadataCleaner cleaner = new JPEGImage10MetadataCleaner((JPEGImageReader) reader); + IIOMetadata cleaned = cleaner.cleanMetadata(origReader.getImageMetadata(0)); + + IIOMetadataNode cleanTree = (IIOMetadataNode) cleaned.getAsTree(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0); + + NodeList origDHT = origTree.getElementsByTagName("dht"); + assertEquals(1, origDHT.getLength()); + + NodeList cleanDHT = cleanTree.getElementsByTagName("dht"); + assertEquals(2, cleanDHT.getLength()); + + NodeList cleanDHTable = cleanTree.getElementsByTagName("dhtable"); + NodeList origDHTable = origTree.getElementsByTagName("dhtable"); + + assertEquals(origDHTable.getLength(), cleanDHTable.getLength()); + + // Note: This also tests that the order of the htables are the same, + // but that will only hold if they are already sorted by class. + // Luckily, they are in these cases... + for (int i = 0; i < origDHTable.getLength(); i++) { + Element cleanDHTableElem = (Element) cleanDHTable.item(i); + Element origDHTableElem = (Element) origDHTable.item(i); + + assertNotNull(cleanDHTableElem); + + assertNotNull(cleanDHTableElem.getAttribute("class")); + assertEquals(origDHTableElem.getAttribute("class"), cleanDHTableElem.getAttribute("class")); + + assertNotNull(cleanDHTableElem.getAttribute("htableId")); + assertEquals(origDHTableElem.getAttribute("htableId"), cleanDHTableElem.getAttribute("htableId")); + } + + reader.dispose(); + origReader.dispose(); + } + } + } +} \ No newline at end of file diff --git a/imageio/imageio-jpeg/src/test/resources/jpeg/5dhtsegments.jpg b/imageio/imageio-jpeg/src/test/resources/jpeg/5dhtsegments.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eab45b295f9c2923e5f33493379ee975c0da3dfa GIT binary patch literal 9322 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 literal 0 HcmV?d00001 diff --git a/imageio/imageio-jpeg/src/test/resources/jpeg/6dhtsegments.jpg b/imageio/imageio-jpeg/src/test/resources/jpeg/6dhtsegments.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aaa6e8e7162268264c62b6afc66c8d306f853f4f GIT binary patch literal 3851 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