Cleaned up reading of layers.

This commit is contained in:
Harald Kuhr 2009-10-25 21:08:42 +01:00
parent d04d4a9a97
commit 669f575585

View File

@ -57,7 +57,6 @@ import java.util.List;
* @version $Id: PSDImageReader.java,v 1.0 Apr 29, 2008 4:45:52 PM haraldk Exp$ * @version $Id: PSDImageReader.java,v 1.0 Apr 29, 2008 4:45:52 PM haraldk Exp$
*/ */
// TODO: Implement ImageIO meta data interface // TODO: Implement ImageIO meta data interface
// TODO: Implement layer reading
// TODO: Allow reading separate (or some?) layers // TODO: Allow reading separate (or some?) layers
// TODO: Consider Romain Guy's Java 2D implementation of PS filters for the blending modes in layers // TODO: Consider Romain Guy's Java 2D implementation of PS filters for the blending modes in layers
// http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/ // http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/
@ -322,17 +321,17 @@ public class PSDImageReader extends ImageReaderBase {
processImageStarted(pIndex); processImageStarted(pIndex);
int[] offsets = null; int[] byteCounts = null;
int compression = mImageInput.readShort(); int compression = mImageInput.readShort();
switch (compression) { switch (compression) {
case PSD.COMPRESSION_NONE: case PSD.COMPRESSION_NONE:
break; break;
case PSD.COMPRESSION_RLE: case PSD.COMPRESSION_RLE:
// NOTE: Offsets will allow us to easily skip rows before AOI // NOTE: Byte counts will allow us to easily skip rows before AOI
offsets = new int[mHeader.mChannels * mHeader.mHeight]; byteCounts = new int[mHeader.mChannels * mHeader.mHeight];
for (int i = 0; i < offsets.length; i++) { for (int i = 0; i < byteCounts.length; i++) {
offsets[i] = mImageInput.readUnsignedShort(); byteCounts[i] = mImageInput.readUnsignedShort();
} }
break; break;
case PSD.COMPRESSION_ZIP: case PSD.COMPRESSION_ZIP:
@ -351,7 +350,7 @@ public class PSDImageReader extends ImageReaderBase {
} }
// What we read here is the "composite layer" of the PSD file // What we read here is the "composite layer" of the PSD file
readImageData(image, rawType.getColorModel(), source, dest, xSub, ySub, offsets, compression); readImageData(image, rawType.getColorModel(), source, dest, xSub, ySub, byteCounts, compression);
if (abortRequested()) { if (abortRequested()) {
processReadAborted(); processReadAborted();
@ -366,7 +365,7 @@ public class PSDImageReader extends ImageReaderBase {
private void readImageData(final BufferedImage pImage, private void readImageData(final BufferedImage pImage,
final ColorModel pSourceCM, final Rectangle pSource, final Rectangle pDest, final ColorModel pSourceCM, final Rectangle pSource, final Rectangle pDest,
final int pXSub, final int pYSub, final int pXSub, final int pYSub,
final int[] pOffsets, final int pCompression) throws IOException { final int[] pByteCounts, final int pCompression) throws IOException {
final WritableRaster raster = pImage.getRaster(); final WritableRaster raster = pImage.getRaster();
// TODO: Conversion if destination cm is not compatible // TODO: Conversion if destination cm is not compatible
@ -388,21 +387,21 @@ public class PSDImageReader extends ImageReaderBase {
DataBufferByte buffer1 = (DataBufferByte) raster.getDataBuffer(); DataBufferByte buffer1 = (DataBufferByte) raster.getDataBuffer();
byte[] data1 = banded ? buffer1.getData(c) : buffer1.getData(); byte[] data1 = banded ? buffer1.getData(c) : buffer1.getData();
read1bitChannel(c, data1, interleavedBands, bandOffset, pSourceCM, row1, pSource, pDest, pXSub, pYSub, pOffsets, pCompression == PSD.COMPRESSION_RLE); read1bitChannel(c, mHeader.mChannels, data1, interleavedBands, bandOffset, pSourceCM, row1, pSource, pDest, pXSub, pYSub, mHeader.mWidth, mHeader.mHeight, pByteCounts, pCompression == PSD.COMPRESSION_RLE);
break; break;
case 8: case 8:
byte[] row8 = ((DataBufferByte) rowRaster.getDataBuffer()).getData(); byte[] row8 = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
DataBufferByte buffer8 = (DataBufferByte) raster.getDataBuffer(); DataBufferByte buffer8 = (DataBufferByte) raster.getDataBuffer();
byte[] data8 = banded ? buffer8.getData(c) : buffer8.getData(); byte[] data8 = banded ? buffer8.getData(c) : buffer8.getData();
read8bitChannel(c, data8, interleavedBands, bandOffset, pSourceCM, row8, pSource, pDest, pXSub, pYSub, pOffsets, pCompression == PSD.COMPRESSION_RLE); read8bitChannel(c, mHeader.mChannels, data8, interleavedBands, bandOffset, pSourceCM, row8, pSource, pDest, pXSub, pYSub, mHeader.mWidth, mHeader.mHeight, pByteCounts, c * mHeader.mHeight, pCompression == PSD.COMPRESSION_RLE);
break; break;
case 16: case 16:
short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData(); short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
DataBufferUShort buffer16 = (DataBufferUShort) raster.getDataBuffer(); DataBufferUShort buffer16 = (DataBufferUShort) raster.getDataBuffer();
short[] data16 = banded ? buffer16.getData(c) : buffer16.getData(); short[] data16 = banded ? buffer16.getData(c) : buffer16.getData();
read16bitChannel(c, data16, interleavedBands, bandOffset, pSourceCM, row16, pSource, pDest, pXSub, pYSub, pOffsets, pCompression == PSD.COMPRESSION_RLE); read16bitChannel(c, mHeader.mChannels, data16, interleavedBands, bandOffset, pSourceCM, row16, pSource, pDest, pXSub, pYSub, mHeader.mWidth, mHeader.mHeight, pByteCounts, c * mHeader.mHeight, pCompression == PSD.COMPRESSION_RLE);
break; break;
default: default:
throw new IIOException("Unknown PSD bit depth: " + mHeader.mBits); throw new IIOException("Unknown PSD bit depth: " + mHeader.mBits);
@ -419,19 +418,22 @@ public class PSDImageReader extends ImageReaderBase {
} }
} }
private void read16bitChannel(final int pChannel, private void read16bitChannel(final int pChannel, final int pChannelCount,
final short[] pData, final int pBands, final int pBandOffset, final short[] pData, final int pBands, final int pBandOffset,
final ColorModel pSourceColorModel, final ColorModel pSourceColorModel,
final short[] pRow, final short[] pRow,
final Rectangle pSource, final Rectangle pDest, final int pXSub, final int pYSub, final Rectangle pSource, final Rectangle pDest,
final int[] pRowOffsets, final boolean pRLECompressed) throws IOException { final int pXSub, final int pYSub,
final int pChannelWidth, final int pChannelHeight,
final int[] pRowByteCounts, final int pRowOffset,
final boolean pRLECompressed) throws IOException {
final boolean isCMYK = pSourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK; final boolean isCMYK = pSourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
final int colorComponents = pSourceColorModel.getColorSpace().getNumComponents(); final int colorComponents = pSourceColorModel.getColorSpace().getNumComponents();
for (int y = 0; y < mHeader.mHeight; y++) { for (int y = 0; y < pChannelHeight; y++) {
// NOTE: Length is in *16 bit values* (shorts) // NOTE: Length is in *16 bit values* (shorts)
int length = 2 * (pRLECompressed ? pRowOffsets[pChannel * mHeader.mHeight + y] : mHeader.mWidth); int length = 2 * (pRLECompressed ? pRowByteCounts[pRowOffset + y] : pChannelWidth);
// TODO: Sometimes need to read the line y == source.y + source.height... // TODO: Sometimes need to read the line y == source.y + source.height...
// Read entire line, if within source region and sampling // Read entire line, if within source region and sampling
@ -439,7 +441,7 @@ public class PSDImageReader extends ImageReaderBase {
if (pRLECompressed) { if (pRLECompressed) {
DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length); DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length);
try { try {
for (int x = 0; x < mHeader.mWidth; x++) { for (int x = 0; x < pChannelWidth; x++) {
pRow[x] = input.readShort(); pRow[x] = input.readShort();
} }
} }
@ -448,7 +450,7 @@ public class PSDImageReader extends ImageReaderBase {
} }
} }
else { else {
mImageInput.readFully(pRow, 0, mHeader.mWidth); mImageInput.readFully(pRow, 0, pChannelWidth);
} }
// TODO: Destination offset...?? // TODO: Destination offset...??
@ -472,81 +474,25 @@ public class PSDImageReader extends ImageReaderBase {
if (abortRequested()) { if (abortRequested()) {
break; break;
} }
processImageProgress((pChannel * y * 100) / mHeader.mChannels * mHeader.mHeight); processImageProgress((pChannel * y * 100) / pChannelCount * pChannelHeight);
} }
} }
private void read8bitChannel(final int pChannel, private void read8bitChannel(final int pChannel, final int pChannelCount,
final byte[] pData, final int pBands, final int pBandOffset,
final ColorModel pSourceColorModel,
final byte[] pRow,
final Rectangle pSource, final Rectangle pDest, final int pXSub, final int pYSub,
final int[] pRowOffsets, final boolean pRLECompressed) throws IOException {
final boolean isCMYK = pSourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
final int colorComponents = pSourceColorModel.getColorSpace().getNumComponents();
for (int y = 0; y < mHeader.mHeight; y++) {
int length = pRLECompressed ? pRowOffsets[pChannel * mHeader.mHeight + y] : mHeader.mWidth;
// TODO: Sometimes need to read the line y == source.y + source.height...
// Read entire line, if within source region and sampling
if (y >= pSource.y && y < pSource.y + pSource.height && y % pYSub == 0) {
if (pRLECompressed) {
DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length);
try {
input.readFully(pRow, 0, mHeader.mWidth);
}
finally {
input.close();
}
}
else {
mImageInput.readFully(pRow, 0, mHeader.mWidth);
}
// TODO: If banded and not sub sampling/cmyk, we could just copy using System.arraycopy
// TODO: Destination offset...??
// Copy line sub sampled into real data
int offset = (y - pSource.y) / pYSub * pDest.width * pBands + pBandOffset;
for (int x = 0; x < pDest.width; x++) {
byte value = pRow[pSource.x + x * pXSub];
// CMYK values are stored inverted, but alpha is not
if (isCMYK && pChannel < colorComponents) {
value = (byte) (255 - value & 0xff);
}
pData[offset + x * pBands] = value;
}
}
else {
mImageInput.skipBytes(length);
}
if (abortRequested()) {
break;
}
processImageProgress((pChannel * y * 100) / mHeader.mChannels * mHeader.mHeight);
}
}
private void read8bitChannelForLAyer(final int pChannel,
final byte[] pData, final int pBands, final int pBandOffset, final byte[] pData, final int pBands, final int pBandOffset,
final ColorModel pSourceColorModel, final ColorModel pSourceColorModel,
final byte[] pRow, final byte[] pRow,
final Rectangle pSource, final Rectangle pDest, final Rectangle pSource, final Rectangle pDest,
final int pXSub, final int pYSub, final int pXSub, final int pYSub,
final int pWidth, final int pHeight, final int pChannelWidth, final int pChannelHeight,
final int[] pRowOffsets, final boolean pRLECompressed) throws IOException { final int[] pRowByteCounts, final int pRowOffset,
final boolean pRLECompressed) throws IOException {
final boolean isCMYK = pSourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK; final boolean isCMYK = pSourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
final int colorComponents = pSourceColorModel.getColorSpace().getNumComponents(); final int colorComponents = pSourceColorModel.getColorSpace().getNumComponents();
for (int y = 0; y < pHeight; y++) { for (int y = 0; y < pChannelHeight; y++) {
// TODO: Extra param? int length = pRLECompressed ? pRowByteCounts[pRowOffset + y] : pChannelWidth;
// int length = pRLECompressed ? pRowOffsets[pChannel * pHeight + y] : pWidth;
int length = pRLECompressed ? pRowOffsets[y] : pWidth;
// TODO: Sometimes need to read the line y == source.y + source.height... // TODO: Sometimes need to read the line y == source.y + source.height...
// Read entire line, if within source region and sampling // Read entire line, if within source region and sampling
@ -554,14 +500,14 @@ public class PSDImageReader extends ImageReaderBase {
if (pRLECompressed) { if (pRLECompressed) {
DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length); DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length);
try { try {
input.readFully(pRow, 0, pWidth); input.readFully(pRow, 0, pChannelWidth);
} }
finally { finally {
input.close(); input.close();
} }
} }
else { else {
mImageInput.readFully(pRow, 0, pWidth); mImageInput.readFully(pRow, 0, pChannelWidth);
} }
// TODO: If banded and not sub sampling/cmyk, we could just copy using System.arraycopy // TODO: If banded and not sub sampling/cmyk, we could just copy using System.arraycopy
@ -586,22 +532,24 @@ public class PSDImageReader extends ImageReaderBase {
if (abortRequested()) { if (abortRequested()) {
break; break;
} }
// processImageProgress((pChannel * y * 100) / mHeader.mChannels * mHeader.mHeight); processImageProgress((pChannel * y * 100) / pChannelCount * pChannelHeight);
} }
} }
private void read1bitChannel(final int pChannel, private void read1bitChannel(final int pChannel, final int pChannelCount,
final byte[] pData, final int pBands, final int pBandOffset, final byte[] pData, final int pBands, final int pBandOffset,
final ColorModel pSourceColorModel, final ColorModel pSourceColorModel,
final byte[] pRow, final byte[] pRow,
final Rectangle pSource, final Rectangle pDest, final int pXSub, final int pYSub, final Rectangle pSource, final Rectangle pDest,
final int[] pRowOffsets, boolean pRLECompressed) throws IOException { final int pXSub, final int pYSub,
final int pChannelWidth, final int pChannelHeight,
final int[] pRowByteCounts, boolean pRLECompressed) throws IOException {
// NOTE: 1 bit channels only occurs once // NOTE: 1 bit channels only occurs once
final int destWidth = (pDest.width + 7) / 8; final int destWidth = (pDest.width + 7) / 8;
for (int y = 0; y < mHeader.mHeight; y++) { for (int y = 0; y < pChannelHeight; y++) {
int length = pRLECompressed ? pRowOffsets[y] : mHeader.mWidth; int length = pRLECompressed ? pRowByteCounts[y] : pChannelWidth;
// TODO: Sometimes need to read the line y == source.y + source.height... // TODO: Sometimes need to read the line y == source.y + source.height...
// Read entire line, if within source region and sampling // Read entire line, if within source region and sampling
@ -661,7 +609,7 @@ public class PSDImageReader extends ImageReaderBase {
if (abortRequested()) { if (abortRequested()) {
break; break;
} }
processImageProgress((pChannel * y * 100) / mHeader.mChannels * mHeader.mHeight); processImageProgress((pChannel * y * 100) / pChannelCount * pChannelHeight);
} }
} }
@ -802,49 +750,25 @@ public class PSDImageReader extends ImageReaderBase {
*/ */
// TODO: Figure out what the last part of that sentence means in practice... // TODO: Figure out what the last part of that sentence means in practice...
int layers = mImageInput.readShort(); int layers = mImageInput.readShort();
// System.out.println("layers: " + layers);
PSDLayerInfo[] layerInfos = new PSDLayerInfo[Math.abs(layers)]; PSDLayerInfo[] layerInfos = new PSDLayerInfo[Math.abs(layers)];
for (int i = 0; i < layerInfos.length; i++) { for (int i = 0; i < layerInfos.length; i++) {
layerInfos[i] = new PSDLayerInfo(mImageInput); layerInfos[i] = new PSDLayerInfo(mImageInput);
// System.out.println("layerInfo[" + i + "]: " + layerInfo[i]);
} }
mLayerInfo = Arrays.asList(layerInfos); mLayerInfo = Arrays.asList(layerInfos);
// TODO: Clean-up
mImageInput.mark(); mImageInput.mark();
ImageTypeSpecifier raw = getRawImageTypeInternal(0); ImageTypeSpecifier raw = getRawImageTypeInternal(0);
ImageTypeSpecifier imageType = getImageTypes(0).next(); ImageTypeSpecifier imageType = getImageTypes(0).next();
mImageInput.reset(); mImageInput.reset();
for (PSDLayerInfo layerInfo : layerInfos) { for (PSDLayerInfo layerInfo : layerInfos) {
// TODO: Skip if one dimension <= 0
int width = layerInfo.mRight - layerInfo.mLeft; int width = layerInfo.mRight - layerInfo.mLeft;
int height = layerInfo.mBottom - layerInfo.mTop; int height = layerInfo.mBottom - layerInfo.mTop;
// If raw/imageType has no alpha, the layers may still have alpha... // Even if raw/imageType has no alpha, the layers may still have alpha...
if (layerInfo.mChannelInfo.length > imageType.getNumBands()) { imageType = getImageTypeForLayer(imageType, layerInfo);
// But, it could also be just the user mask...
boolean userMask = false;
for (PSDChannelInfo channelInfo : layerInfo.mChannelInfo) {
if (channelInfo.mChannelId == -2) {
userMask = true;
break;
}
}
int newBandNum = layerInfo.mChannelInfo.length - (userMask ? 1 : 0);
// If still more channels, then create new imageType
if (newBandNum > imageType.getNumBands()) {
int[] offs = new int[newBandNum];
for (int i = 0, offsLength = offs.length; i < offsLength; i++) {
offs[i] = offsLength - i;
}
imageType = ImageTypeSpecifier.createInterleaved(imageType.getColorModel().getColorSpace(), offs, imageType.getSampleModel().getDataType(), true, false);
}
}
// Create image // Create image
BufferedImage layer = width > 0 && height > 0 ? imageType.createBufferedImage(width, height) : null; BufferedImage layer = width > 0 && height > 0 ? imageType.createBufferedImage(width, height) : null;
@ -852,50 +776,42 @@ public class PSDImageReader extends ImageReaderBase {
Rectangle source = new Rectangle(width, height); Rectangle source = new Rectangle(width, height);
Rectangle dest = source; Rectangle dest = source;
int xsub = 1; final int xsub = 1;
int ysub = 1; final int ysub = 1;
for (PSDChannelInfo channelInfo : layerInfo.mChannelInfo) { for (PSDChannelInfo channelInfo : layerInfo.mChannelInfo) {
int compression = mImageInput.readUnsignedShort();
// TODO: Clean it up...
// TODO: If not explicitly needed, skip layers... // TODO: If not explicitly needed, skip layers...
if (layer == null || channelInfo.mChannelId == -2) { if (layer == null || channelInfo.mChannelId == -2 || (compression != PSD.COMPRESSION_NONE && compression != PSD.COMPRESSION_RLE)) {
// channelId == 2 means "user supplied layer mask", whatever that is... // channelId == 2 means "user supplied layer mask", whatever that is...
mImageInput.skipBytes(channelInfo.mLength); mImageInput.skipBytes(channelInfo.mLength - 2);
} }
else { else {
int c = channelInfo.mChannelId == -1 ? layerInfo.mChannelInfo.length - 1 : channelInfo.mChannelId; int c = channelInfo.mChannelId == -1 ? layerInfo.mChannelInfo.length - 1 : channelInfo.mChannelId;
// System.err.println("channelInfo.mChannelId: " + channelInfo.mChannelId); // NOTE: For layers, byte counts are written per channel, while for the composite data
// System.err.println("c: " + c); // byte counts are written for all channels before the image data.
// System.err.println("layer.getRaster().getNumBands(): " + layer.getRaster().getNumBands()); // This is the reason for the current code duplication
int[] byteCounts = null;
int[] offsets = null;
int compression = mImageInput.readUnsignedShort();
// 0: None, 1: PackBits RLE, 2: Zip, 3: Zip w/prediction // 0: None, 1: PackBits RLE, 2: Zip, 3: Zip w/prediction
switch (compression) { switch (compression) {
case PSD.COMPRESSION_NONE: case PSD.COMPRESSION_NONE:
// System.out.println("Compression: None");
break; break;
case PSD.COMPRESSION_RLE: case PSD.COMPRESSION_RLE:
// System.out.println("Compression: PackBits RLE"); // If RLE, the the image data starts with the byte counts
// for all the scan lines in the channel (LayerBottom-LayerTop), with
// NOTE: Offsets will allow us to easily skip rows before AOI // each count stored as a two*byte value.
// offsets = new int[mHeader.mChannels * mHeader.mHeight]; byteCounts = new int[layerInfo.mBottom - layerInfo.mTop];
offsets = new int[layerInfo.mBottom - layerInfo.mTop]; for (int i = 0; i < byteCounts.length; i++) {
for (int i = 0; i < offsets.length; i++) { byteCounts[i] = mImageInput.readUnsignedShort();
offsets[i] = mImageInput.readUnsignedShort();
} }
break; break;
case PSD.COMPRESSION_ZIP: case PSD.COMPRESSION_ZIP:
// TODO: Skip
// System.out.println("Compression: ZIP");
break;
case PSD.COMPRESSION_ZIP_PREDICTON: case PSD.COMPRESSION_ZIP_PREDICTON:
// TODO: Skip throw new IIOException("ZIP compression not supported yet");
// System.out.println("Compression: ZIP with prediction");
break;
default: default:
// TODO: Do we care, as we can just skip the data? // TODO: Do we care, as we can just skip the data?
// We could issue a warning to the warning listener // We could issue a warning to the warning listener
@ -905,27 +821,18 @@ public class PSDImageReader extends ImageReaderBase {
)); ));
} }
// TODO: If RLE, the the image data starts with the byte counts
// for all the scan lines in the channel (LayerBottom-LayerTop), with
// each count stored as a two*byte value.
// System.out.println("offsets: " + Arrays.toString(offsets));
final WritableRaster raster = layer.getRaster(); final WritableRaster raster = layer.getRaster();
// TODO: Conversion if destination cm is not compatible // TODO: Conversion if destination cm is not compatible
final ColorModel destCM = layer.getColorModel(); final ColorModel destCM = layer.getColorModel();
// TODO: This raster is 3-5 times longer than needed, depending on number of channels... // TODO: This raster is 3-5 times longer than needed, depending on number of channels...
ColorModel sourceCM = raw.getColorModel(); ColorModel sourceCM = raw.getColorModel();
// final WritableRaster rowRaster = sourceCM.createCompatibleWritableRaster(mHeader.mWidth, 1); final WritableRaster rowRaster = sourceCM.createCompatibleWritableRaster(width, 1);
final WritableRaster rowRaster = sourceCM.createCompatibleWritableRaster(layer.getWidth(), 1);
// final int channels = rowRaster.getNumBands(); // final int channels = rowRaster.getNumBands();
final boolean banded = raster.getDataBuffer().getNumBanks() > 1; final boolean banded = raster.getDataBuffer().getNumBanks() > 1;
final int interleavedBands = banded ? 1 : raster.getNumBands(); final int interleavedBands = banded ? 1 : raster.getNumBands();
// for (int c = 0; c < channels; c++) {
// for (int c = 0; c < info.mChannelInfo.length; c++) {
int bandOffset = banded ? 0 : interleavedBands - 1 - c; int bandOffset = banded ? 0 : interleavedBands - 1 - c;
switch (mHeader.mBits) { switch (mHeader.mBits) {
@ -934,21 +841,21 @@ public class PSDImageReader extends ImageReaderBase {
DataBufferByte buffer1 = (DataBufferByte) raster.getDataBuffer(); DataBufferByte buffer1 = (DataBufferByte) raster.getDataBuffer();
byte[] data1 = banded ? buffer1.getData(c) : buffer1.getData(); byte[] data1 = banded ? buffer1.getData(c) : buffer1.getData();
read1bitChannel(c, data1, interleavedBands, bandOffset, sourceCM, row1, source, dest, xsub, ysub, offsets, compression == PSD.COMPRESSION_RLE); read1bitChannel(c, imageType.getNumBands(), data1, interleavedBands, bandOffset, sourceCM, row1, source, dest, xsub, ysub, width, height, byteCounts, compression == PSD.COMPRESSION_RLE);
break; break;
case 8: case 8:
byte[] row8 = ((DataBufferByte) rowRaster.getDataBuffer()).getData(); byte[] row8 = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
DataBufferByte buffer8 = (DataBufferByte) raster.getDataBuffer(); DataBufferByte buffer8 = (DataBufferByte) raster.getDataBuffer();
byte[] data8 = banded ? buffer8.getData(c) : buffer8.getData(); byte[] data8 = banded ? buffer8.getData(c) : buffer8.getData();
read8bitChannelForLAyer(c, data8, interleavedBands, bandOffset, sourceCM, row8, source, dest, xsub, ysub, layer.getWidth(), layer.getHeight(), offsets, compression == PSD.COMPRESSION_RLE); read8bitChannel(c, imageType.getNumBands(), data8, interleavedBands, bandOffset, sourceCM, row8, source, dest, xsub, ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
break; break;
case 16: case 16:
short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData(); short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
DataBufferUShort buffer16 = (DataBufferUShort) raster.getDataBuffer(); DataBufferUShort buffer16 = (DataBufferUShort) raster.getDataBuffer();
short[] data16 = banded ? buffer16.getData(c) : buffer16.getData(); short[] data16 = banded ? buffer16.getData(c) : buffer16.getData();
read16bitChannel(c, data16, interleavedBands, bandOffset, sourceCM, row16, source, dest, xsub, ysub, offsets, compression == PSD.COMPRESSION_RLE); read16bitChannel(c, imageType.getNumBands(), data16, interleavedBands, bandOffset, sourceCM, row16, source, dest, xsub, ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
break; break;
default: default:
throw new IIOException("Unknown PSD bit depth: " + mHeader.mBits); throw new IIOException("Unknown PSD bit depth: " + mHeader.mBits);
@ -960,18 +867,13 @@ public class PSDImageReader extends ImageReaderBase {
} }
} }
// System.err.println("layer: " + layer);
if (layer != null) { if (layer != null) {
showIt(layer, layerInfo.mLayerName + " " + layerInfo.mBlendMode.toString()); showIt(layer, layerInfo.mLayerName + " " + layerInfo.mBlendMode.toString());
} }
} }
// TODO: We seem to have some alignment issues here...
// I'm always reading two bytes off..
long read = mImageInput.getStreamPosition() - pos; long read = mImageInput.getStreamPosition() - pos;
// System.out.println("layerInfoLength: " + layerInfoLength);
// System.out.println("layer info read: " + (read - 4));
long diff = layerInfoLength - (read - 4); // - 4 for the layerInfoLength field itself long diff = layerInfoLength - (read - 4); // - 4 for the layerInfoLength field itself
// System.out.println("diff: " + diff); // System.out.println("diff: " + diff);
mImageInput.skipBytes(diff); mImageInput.skipBytes(diff);
@ -982,6 +884,7 @@ public class PSDImageReader extends ImageReaderBase {
// System.out.println("GlobalLayerMaskInfo length: " + layerMaskInfoLength); // System.out.println("GlobalLayerMaskInfo length: " + layerMaskInfoLength);
if (layerMaskInfoLength > 0) { if (layerMaskInfoLength > 0) {
mGlobalLayerMask = new PSDGlobalLayerMask(mImageInput); mGlobalLayerMask = new PSDGlobalLayerMask(mImageInput);
// System.out.println("mGlobalLayerMask: " + mGlobalLayerMask);
} }
read = mImageInput.getStreamPosition() - pos; read = mImageInput.getStreamPosition() - pos;
@ -995,6 +898,33 @@ public class PSDImageReader extends ImageReaderBase {
} }
} }
private ImageTypeSpecifier getImageTypeForLayer(final ImageTypeSpecifier pOriginal, final PSDLayerInfo pLayerInfo) {
// If layer has more channels than composite data, it's normally extra alpha...
if (pLayerInfo.mChannelInfo.length > pOriginal.getNumBands()) {
// ...but, it could also be just the user mask...
boolean userMask = false;
for (PSDChannelInfo channelInfo : pLayerInfo.mChannelInfo) {
if (channelInfo.mChannelId == -2) {
userMask = true;
break;
}
}
int newBandNum = pLayerInfo.mChannelInfo.length - (userMask ? 1 : 0);
// If there really is more channels, then create new imageTypeSpec
if (newBandNum > pOriginal.getNumBands()) {
int[] offs = new int[newBandNum];
for (int i = 0, offsLength = offs.length; i < offsLength; i++) {
offs[i] = offsLength - i;
}
return ImageTypeSpecifier.createInterleaved(pOriginal.getColorModel().getColorSpace(), offs, pOriginal.getSampleModel().getDataType(), true, false);
}
}
return pOriginal;
}
/// Thumbnail support /// Thumbnail support
@Override @Override
public boolean readerSupportsThumbnails() { public boolean readerSupportsThumbnails() {