mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 04:25:29 -04:00
Experimental reading of layers (8 bit channels only ATM).
This commit is contained in:
parent
ef7029f306
commit
17e8de8c99
@ -531,6 +531,65 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void read8bitChannelForLAyer(final int pChannel,
|
||||||
|
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 pWidth, final int pHeight,
|
||||||
|
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 < pHeight; y++) {
|
||||||
|
// TODO: Extra param?
|
||||||
|
// 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...
|
||||||
|
// 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, pWidth);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mImageInput.readFully(pRow, 0, pWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 read1bitChannel(final int pChannel,
|
private void read1bitChannel(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,
|
||||||
@ -745,51 +804,165 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
int layers = mImageInput.readShort();
|
int layers = mImageInput.readShort();
|
||||||
// System.out.println("layers: " + layers);
|
// System.out.println("layers: " + layers);
|
||||||
|
|
||||||
PSDLayerInfo[] layerInfo = new PSDLayerInfo[Math.abs(layers)];
|
PSDLayerInfo[] layerInfos = new PSDLayerInfo[Math.abs(layers)];
|
||||||
for (int i = 0; i < layerInfo.length; i++) {
|
for (int i = 0; i < layerInfos.length; i++) {
|
||||||
layerInfo[i] = new PSDLayerInfo(mImageInput);
|
layerInfos[i] = new PSDLayerInfo(mImageInput);
|
||||||
// System.out.println("layerInfo[" + i + "]: " + layerInfo[i]);
|
// System.out.println("layerInfo[" + i + "]: " + layerInfo[i]);
|
||||||
}
|
}
|
||||||
mLayerInfo = Arrays.asList(layerInfo);
|
mLayerInfo = Arrays.asList(layerInfos);
|
||||||
|
|
||||||
for (PSDLayerInfo info : layerInfo) {
|
mImageInput.mark();
|
||||||
for (PSDChannelInfo channelInfo : info.mChannelInfo) {
|
ImageTypeSpecifier raw = getRawImageTypeInternal(0);
|
||||||
int compression = mImageInput.readUnsignedShort();
|
ImageTypeSpecifier imageType = getImageTypes(0).next();
|
||||||
// 0: None, 1: PackBits RLE, 2: Zip, 3: Zip w/prediction
|
mImageInput.reset();
|
||||||
switch (compression) {
|
|
||||||
case PSD.COMPRESSION_NONE:
|
for (PSDLayerInfo layerInfo : layerInfos) {
|
||||||
// System.out.println("Compression: None");
|
// TODO: Skip if one dimension <= 0
|
||||||
|
int width = layerInfo.mRight - layerInfo.mLeft;
|
||||||
|
int height = layerInfo.mBottom - layerInfo.mTop;
|
||||||
|
|
||||||
|
// If raw/imageType has no alpha, the layers may still have alpha...
|
||||||
|
if (layerInfo.mChannelInfo.length > imageType.getNumBands()) {
|
||||||
|
|
||||||
|
// But, it could also be just the user mask...
|
||||||
|
boolean userMask = false;
|
||||||
|
for (PSDChannelInfo channelInfo : layerInfo.mChannelInfo) {
|
||||||
|
if (channelInfo.mChannelId == -2) {
|
||||||
|
userMask = true;
|
||||||
break;
|
break;
|
||||||
case PSD.COMPRESSION_RLE:
|
}
|
||||||
// System.out.println("Compression: PackBits RLE");
|
|
||||||
break;
|
|
||||||
case PSD.COMPRESSION_ZIP:
|
|
||||||
// System.out.println("Compression: ZIP");
|
|
||||||
break;
|
|
||||||
case PSD.COMPRESSION_ZIP_PREDICTON:
|
|
||||||
// System.out.println("Compression: ZIP with prediction");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// TODO: Do we care, as we can just skip the data?
|
|
||||||
// We could issue a warning to the warning listener
|
|
||||||
throw new IIOException(String.format(
|
|
||||||
"Unknown PSD compression: %d. Expected 0 (none), 1 (RLE), 2 (ZIP) or 3 (ZIP w/prediction).",
|
|
||||||
compression
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: If RLE, the the image data starts with the byte counts
|
int newBandNum = layerInfo.mChannelInfo.length - (userMask ? 1 : 0);
|
||||||
// for all the scan lines in the channel (LayerBottom*LayerTop), with
|
|
||||||
// each count stored as a two*byte value.
|
|
||||||
// if (compression == 1) {
|
|
||||||
// mImageInput.skipBytes(channelInfo.mLength);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: Read channel image data (same format as composite image channel data)
|
// If still more channels, then create new imageType
|
||||||
mImageInput.skipBytes(channelInfo.mLength - 2);
|
if (newBandNum > imageType.getNumBands()) {
|
||||||
// if (channelInfo.mLength % 2 != 0) {
|
int[] offs = new int[newBandNum];
|
||||||
// mImageInput.readByte();
|
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
|
||||||
|
BufferedImage layer = width > 0 && height > 0 ? imageType.createBufferedImage(width, height) : null;
|
||||||
|
|
||||||
|
Rectangle source = new Rectangle(width, height);
|
||||||
|
Rectangle dest = source;
|
||||||
|
|
||||||
|
int xsub = 1;
|
||||||
|
int ysub = 1;
|
||||||
|
|
||||||
|
for (PSDChannelInfo channelInfo : layerInfo.mChannelInfo) {
|
||||||
|
|
||||||
|
// TODO: If not explicitly needed, skip layers...
|
||||||
|
if (layer == null || channelInfo.mChannelId == -2) {
|
||||||
|
// channelId == 2 means "user supplied layer mask", whatever that is...
|
||||||
|
mImageInput.skipBytes(channelInfo.mLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int c = channelInfo.mChannelId == -1 ? layerInfo.mChannelInfo.length - 1 : channelInfo.mChannelId;
|
||||||
|
|
||||||
|
// System.err.println("channelInfo.mChannelId: " + channelInfo.mChannelId);
|
||||||
|
// System.err.println("c: " + c);
|
||||||
|
// System.err.println("layer.getRaster().getNumBands(): " + layer.getRaster().getNumBands());
|
||||||
|
|
||||||
|
int[] offsets = null;
|
||||||
|
|
||||||
|
int compression = mImageInput.readUnsignedShort();
|
||||||
|
// 0: None, 1: PackBits RLE, 2: Zip, 3: Zip w/prediction
|
||||||
|
switch (compression) {
|
||||||
|
case PSD.COMPRESSION_NONE:
|
||||||
|
// System.out.println("Compression: None");
|
||||||
|
break;
|
||||||
|
case PSD.COMPRESSION_RLE:
|
||||||
|
// System.out.println("Compression: PackBits RLE");
|
||||||
|
|
||||||
|
// NOTE: Offsets will allow us to easily skip rows before AOI
|
||||||
|
// offsets = new int[mHeader.mChannels * mHeader.mHeight];
|
||||||
|
offsets = new int[layerInfo.mBottom - layerInfo.mTop];
|
||||||
|
for (int i = 0; i < offsets.length; i++) {
|
||||||
|
offsets[i] = mImageInput.readUnsignedShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PSD.COMPRESSION_ZIP:
|
||||||
|
// TODO: Skip
|
||||||
|
// System.out.println("Compression: ZIP");
|
||||||
|
break;
|
||||||
|
case PSD.COMPRESSION_ZIP_PREDICTON:
|
||||||
|
// TODO: Skip
|
||||||
|
// System.out.println("Compression: ZIP with prediction");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO: Do we care, as we can just skip the data?
|
||||||
|
// We could issue a warning to the warning listener
|
||||||
|
throw new IIOException(String.format(
|
||||||
|
"Unknown PSD compression: %d. Expected 0 (none), 1 (RLE), 2 (ZIP) or 3 (ZIP w/prediction).",
|
||||||
|
compression
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
// TODO: Conversion if destination cm is not compatible
|
||||||
|
final ColorModel destCM = layer.getColorModel();
|
||||||
|
|
||||||
|
// TODO: This raster is 3-5 times longer than needed, depending on number of channels...
|
||||||
|
ColorModel sourceCM = raw.getColorModel();
|
||||||
|
// final WritableRaster rowRaster = sourceCM.createCompatibleWritableRaster(mHeader.mWidth, 1);
|
||||||
|
final WritableRaster rowRaster = sourceCM.createCompatibleWritableRaster(layer.getWidth(), 1);
|
||||||
|
|
||||||
|
// final int channels = rowRaster.getNumBands();
|
||||||
|
final boolean banded = raster.getDataBuffer().getNumBanks() > 1;
|
||||||
|
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;
|
||||||
|
|
||||||
|
switch (mHeader.mBits) {
|
||||||
|
case 1:
|
||||||
|
byte[] row1 = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||||
|
DataBufferByte buffer1 = (DataBufferByte) raster.getDataBuffer();
|
||||||
|
byte[] data1 = banded ? buffer1.getData(c) : buffer1.getData();
|
||||||
|
|
||||||
|
read1bitChannel(c, data1, interleavedBands, bandOffset, sourceCM, row1, source, dest, xsub, ysub, offsets, compression == PSD.COMPRESSION_RLE);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
byte[] row8 = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||||
|
DataBufferByte buffer8 = (DataBufferByte) raster.getDataBuffer();
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
|
||||||
|
DataBufferUShort buffer16 = (DataBufferUShort) raster.getDataBuffer();
|
||||||
|
short[] data16 = banded ? buffer16.getData(c) : buffer16.getData();
|
||||||
|
|
||||||
|
read16bitChannel(c, data16, interleavedBands, bandOffset, sourceCM, row16, source, dest, xsub, ysub, offsets, compression == PSD.COMPRESSION_RLE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IIOException("Unknown PSD bit depth: " + mHeader.mBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.err.println("layer: " + layer);
|
||||||
|
if (layer != null) {
|
||||||
|
showIt(layer, layerInfo.mLayerName + " " + layerInfo.mBlendMode.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -798,8 +971,8 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
long read = mImageInput.getStreamPosition() - pos;
|
long read = mImageInput.getStreamPosition() - pos;
|
||||||
// System.out.println("layerInfoLength: " + layerInfoLength);
|
// System.out.println("layerInfoLength: " + layerInfoLength);
|
||||||
// System.out.println("layer info read: " + (read - 4)); // - 4 for the layerInfoLength field itself
|
// System.out.println("layer info read: " + (read - 4));
|
||||||
long diff = layerInfoLength - (read - 4);
|
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);
|
||||||
|
|
||||||
@ -939,14 +1112,14 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
ImageInputStream stream = ImageIO.createImageInputStream(file);
|
ImageInputStream stream = ImageIO.createImageInputStream(file);
|
||||||
imageReader.setInput(stream);
|
imageReader.setInput(stream);
|
||||||
imageReader.readHeader();
|
imageReader.readHeader();
|
||||||
System.out.println("imageReader.mHeader: " + imageReader.mHeader);
|
// System.out.println("imageReader.mHeader: " + imageReader.mHeader);
|
||||||
|
|
||||||
imageReader.readImageResources(true);
|
imageReader.readImageResources(true);
|
||||||
System.out.println("imageReader.mImageResources: " + imageReader.mImageResources);
|
// System.out.println("imageReader.mImageResources: " + imageReader.mImageResources);
|
||||||
|
|
||||||
imageReader.readLayerAndMaskInfo(true);
|
imageReader.readLayerAndMaskInfo(true);
|
||||||
System.out.println("imageReader.mLayerInfo: " + imageReader.mLayerInfo);
|
System.out.println("imageReader.mLayerInfo: " + imageReader.mLayerInfo);
|
||||||
System.out.println("imageReader.mGlobalLayerMask: " + imageReader.mGlobalLayerMask);
|
// System.out.println("imageReader.mGlobalLayerMask: " + imageReader.mGlobalLayerMask);
|
||||||
|
|
||||||
if (imageReader.hasThumbnails(0)) {
|
if (imageReader.hasThumbnails(0)) {
|
||||||
int thumbnails = imageReader.getNumThumbnails(0);
|
int thumbnails = imageReader.getNumThumbnails(0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user