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..6b88eed0 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 @@ -155,24 +155,30 @@ final class JPEGImage10MetadataCleaner { } } - // Special case: Broken AdobeDCT segment, inconsistent with SOF, use values from SOF - if (adobeDCT != null && (adobeDCT.getTransform() == AdobeDCTSegment.YCCK && sof.componentsInFrame() < 4 || + if (adobeDCT != null) { + // Special case: Broken AdobeDCT segment, inconsistent with SOF, use values from SOF + if ((adobeDCT.getTransform() == AdobeDCTSegment.YCCK && sof.componentsInFrame() < 4 || adobeDCT.getTransform() == AdobeDCTSegment.YCC && sof.componentsInFrame() < 3)) { - reader.processWarningOccurred(String.format( - "Invalid Adobe App14 marker. Indicates %s data, but SOF%d has %d color component(s). " + - "Ignoring Adobe App14 marker.", - adobeDCT.getTransform() == AdobeDCTSegment.YCCK ? "YCCK/CMYK" : "YCC/RGB", - sof.marker & 0xf, sof.componentsInFrame() - )); + + reader.processWarningOccurred(String.format( + "Invalid Adobe App14 marker. Indicates %s data, but SOF%d has %d color component(s). " + + "Ignoring Adobe App14 marker.", + adobeDCT.getTransform() == AdobeDCTSegment.YCCK ? "YCCK/CMYK" : "YCC/RGB", + sof.marker & 0xf, sof.componentsInFrame() + )); - // Remove bad AdobeDCT - NodeList app14Adobe = tree.getElementsByTagName("app14Adobe"); - for (int i = app14Adobe.getLength() - 1; i >= 0; i--) { - Node item = app14Adobe.item(i); - item.getParentNode().removeChild(item); + // We don't add this as unknown marker, as we are certain it's bogus by now } + else { + // Otherwise, add back the Adobe tag we filtered out in JPEGSegmentImageInputStream + IIOMetadataNode app14Adobe = new IIOMetadataNode("app14Adobe"); + app14Adobe.setAttribute("version", String.valueOf(adobeDCT.getVersion())); + app14Adobe.setAttribute("flags0", String.valueOf(adobeDCT.getFlags0())); + app14Adobe.setAttribute("flags1", String.valueOf(adobeDCT.getFlags1())); + app14Adobe.setAttribute("transform", String.valueOf(adobeDCT.getTransform())); - // We don't add this as unknown marker, as we are certain it's bogus by now + markerSequence.insertBefore(app14Adobe, markerSequence.getFirstChild()); + } } Node next = null; diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java index 096d99d9..ff58c0e9 100644 --- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java @@ -117,9 +117,9 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl { marker = 0xff00 | stream.readUnsignedByte(); } - // TODO: Optionally skip JFIF only for non-JFIF conformant streams - // TODO: Refactor to make various segments optional, we probably only want the "Adobe" APP14 segment, 'Exif' APP1 and very few others - if (isAppSegmentMarker(marker) && !(marker == JPEG.APP1 && isAppSegmentWithId("Exif", stream)) && marker != JPEG.APP14) { + // TODO: Should we just skip all app marker segments? + // We are now handling all important segments ourselves + if (isAppSegmentMarker(marker) && !(marker == JPEG.APP1 && isAppSegmentWithId("Exif", stream))) { int length = stream.readUnsignedShort(); // Length including length field itself stream.seek(realPosition + 2 + length); // Skip marker (2) + length } @@ -133,8 +133,12 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl { if (marker == JPEG.SOS) { // Treat rest of stream as a single segment (scanning for EOI is too much work) + // TODO: For progressive, there will be more than one SOS... length = Long.MAX_VALUE - realPosition; } +// else if (marker == JPEG.APP14 && isAppSegmentWithId("Adobe", stream)) { +// length = 16; +// } else { // Length including length field itself length = stream.readUnsignedShort() + 2; diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java index e4a6e2b7..9c9eaea5 100644 --- a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java +++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java @@ -418,9 +418,13 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase spiClass = (Class) Class.forName("com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi"); - ImageReaderSpi provider = spiClass.newInstance(); - referenceReader = provider.createReaderInstance(); - } - catch (Throwable t) { - System.err.println("WARNING: Could not create ImageReader for reference (missing dependency): " + t.getMessage()); + if (referenceReader == null) { return; } @@ -1196,6 +1193,21 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase spiClass = (Class) Class.forName("com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi"); + ImageReaderSpi provider = spiClass.newInstance(); + + return provider.createReaderInstance(); + } + catch (Throwable t) { + System.err.println("WARNING: Could not create ImageReader for reference (missing dependency): " + t.getMessage()); + + return null; + } + } + private void assertTreesEquals(String message, Node expectedTree, Node actualTree) { if (expectedTree == actualTree) { return; @@ -1347,9 +1359,87 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase