mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 12:05:29 -04:00
Refactorings.
Implememented subsampled reading for non-compressed imaga data (untested, no test data).
This commit is contained in:
parent
9a05cca4c8
commit
0bc38328de
@ -32,17 +32,21 @@ import com.twelvemonkeys.image.ImageUtil;
|
|||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
import com.twelvemonkeys.imageio.util.IndexedImageTypeSpecifier;
|
import com.twelvemonkeys.imageio.util.IndexedImageTypeSpecifier;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
import java.awt.color.ICC_ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.awt.*;
|
import java.io.DataInput;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -207,6 +211,10 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
BufferedImage image = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight);
|
BufferedImage image = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight);
|
||||||
|
|
||||||
|
final Rectangle source = new Rectangle();
|
||||||
|
final Rectangle dest = new Rectangle();
|
||||||
|
computeRegions(pParam, mHeader.mWidth, mHeader.mHeight, image, source, dest);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE: It seems safe to just leave this out for now. The only thing we need is to support sub sampling.
|
NOTE: It seems safe to just leave this out for now. The only thing we need is to support sub sampling.
|
||||||
Sun's readers does not support arbitrary destination formats.
|
Sun's readers does not support arbitrary destination formats.
|
||||||
@ -228,36 +236,12 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: Should do color convert op for CMYK -> RGB
|
// TODO: Maybe a banded raster would be easier than interleaved? We could still convert to interleaved in CCOp
|
||||||
ColorModel cm = image.getColorModel();
|
|
||||||
final boolean isCMYK = cm.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
|
|
||||||
final int numColorComponents = cm.getColorSpace().getNumComponents();
|
|
||||||
|
|
||||||
WritableRaster raster = image.getRaster();
|
WritableRaster raster = image.getRaster();
|
||||||
if (!(raster.getDataBuffer() instanceof DataBufferByte)) {
|
if (!(raster.getDataBuffer() instanceof DataBufferByte)) {
|
||||||
throw new IIOException("Unsupported raster type: " + raster);
|
throw new IIOException("Unsupported raster type: " + raster);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Maybe a banded raster would be easier than interleaved? We could still convert to interleaved in CCOp
|
|
||||||
final int channels = raster.getNumBands();
|
|
||||||
|
|
||||||
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
|
|
||||||
final byte[] line = new byte[mHeader.mWidth];
|
|
||||||
|
|
||||||
// System.out.println("channels: " + channels);
|
|
||||||
// System.out.println("numColorComponents: " + numColorComponents);
|
|
||||||
// System.out.println("isCMYK: " + isCMYK);
|
|
||||||
|
|
||||||
short compression = mImageInput.readShort();
|
|
||||||
|
|
||||||
// final Rectangle source = getSourceRegion(pParam, mHeader.mWidth, mHeader.mHeight);
|
|
||||||
final Rectangle source = new Rectangle();
|
|
||||||
final Rectangle dest = new Rectangle();
|
|
||||||
computeRegions(pParam, mHeader.mWidth, mHeader.mHeight, image, source, dest);
|
|
||||||
// System.out.println("image: " + new Rectangle(image.getWidth(), image.getHeight()));
|
|
||||||
// System.out.println("source: " + source);
|
|
||||||
// System.out.println("dest: " + dest);
|
|
||||||
|
|
||||||
final int xSub;
|
final int xSub;
|
||||||
final int ySub;
|
final int ySub;
|
||||||
|
|
||||||
@ -269,111 +253,23 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
ySub = pParam.getSourceYSubsampling();
|
ySub = pParam.getSourceYSubsampling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int[] offsets = null;
|
||||||
|
int compression = mImageInput.readShort();
|
||||||
|
|
||||||
// TODO: Bitmap (depth = 1) and 16 bit (depth = 16) must be read differently, obviously...
|
// TODO: Bitmap (depth = 1) and 16 bit (depth = 16) must be read differently, obviously...
|
||||||
// This code works fine for images with channel depth = 8
|
// This code works fine for images with channel depth = 8
|
||||||
switch (compression) {
|
switch (compression) {
|
||||||
case PSD.COMPRESSION_NONE:
|
|
||||||
// TODO: This entire reading block is duplicated and should be replaced with the one for RLE!
|
// TODO: This entire reading block is duplicated and should be replaced with the one for RLE!
|
||||||
// System.out.println("Uncompressed");
|
|
||||||
for (int c = 0; c < mHeader.mChannels; c++) {
|
|
||||||
for (int y = 0; y < mHeader.mHeight; y++) {
|
|
||||||
for (int x = 0; x < mHeader.mWidth; x++) {
|
|
||||||
int offset = (x + y * mHeader.mWidth) * channels;
|
|
||||||
|
|
||||||
byte value = mImageInput.readByte();
|
|
||||||
|
|
||||||
// CMYK values are stored inverted, but alpha is not
|
|
||||||
if (isCMYK && c < numColorComponents) {
|
|
||||||
value = (byte) (255 - value & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// System.out.println("b: " + Integer.toHexString(b & 0xff));
|
|
||||||
data[offset + (channels - 1 - c)] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abortRequested()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
processImageProgress((c * y * 100) / mHeader.mChannels * mHeader.mHeight);
|
|
||||||
}
|
|
||||||
if (abortRequested()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PSD.COMPRESSION_RLE:
|
case PSD.COMPRESSION_RLE:
|
||||||
// System.out.println("PackBits compressed");
|
|
||||||
// NOTE: Offsets will allow us to easily skip rows before AOI
|
// NOTE: Offsets will allow us to easily skip rows before AOI
|
||||||
int[] offsets = new int[mHeader.mChannels * mHeader.mHeight];
|
offsets = new int[mHeader.mChannels * mHeader.mHeight];
|
||||||
for (int i = 0; i < offsets.length; i++) {
|
for (int i = 0; i < offsets.length; i++) {
|
||||||
offsets[i] = mImageInput.readUnsignedShort();
|
offsets[i] = mImageInput.readUnsignedShort();
|
||||||
}
|
}
|
||||||
|
// Fall through
|
||||||
|
|
||||||
int x = 0, y = 0, c = 0;
|
case PSD.COMPRESSION_NONE:
|
||||||
try {
|
read8bitData(raster, image.getColorModel(), source, dest, xSub, ySub, offsets, compression == PSD.COMPRESSION_RLE);
|
||||||
for (c = 0; c < channels; c++) {
|
|
||||||
for (y = 0; y < mHeader.mHeight; y++) {
|
|
||||||
int length = offsets[c * mHeader.mHeight + y];
|
|
||||||
// System.out.println("channel: " + c + " line: " + y + " length: " + length);
|
|
||||||
|
|
||||||
// TODO: Sometimes need to read the line y == source.y + source.height...
|
|
||||||
// Read entire line, if within source region and sampling
|
|
||||||
if (y >= source.y && y < source.y + source.height && y % ySub == 0) {
|
|
||||||
DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length);
|
|
||||||
|
|
||||||
for (x = 0; x < mHeader.mWidth; x++) {
|
|
||||||
byte value = input.readByte();
|
|
||||||
|
|
||||||
// if (c < numColorComponents) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// CMYK values are stored inverted, but alpha is not
|
|
||||||
if (isCMYK && c < numColorComponents) {
|
|
||||||
value = (byte) (255 - value & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// System.out.println("b: " + Integer.toHexString(b & 0xff));
|
|
||||||
line[x] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Destination offset...
|
|
||||||
// Copy line sub sampled into real data
|
|
||||||
int offset = (y - source.y) / ySub * dest.width * channels + (channels - 1 - c);
|
|
||||||
for (int i = 0; i < dest.width; i++) {
|
|
||||||
data[offset + i * channels] = line[source.x + i * xSub];
|
|
||||||
}
|
|
||||||
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mImageInput.skipBytes(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abortRequested()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
processImageProgress((c * y * 100) / mHeader.mChannels * mHeader.mHeight);
|
|
||||||
}
|
|
||||||
if (abortRequested()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
System.err.println("c: " + c);
|
|
||||||
System.err.println("y: " + y);
|
|
||||||
System.err.println("x: " + x);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (IndexOutOfBoundsException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.out.println("data.length: " + data.length);
|
|
||||||
System.err.println("c: " + c);
|
|
||||||
System.err.println("y: " + y);
|
|
||||||
System.err.println("x: " + x);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PSD.COMPRESSION_ZIP:
|
case PSD.COMPRESSION_ZIP:
|
||||||
// TODO: Could probably use the ZIPDecoder (DeflateDecoder) here..
|
// TODO: Could probably use the ZIPDecoder (DeflateDecoder) here..
|
||||||
@ -398,6 +294,87 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void read8bitData(final WritableRaster pRaster, final ColorModel pDestinationColorModel,
|
||||||
|
final Rectangle pSource, final Rectangle pDest,
|
||||||
|
final int pXSub, final int pYSub,
|
||||||
|
final int[] pRowOffsets, final boolean pRLECompressed) throws IOException
|
||||||
|
{
|
||||||
|
final int channels = pRaster.getNumBands();
|
||||||
|
final byte[] data = ((DataBufferByte) pRaster.getDataBuffer()).getData();
|
||||||
|
|
||||||
|
// TODO: FixMe: Use real source color model from native (raw) image type, and convert if needed
|
||||||
|
ColorModel sourceColorModel = pDestinationColorModel;
|
||||||
|
WritableRaster rowRaster = sourceColorModel.createCompatibleWritableRaster(mHeader.mWidth, 1);
|
||||||
|
final byte[] row = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||||
|
|
||||||
|
final boolean isCMYK = sourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
|
||||||
|
final int colorComponents = sourceColorModel.getColorSpace().getNumComponents();
|
||||||
|
|
||||||
|
int x = 0, y = 0, c = 0;
|
||||||
|
try {
|
||||||
|
for (c = 0; c < channels; c++) {
|
||||||
|
for (y = 0; y < mHeader.mHeight; y++) {
|
||||||
|
int length = pRLECompressed ? pRowOffsets[c * 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) {
|
||||||
|
DataInput input = pRLECompressed ? PSDUtil.createPackBitsStream(mImageInput, length) : mImageInput;
|
||||||
|
|
||||||
|
for (x = 0; x < mHeader.mWidth; x++) {
|
||||||
|
byte value = input.readByte();
|
||||||
|
|
||||||
|
|
||||||
|
// CMYK values are stored inverted, but alpha is not
|
||||||
|
if (isCMYK && c < colorComponents) {
|
||||||
|
value = (byte) (255 - value & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
row[x] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Destination offset...??
|
||||||
|
// Copy line sub sampled into real data
|
||||||
|
int offset = (y - pSource.y) / pYSub * pDest.width * channels + (channels - 1 - c);
|
||||||
|
for (int i = 0; i < pDest.width; i++) {
|
||||||
|
data[offset + i * channels] = row[pSource.x + i * pXSub];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pRLECompressed) {
|
||||||
|
((DataInputStream) input).close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mImageInput.skipBytes(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
processImageProgress((c * y * 100) / mHeader.mChannels * mHeader.mHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.err.println("c: " + c);
|
||||||
|
System.err.println("y: " + y);
|
||||||
|
System.err.println("x: " + x);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (IndexOutOfBoundsException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println("data.length: " + data.length);
|
||||||
|
System.err.println("c: " + c);
|
||||||
|
System.err.println("y: " + y);
|
||||||
|
System.err.println("x: " + x);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void decomposeAlpha(final BufferedImage pImage) throws IOException {
|
private void decomposeAlpha(final BufferedImage pImage) throws IOException {
|
||||||
ColorModel cm = pImage.getColorModel();
|
ColorModel cm = pImage.getColorModel();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user