#248 PSDImageReader now uses correct band indices for grayscale + alpha layers.

This commit is contained in:
Harald Kuhr 2016-06-30 14:17:00 +02:00
parent 478ed62cd1
commit a29960e8ee
3 changed files with 202 additions and 126 deletions

View File

@ -267,6 +267,20 @@ public final class PSDImageReader extends ImageReaderBase {
List<ImageTypeSpecifier> types = new ArrayList<>(); List<ImageTypeSpecifier> types = new ArrayList<>();
switch (header.mode) { 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: case PSD.COLOR_MODE_RGB:
// Prefer interleaved versions as they are much faster to display // Prefer interleaved versions as they are much faster to display
if (rawType.getNumBands() == 3 && rawType.getBitsPerBand(0) == 8) { if (rawType.getNumBands() == 3 && rawType.getBitsPerBand(0) == 8) {
@ -283,7 +297,7 @@ public final class PSDImageReader extends ImageReaderBase {
// TODO: Integer raster // TODO: Integer raster
// types.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.INT_ARGB)); // types.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.INT_ARGB));
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR)); types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR));
//
if (!cs.isCS_sRGB()) { if (!cs.isCS_sRGB()) {
// Basically BufferedImage.TYPE_4BYTE_ABGR, with corrected ColorSpace. Possibly slow. // 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)); 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()) { if (newBandNum > compositeType.getNumBands()) {
int[] indices = new int[newBandNum]; int[] indices = new int[newBandNum];
for (int i = 0, indicesLength = indices.length; i < indicesLength; i++) { for (int i = 0, indicesLength = indices.length; i < indicesLength; i++) {
indices[i] = indicesLength - i; indices[i] = i;
} }
int[] offs = new int[newBandNum]; int[] offs = new int[newBandNum];

View File

@ -138,7 +138,8 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
public void testThumbnailReading() throws IOException { public void testThumbnailReading() throws IOException {
PSDImageReader imageReader = createReader(); 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));
@ -148,6 +149,7 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
assertEquals(128, thumbnail.getWidth()); assertEquals(128, thumbnail.getWidth());
assertEquals(96, thumbnail.getHeight()); assertEquals(96, thumbnail.getHeight());
} }
}
@Test @Test
public void testThumbnailReadingNoInput() throws IOException { public void testThumbnailReadingNoInput() throws IOException {
@ -190,7 +192,8 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
public void testThumbnailReadingOutOfBounds() throws IOException { public void testThumbnailReadingOutOfBounds() throws IOException {
PSDImageReader imageReader = createReader(); 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);
@ -227,43 +230,47 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index")); assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index"));
} }
} }
}
@Test @Test
public void testThumbnailDimensions() throws IOException { public void testThumbnailDimensions() throws IOException {
PSDImageReader imageReader = createReader(); 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(128, imageReader.getThumbnailWidth(0, 0));
assertEquals(96, imageReader.getThumbnailHeight(0, 0)); assertEquals(96, imageReader.getThumbnailHeight(0, 0));
} }
}
@Test @Test
public void testThumbnailReadListeners() throws IOException { public void testThumbnailReadListeners() throws IOException {
PSDImageReader imageReader = createReader(); PSDImageReader imageReader = createReader();
imageReader.setInput(getTestData().get(0).getInputStream()); try (ImageInputStream stream = getTestData().get(0).getInputStream()) {
imageReader.setInput(stream);
final List<Object> sequnce = new ArrayList<>(); final List<Object> seqeunce = new ArrayList<>();
imageReader.addIIOReadProgressListener(new ProgressListenerBase() { imageReader.addIIOReadProgressListener(new ProgressListenerBase() {
private float mLastPercentageDone = 0; private float mLastPercentageDone = 0;
@Override @Override
public void thumbnailStarted(final ImageReader pSource, final int pImageIndex, final int pThumbnailIndex) { public void thumbnailStarted(final ImageReader pSource, final int pImageIndex, final int pThumbnailIndex) {
sequnce.add("started"); seqeunce.add("started");
} }
@Override @Override
public void thumbnailComplete(final ImageReader pSource) { public void thumbnailComplete(final ImageReader pSource) {
sequnce.add("complete"); seqeunce.add("complete");
} }
@Override @Override
public void thumbnailProgress(final ImageReader pSource, final float pPercentageDone) { public void thumbnailProgress(final ImageReader pSource, final float pPercentageDone) {
// Optional // Optional
assertTrue("Listener invoked out of sequence", sequnce.size() == 1); assertTrue("Listener invoked out of sequence", seqeunce.size() == 1);
assertTrue(pPercentageDone >= mLastPercentageDone); assertTrue(pPercentageDone >= mLastPercentageDone);
} }
}); });
@ -271,16 +278,18 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
BufferedImage thumbnail = imageReader.readThumbnail(0, 0); BufferedImage thumbnail = imageReader.readThumbnail(0, 0);
assertNotNull(thumbnail); assertNotNull(thumbnail);
assertEquals("Listeners not invoked", 2, sequnce.size()); assertEquals("Listeners not invoked", 2, seqeunce.size());
assertEquals("started", sequnce.get(0)); assertEquals("started", seqeunce.get(0));
assertEquals("complete", sequnce.get(1)); assertEquals("complete", seqeunce.get(1));
}
} }
@Test @Test
public void testReadLayers() throws IOException { public void testReadLayers() throws IOException {
PSDImageReader imageReader = createReader(); 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);
@ -295,17 +304,18 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
assertEquals(image.getHeight(), imageReader.getHeight(i)); assertEquals(image.getHeight(), imageReader.getHeight(i));
} }
} }
}
@Test @Test
public void testImageTypesLayers() throws IOException { public void testImageTypesLayers() throws IOException {
PSDImageReader imageReader = createReader(); 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);
for (int i = 0; i < numImages; i++) { for (int i = 0; i < numImages; i++) {
ImageTypeSpecifier rawType = imageReader.getRawImageType(i); ImageTypeSpecifier rawType = imageReader.getRawImageType(i);
// System.err.println("rawType: " + rawType);
assertNotNull(rawType); assertNotNull(rawType);
Iterator<ImageTypeSpecifier> types = imageReader.getImageTypes(i); Iterator<ImageTypeSpecifier> types = imageReader.getImageTypes(i);
@ -317,7 +327,6 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
while (types.hasNext()) { while (types.hasNext()) {
ImageTypeSpecifier type = types.next(); ImageTypeSpecifier type = types.next();
// System.err.println("type: " + type);
if (!found && (rawType == type || rawType.equals(type))) { if (!found && (rawType == type || rawType.equals(type))) {
found = true; found = true;
@ -327,12 +336,14 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
assertTrue("RAW image type not in type iterator", found); assertTrue("RAW image type not in type iterator", found);
} }
} }
}
@Test @Test
public void testReadLayersExplicitType() throws IOException { public void testReadLayersExplicitType() throws IOException {
PSDImageReader imageReader = createReader(); 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);
for (int i = 0; i < numImages; i++) { for (int i = 0; i < numImages; i++) {
@ -365,12 +376,14 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
} }
} }
} }
}
@Test @Test
public void testReadLayersExplicitDestination() throws IOException { public void testReadLayersExplicitDestination() throws IOException {
PSDImageReader imageReader = createReader(); 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);
for (int i = 0; i < numImages; i++) { for (int i = 0; i < numImages; i++) {
@ -390,6 +403,55 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
} }
} }
} }
}
@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<ImageTypeSpecifier> 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);
}
}
}
}
@Test @Test
public void testReadUnicodeLayerName() throws IOException { public void testReadUnicodeLayerName() throws IOException {