diff --git a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java index d5f45e16..b30b28d7 100644 --- a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java +++ b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java @@ -267,6 +267,20 @@ public final class PSDImageReader extends ImageReaderBase { List types = new ArrayList<>(); switch (header.mode) { + case PSD.COLOR_MODE_GRAYSCALE: + if (rawType.getNumBands() == 1 && rawType.getBitsPerBand(0) == 8) { + types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)); + } + else if (rawType.getNumBands() >= 2 && rawType.getBitsPerBand(0) == 8) { + types.add(ImageTypeSpecifiers.createInterleaved(cs, new int[] {1, 0}, DataBuffer.TYPE_BYTE, true, false)); + } + else if (rawType.getNumBands() == 1 && rawType.getBitsPerBand(0) == 16) { + types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_GRAY)); + } + else if (rawType.getNumBands() >= 2 && rawType.getBitsPerBand(0) == 16) { + types.add(ImageTypeSpecifiers.createInterleaved(cs, new int[] {1, 0}, DataBuffer.TYPE_USHORT, true, false)); + } + break; case PSD.COLOR_MODE_RGB: // Prefer interleaved versions as they are much faster to display if (rawType.getNumBands() == 3 && rawType.getBitsPerBand(0) == 8) { @@ -283,7 +297,7 @@ public final class PSDImageReader extends ImageReaderBase { // TODO: Integer raster // types.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.INT_ARGB)); types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR)); -// + if (!cs.isCS_sRGB()) { // Basically BufferedImage.TYPE_4BYTE_ABGR, with corrected ColorSpace. Possibly slow. types.add(ImageTypeSpecifiers.createInterleaved(cs, new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, true, false)); @@ -1116,7 +1130,7 @@ public final class PSDImageReader extends ImageReaderBase { if (newBandNum > compositeType.getNumBands()) { int[] indices = new int[newBandNum]; for (int i = 0, indicesLength = indices.length; i < indicesLength; i++) { - indices[i] = indicesLength - i; + indices[i] = i; } int[] offs = new int[newBandNum]; diff --git a/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java b/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java index 73ca0e32..7d93f18f 100755 --- a/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java +++ b/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java @@ -138,15 +138,17 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest public void testThumbnailReading() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(0).getInputStream()); + try (ImageInputStream stream = getTestData().get(0).getInputStream()) { + imageReader.setInput(stream); - assertEquals(1, imageReader.getNumThumbnails(0)); + assertEquals(1, imageReader.getNumThumbnails(0)); - BufferedImage thumbnail = imageReader.readThumbnail(0, 0); - assertNotNull(thumbnail); + BufferedImage thumbnail = imageReader.readThumbnail(0, 0); + assertNotNull(thumbnail); - assertEquals(128, thumbnail.getWidth()); - assertEquals(96, thumbnail.getHeight()); + assertEquals(128, thumbnail.getWidth()); + assertEquals(96, thumbnail.getHeight()); + } } @Test @@ -190,41 +192,43 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest public void testThumbnailReadingOutOfBounds() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(0).getInputStream()); + try (ImageInputStream stream = getTestData().get(0).getInputStream()) { + imageReader.setInput(stream); - int numImages = imageReader.getNumImages(true); + int numImages = imageReader.getNumImages(true); - try { - imageReader.getNumThumbnails(numImages + 1); - fail("Expected IndexOutOfBoundsException"); - } - catch (IndexOutOfBoundsException expected) { - assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); - } + try { + imageReader.getNumThumbnails(numImages + 1); + fail("Expected IndexOutOfBoundsException"); + } + catch (IndexOutOfBoundsException expected) { + assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); + } - try { - imageReader.getThumbnailWidth(-1, 0); - fail("Expected IndexOutOfBoundsException"); - } - catch (IndexOutOfBoundsException expected) { - assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); - } + try { + imageReader.getThumbnailWidth(-1, 0); + fail("Expected IndexOutOfBoundsException"); + } + catch (IndexOutOfBoundsException expected) { + assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); + } - try { - imageReader.getThumbnailHeight(0, -2); - fail("Expected IndexOutOfBoundsException"); - } - catch (IndexOutOfBoundsException expected) { - // Sloppy... - assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("-2")); - } + try { + imageReader.getThumbnailHeight(0, -2); + fail("Expected IndexOutOfBoundsException"); + } + catch (IndexOutOfBoundsException expected) { + // Sloppy... + assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("-2")); + } - try { - imageReader.readThumbnail(numImages + 99, 42); - fail("Expected IndexOutOfBoundsException"); - } - catch (IndexOutOfBoundsException expected) { - assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); + try { + imageReader.readThumbnail(numImages + 99, 42); + fail("Expected IndexOutOfBoundsException"); + } + catch (IndexOutOfBoundsException expected) { + assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); + } } } @@ -232,67 +236,73 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest public void testThumbnailDimensions() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(0).getInputStream()); + try (ImageInputStream stream = getTestData().get(0).getInputStream()) { + imageReader.setInput(stream); - assertEquals(1, imageReader.getNumThumbnails(0)); + assertEquals(1, imageReader.getNumThumbnails(0)); - assertEquals(128, imageReader.getThumbnailWidth(0, 0)); - assertEquals(96, imageReader.getThumbnailHeight(0, 0)); + assertEquals(128, imageReader.getThumbnailWidth(0, 0)); + assertEquals(96, imageReader.getThumbnailHeight(0, 0)); + } } @Test public void testThumbnailReadListeners() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(0).getInputStream()); + try (ImageInputStream stream = getTestData().get(0).getInputStream()) { + imageReader.setInput(stream); - final List sequnce = new ArrayList<>(); - imageReader.addIIOReadProgressListener(new ProgressListenerBase() { - private float mLastPercentageDone = 0; + final List seqeunce = new ArrayList<>(); + imageReader.addIIOReadProgressListener(new ProgressListenerBase() { + private float mLastPercentageDone = 0; - @Override - public void thumbnailStarted(final ImageReader pSource, final int pImageIndex, final int pThumbnailIndex) { - sequnce.add("started"); - } + @Override + public void thumbnailStarted(final ImageReader pSource, final int pImageIndex, final int pThumbnailIndex) { + seqeunce.add("started"); + } - @Override - public void thumbnailComplete(final ImageReader pSource) { - sequnce.add("complete"); - } + @Override + public void thumbnailComplete(final ImageReader pSource) { + seqeunce.add("complete"); + } - @Override - public void thumbnailProgress(final ImageReader pSource, final float pPercentageDone) { - // Optional - assertTrue("Listener invoked out of sequence", sequnce.size() == 1); - assertTrue(pPercentageDone >= mLastPercentageDone); - } - }); + @Override + public void thumbnailProgress(final ImageReader pSource, final float pPercentageDone) { + // Optional + assertTrue("Listener invoked out of sequence", seqeunce.size() == 1); + assertTrue(pPercentageDone >= mLastPercentageDone); + } + }); - BufferedImage thumbnail = imageReader.readThumbnail(0, 0); - assertNotNull(thumbnail); + BufferedImage thumbnail = imageReader.readThumbnail(0, 0); + assertNotNull(thumbnail); - assertEquals("Listeners not invoked", 2, sequnce.size()); - assertEquals("started", sequnce.get(0)); - assertEquals("complete", sequnce.get(1)); + assertEquals("Listeners not invoked", 2, seqeunce.size()); + assertEquals("started", seqeunce.get(0)); + assertEquals("complete", seqeunce.get(1)); + } } @Test public void testReadLayers() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(3).getInputStream()); + try (ImageInputStream stream = getTestData().get(3).getInputStream()) { + imageReader.setInput(stream); - int numImages = imageReader.getNumImages(true); + int numImages = imageReader.getNumImages(true); - assertEquals(3, numImages); + assertEquals(3, numImages); - for (int i = 0; i < numImages; i++) { - BufferedImage image = imageReader.read(i); - assertNotNull(image); + for (int i = 0; i < numImages; i++) { + BufferedImage image = imageReader.read(i); + assertNotNull(image); - // Make sure layers are correct size - assertEquals(image.getWidth(), imageReader.getWidth(i)); - assertEquals(image.getHeight(), imageReader.getHeight(i)); + // Make sure layers are correct size + assertEquals(image.getWidth(), imageReader.getWidth(i)); + assertEquals(image.getHeight(), imageReader.getHeight(i)); + } } } @@ -300,31 +310,31 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest public void testImageTypesLayers() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(3).getInputStream()); + try (ImageInputStream stream = getTestData().get(3).getInputStream()) { + imageReader.setInput(stream); - int numImages = imageReader.getNumImages(true); - for (int i = 0; i < numImages; i++) { - ImageTypeSpecifier rawType = imageReader.getRawImageType(i); -// System.err.println("rawType: " + rawType); - assertNotNull(rawType); + int numImages = imageReader.getNumImages(true); + for (int i = 0; i < numImages; i++) { + ImageTypeSpecifier rawType = imageReader.getRawImageType(i); + assertNotNull(rawType); - Iterator types = imageReader.getImageTypes(i); + Iterator types = imageReader.getImageTypes(i); - assertNotNull(types); - assertTrue(types.hasNext()); + assertNotNull(types); + assertTrue(types.hasNext()); - boolean found = false; + boolean found = false; - while (types.hasNext()) { - ImageTypeSpecifier type = types.next(); -// System.err.println("type: " + type); + while (types.hasNext()) { + ImageTypeSpecifier type = types.next(); - if (!found && (rawType == type || rawType.equals(type))) { - found = true; + if (!found && (rawType == type || rawType.equals(type))) { + found = true; + } } - } - assertTrue("RAW image type not in type iterator", found); + assertTrue("RAW image type not in type iterator", found); + } } } @@ -332,34 +342,36 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest public void testReadLayersExplicitType() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(3).getInputStream()); + try (ImageInputStream stream = getTestData().get(3).getInputStream()) { + imageReader.setInput(stream); - int numImages = imageReader.getNumImages(true); - for (int i = 0; i < numImages; i++) { - Iterator types = imageReader.getImageTypes(i); + int numImages = imageReader.getNumImages(true); + for (int i = 0; i < numImages; i++) { + Iterator types = imageReader.getImageTypes(i); - while (types.hasNext()) { - ImageTypeSpecifier type = types.next(); - ImageReadParam param = imageReader.getDefaultReadParam(); - param.setDestinationType(type); - BufferedImage image = imageReader.read(i, param); + while (types.hasNext()) { + ImageTypeSpecifier type = types.next(); + ImageReadParam param = imageReader.getDefaultReadParam(); + param.setDestinationType(type); + BufferedImage image = imageReader.read(i, param); - assertEquals(type.getBufferedImageType(), image.getType()); + assertEquals(type.getBufferedImageType(), image.getType()); - if (type.getBufferedImageType() == 0) { - // TODO: If type.getBIT == 0, test more - // Compatible color model - assertEquals(type.getNumComponents(), image.getColorModel().getNumComponents()); + if (type.getBufferedImageType() == 0) { + // TODO: If type.getBIT == 0, test more + // Compatible color model + assertEquals(type.getNumComponents(), image.getColorModel().getNumComponents()); - // Same color space - assertEquals(type.getColorModel().getColorSpace(), image.getColorModel().getColorSpace()); + // Same color space + assertEquals(type.getColorModel().getColorSpace(), image.getColorModel().getColorSpace()); - // Same number of samples - assertEquals(type.getNumBands(), image.getSampleModel().getNumBands()); + // Same number of samples + assertEquals(type.getNumBands(), image.getSampleModel().getNumBands()); - // Same number of bits/sample - for (int j = 0; j < type.getNumBands(); j++) { - assertEquals(type.getBitsPerBand(j), image.getSampleModel().getSampleSize(j)); + // Same number of bits/sample + for (int j = 0; j < type.getNumBands(); j++) { + assertEquals(type.getBitsPerBand(j), image.getSampleModel().getSampleSize(j)); + } } } } @@ -370,23 +382,73 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest public void testReadLayersExplicitDestination() throws IOException { PSDImageReader imageReader = createReader(); - imageReader.setInput(getTestData().get(3).getInputStream()); + try (ImageInputStream stream = getTestData().get(3).getInputStream()) { + imageReader.setInput(stream); - int numImages = imageReader.getNumImages(true); - for (int i = 0; i < numImages; i++) { - Iterator types = imageReader.getImageTypes(i); - int width = imageReader.getWidth(i); - int height = imageReader.getHeight(i); + int numImages = imageReader.getNumImages(true); + for (int i = 0; i < numImages; i++) { + Iterator types = imageReader.getImageTypes(i); + int width = imageReader.getWidth(i); + int height = imageReader.getHeight(i); - while (types.hasNext()) { - ImageTypeSpecifier type = types.next(); - ImageReadParam param = imageReader.getDefaultReadParam(); - BufferedImage destination = type.createBufferedImage(width, height); - param.setDestination(destination); + while (types.hasNext()) { + ImageTypeSpecifier type = types.next(); + ImageReadParam param = imageReader.getDefaultReadParam(); + BufferedImage destination = type.createBufferedImage(width, height); + param.setDestination(destination); - BufferedImage image = imageReader.read(i, param); + BufferedImage image = imageReader.read(i, param); - assertSame(destination, image); + assertSame(destination, image); + } + } + } + } + + @Test + public void testGrayAlphaLayers() throws IOException { + PSDImageReader imageReader = createReader(); + + // The expected colors for each layer + int[] colors = new int[] { + -1, // Don't care + 0xff000000, + 0xffffffff, + 0xff737373, + 0xff3c3c3c, + 0xff656565, + 0xffc9c9c9, + 0xff979797, + 0xff5a5a5a + }; + + try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/psd/test_grayscale_boxes.psd"))) { + imageReader.setInput(stream); + + int numImages = imageReader.getNumImages(true); + assertEquals(colors.length, numImages); + + // Skip reading the merged composite image + for (int i = 1; i < numImages; i++) { + Iterator types = imageReader.getImageTypes(i); + int width = imageReader.getWidth(i); + int height = imageReader.getHeight(i); + + while (types.hasNext()) { + ImageTypeSpecifier type = types.next(); + + ImageReadParam param = imageReader.getDefaultReadParam(); + BufferedImage destination = type.createBufferedImage(width, height); + param.setDestination(destination); + + BufferedImage image = imageReader.read(i, param); + + assertSame(destination, image); + + // NOTE: Allow some slack, as Java 1.7 and 1.8 color management differs slightly + int rgb = image.getRGB(0, 0); + assertRGBEquals(String.format("#%04x != #%04x", colors[i], rgb), colors[i], rgb, 1); + } } } } diff --git a/imageio/imageio-psd/src/test/resources/psd/test_grayscale_boxes.psd b/imageio/imageio-psd/src/test/resources/psd/test_grayscale_boxes.psd new file mode 100644 index 00000000..c854942d Binary files /dev/null and b/imageio/imageio-psd/src/test/resources/psd/test_grayscale_boxes.psd differ