From 34eb084d246d4d3a9bc84859326d4784b734b569 Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Wed, 2 Nov 2016 19:06:12 +0100 Subject: [PATCH] #212 TIFF subsampling fix --- .../plugins/svg/SVGImageReaderTest.java | 7 ++ .../plugins/wmf/WMFImageReaderTest.java | 7 ++ .../imageio/plugins/bmp/BMPImageReader.java | 6 +- .../plugins/bmp/BMPImageReaderTest.java | 59 +++++++++++++- .../plugins/bmp/CURImageReaderTest.java | 7 ++ .../plugins/bmp/ICOImageReaderTest.java | 7 ++ .../imageio/util/ImageReaderAbstractTest.java | 59 +++++++++++--- .../plugins/pict/PICTImageReaderTest.java | 14 ++-- .../imageio/plugins/tga/TGAImageReader.java | 7 +- .../imageio/plugins/tiff/TIFFImageReader.java | 79 +++++++++++++------ .../plugins/tiff/TIFFImageReaderTest.java | 71 ++++++++++++++++- 11 files changed, 273 insertions(+), 50 deletions(-) diff --git a/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderTest.java b/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderTest.java index 9f0e8b52..59a06967 100755 --- a/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderTest.java +++ b/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderTest.java @@ -120,6 +120,13 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest super.testReadWithSourceRegionParamEqualImage(); } + @Test + @Ignore("Known issue: Subsampled reading not supported") + @Override + public void testReadWithSubsampleParamPixels() throws IOException { + super.testReadWithSubsampleParamPixels(); + } + @Test public void testRepeatedRead() throws IOException { Dimension dim = new Dimension(100, 100); diff --git a/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/wmf/WMFImageReaderTest.java b/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/wmf/WMFImageReaderTest.java index 9220d115..b634b138 100755 --- a/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/wmf/WMFImageReaderTest.java +++ b/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/wmf/WMFImageReaderTest.java @@ -86,4 +86,11 @@ public class WMFImageReaderTest extends ImageReaderAbstractTest public void testReadWithSourceRegionParamEqualImage() throws IOException { super.testReadWithSourceRegionParamEqualImage(); } + + @Test + @Ignore("Known issue: Subsampled reading not supported") + @Override + public void testReadWithSubsampleParamPixels() throws IOException { + super.testReadWithSubsampleParamPixels(); + } } \ No newline at end of file diff --git a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java index 6ff96a19..9151dce6 100755 --- a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java +++ b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java @@ -692,12 +692,14 @@ public final class BMPImageReader extends ImageReaderBase { if (imageMetadata != null) { new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName), false); } - } catch (Throwable t) { + } + catch (Throwable t) { if (args.length > 1) { System.err.println("---"); System.err.println("---> " + t.getClass().getSimpleName() + ": " + t.getMessage() + " for " + arg); System.err.println("---"); - } else { + } + else { throwAs(RuntimeException.class, t); } } diff --git a/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReaderTest.java b/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReaderTest.java index 76a495b3..12646e9a 100755 --- a/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReaderTest.java +++ b/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReaderTest.java @@ -1,20 +1,19 @@ package com.twelvemonkeys.imageio.plugins.bmp; import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest; +import org.junit.Ignore; import org.junit.Test; import org.mockito.InOrder; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import javax.imageio.IIOException; -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.ImageTypeSpecifier; +import javax.imageio.*; import javax.imageio.event.IIOReadProgressListener; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.spi.ImageReaderSpi; import java.awt.*; +import java.awt.image.BufferedImage; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.URISyntaxException; @@ -174,6 +173,58 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest } } + @Ignore("Known issue: Subsampled reading is currently broken") + @Test + public void testReadWithSubsampleParamPixelsIndexed8() throws IOException { + ImageReader reader = createReader(); + TestData data = getTestData().get(0); + reader.setInput(data.getInputStream()); + + ImageReadParam param = reader.getDefaultReadParam(); + + BufferedImage image = null; + BufferedImage subsampled = null; + try { + image = reader.read(0, param); + + param.setSourceSubsampling(2, 2, 0, 0); + subsampled = reader.read(0, param); + } + catch (IOException e) { + failBecause("Image could not be read", e); + } + + assertSubsampledImageDataEquals("Subsampled image data does not match expected", image, subsampled, param); + } + + // TODO: 1. Subsampling is currently broken, should fix it. + // 2. BMPs are (normally) stored bottom/up, meaning y subsampling offsets will differ from normal + // subsampling of the same data with an offset... Should we deal with this in the reader? Yes? + @Ignore("Known issue: Subsampled reading is currently broken") + @Test + @Override + public void testReadWithSubsampleParamPixels() throws IOException { + ImageReader reader = createReader(); + TestData data = getTestData().get(19); // RGB 24 + reader.setInput(data.getInputStream()); + + ImageReadParam param = reader.getDefaultReadParam(); + + BufferedImage image = null; + BufferedImage subsampled = null; + try { + image = reader.read(0, param); + + param.setSourceSubsampling(2, 2, 0, 0); + subsampled = reader.read(0, param); + } + catch (IOException e) { + failBecause("Image could not be read", e); + } + + assertSubsampledImageDataEquals("Subsampled image data does not match expected", image, subsampled, param); + } + @Test(expected = IIOException.class) public void testReadCorruptCausesIIOException() throws IOException { // See https://bugs.openjdk.java.net/browse/JDK-8066904 diff --git a/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/CURImageReaderTest.java b/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/CURImageReaderTest.java index fe885d86..a40ba06d 100755 --- a/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/CURImageReaderTest.java +++ b/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/CURImageReaderTest.java @@ -119,4 +119,11 @@ public class CURImageReaderTest extends ImageReaderAbstractTest public void testNotBadCaching() throws IOException { super.testNotBadCaching(); } + + @Test + @Ignore("Known issue: Subsampled reading currently not supported") + @Override + public void testReadWithSubsampleParamPixels() throws IOException { + super.testReadWithSubsampleParamPixels(); + } } \ No newline at end of file diff --git a/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/ICOImageReaderTest.java b/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/ICOImageReaderTest.java index ed5a2adc..9c121287 100755 --- a/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/ICOImageReaderTest.java +++ b/imageio/imageio-bmp/src/test/java/com/twelvemonkeys/imageio/plugins/bmp/ICOImageReaderTest.java @@ -76,4 +76,11 @@ public class ICOImageReaderTest extends ImageReaderAbstractTest public void testNotBadCaching() throws IOException { super.testNotBadCaching(); } + + @Test + @Ignore("Known issue: Subsampled reading currently not supported") + @Override + public void testReadWithSubsampleParamPixels() throws IOException { + super.testReadWithSubsampleParamPixels(); + } } \ No newline at end of file diff --git a/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/util/ImageReaderAbstractTest.java b/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/util/ImageReaderAbstractTest.java index 2864f844..f002a0fb 100644 --- a/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/util/ImageReaderAbstractTest.java +++ b/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/util/ImageReaderAbstractTest.java @@ -28,7 +28,6 @@ package com.twelvemonkeys.imageio.util; -import com.twelvemonkeys.image.ImageUtil; import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi; import org.junit.Ignore; import org.junit.Test; @@ -46,6 +45,7 @@ import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; +import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; @@ -98,7 +98,7 @@ public abstract class ImageReaderAbstractTest { return false; } - private static void failBecause(String message, Throwable exception) { + protected static void failBecause(String message, Throwable exception) { AssertionError error = new AssertionError(message); error.initCause(exception); throw error; @@ -471,7 +471,6 @@ public abstract class ImageReaderAbstractTest { assertEquals("Read image has wrong height: ", (data.getDimension(0).height + 4) / 5, image.getHeight()); } - @Ignore @Test public void testReadWithSubsampleParamPixels() throws IOException { ImageReader reader = createReader(); @@ -479,28 +478,66 @@ public abstract class ImageReaderAbstractTest { reader.setInput(data.getInputStream()); ImageReadParam param = reader.getDefaultReadParam(); - param.setSourceRegion(new Rectangle(Math.min(100, reader.getWidth(0)), Math.min(100, reader.getHeight(0)))); BufferedImage image = null; BufferedImage subsampled = null; try { image = reader.read(0, param); - param.setSourceSubsampling(2, 2, 1, 1); // Hmm.. Seems to be the offset the fake version (ReplicateScaleFilter) uses + param.setSourceSubsampling(2, 2, 0, 0); subsampled = reader.read(0, param); } catch (IOException e) { failBecause("Image could not be read", e); } - BufferedImage expected = ImageUtil.toBuffered(IIOUtil.fakeSubsampling(image, param)); + assertSubsampledImageDataEquals("Subsampled image data does not match expected", image, subsampled, param); + } -// JPanel panel = new JPanel(); -// panel.add(new JLabel("Expected", new BufferedImageIcon(expected, 300, 300), JLabel.CENTER)); -// panel.add(new JLabel("Actual", new BufferedImageIcon(subsampled, 300, 300), JLabel.CENTER)); -// JOptionPane.showConfirmDialog(null, panel); + // TODO: Subsample all test data + // TODO: Subsample with varying ratios and offsets - assertImageDataEquals("Subsampled image data does not match expected", expected, subsampled); + protected final void assertSubsampledImageDataEquals(String message, BufferedImage expected, BufferedImage actual, ImageReadParam param) throws IOException { + assertNotNull("Expected image was null", expected); + assertNotNull("Actual image was null!", actual); + + if (expected == actual) { + return; + } + + int xOff = param.getSubsamplingXOffset(); + int yOff = param.getSubsamplingYOffset(); + int xSub = param.getSourceXSubsampling(); + int ySub = param.getSourceYSubsampling(); + + assertEquals("Subsampled image has wrong width: ", (expected.getWidth() - xOff + xSub - 1) / xSub, actual.getWidth()); + assertEquals("Subsampled image has wrong height: ", (expected.getHeight() - yOff + ySub - 1) / ySub, actual.getHeight()); + assertEquals("Subsampled has different type", expected.getType(), actual.getType()); + + for (int y = 0; y < actual.getHeight(); y++) { + for (int x = 0; x < actual.getWidth(); x++) { + int expectedRGB = expected.getRGB(xOff + x * xSub, yOff + y * ySub); + int actualRGB = actual.getRGB(x, y); + + try { + assertEquals(String.format("%s alpha at (%d, %d)", message, x, y), (expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5); + assertEquals(String.format("%s red at (%d, %d)", message, x, y), (expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5); + assertEquals(String.format("%s green at (%d, %d)", message, x, y), (expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5); + assertEquals(String.format("%s blue at (%d, %d)", message, x, y), expectedRGB & 0xff, actualRGB & 0xff, 5); + } + catch (AssertionError e) { + File tempExpected = File.createTempFile("junit-expected-", ".png"); + System.err.println("tempExpected.getAbsolutePath(): " + tempExpected.getAbsolutePath()); + ImageIO.write(expected, "PNG", tempExpected); + File tempActual = File.createTempFile("junit-actual-", ".png"); + System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath()); + ImageIO.write(actual, "PNG", tempActual); + + + assertEquals(String.format("%s ARGB at (%d, %d)", message, x, y), String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB)); + } + } + } } protected final void assertImageDataEquals(String message, BufferedImage expected, BufferedImage actual) { diff --git a/imageio/imageio-pict/src/test/java/com/twelvemonkeys/imageio/plugins/pict/PICTImageReaderTest.java b/imageio/imageio-pict/src/test/java/com/twelvemonkeys/imageio/plugins/pict/PICTImageReaderTest.java index 9c46904c..15078df2 100644 --- a/imageio/imageio-pict/src/test/java/com/twelvemonkeys/imageio/plugins/pict/PICTImageReaderTest.java +++ b/imageio/imageio-pict/src/test/java/com/twelvemonkeys/imageio/plugins/pict/PICTImageReaderTest.java @@ -3,6 +3,7 @@ package com.twelvemonkeys.imageio.plugins.pict; import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream; import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStreamSpi; import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest; +import org.junit.Ignore; import org.junit.Test; import javax.imageio.spi.IIORegistry; @@ -83,6 +84,13 @@ public class PICTImageReaderTest extends ImageReaderAbstractTest