Added subsampled reading to RLE encoded images. Still work to do.

This commit is contained in:
Harald Kuhr 2009-09-22 22:30:45 +02:00
parent 7ef607815e
commit cac1212944

View File

@ -32,16 +32,14 @@ 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.IIOException; import javax.imageio.*;
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.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.DataInputStream; import java.io.DataInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -85,19 +83,22 @@ public class PSDImageReader extends ImageReaderBase {
mColorSpace = null; mColorSpace = null;
} }
public int getWidth(int pIndex) throws IOException { public int getWidth(final int pIndex) throws IOException {
checkBounds(pIndex); checkBounds(pIndex);
readHeader(); readHeader();
return mHeader.mWidth; return mHeader.mWidth;
} }
public int getHeight(int pIndex) throws IOException { public int getHeight(final int pIndex) throws IOException {
checkBounds(pIndex); checkBounds(pIndex);
readHeader(); readHeader();
return mHeader.mHeight; return mHeader.mHeight;
} }
public Iterator<ImageTypeSpecifier> getImageTypes(int pIndex) throws IOException { public Iterator<ImageTypeSpecifier> getImageTypes(final int pIndex) throws IOException {
// TODO: Check out the custom ImageTypeIterator and ImageTypeProducer used in the Sun provided JPEGImageReader
// Could use similar concept to create lazily-created ImageTypeSpecifiers (util candidate, based on FilterIterator?)
checkBounds(pIndex); checkBounds(pIndex);
readHeader(); readHeader();
@ -205,6 +206,28 @@ public class PSDImageReader extends ImageReaderBase {
readLayerAndMaskInfo(false); readLayerAndMaskInfo(false);
BufferedImage image = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight); BufferedImage image = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight);
/*
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.
// TODO: Create temp raster in native format w * 1
// Read (sub-sampled) row into temp raster (skip other rows)
// If color model (color space) is not RGB, do color convert op
// Otherwise, copy "through" ColorMode?l
// Copy pixels from temp raster
// If possible, leave the destination image "untouched" (accelerated)
// TODO: Banding...
ImageTypeSpecifier spec = getRawImageType(pIndex);
BufferedImage temp = spec.createBufferedImage(getWidth(pIndex), 1);
temp.getRaster();
if (...)
ColorConvertOp convert = new ColorConvertOp(...);
*/
// TODO: Should do color convert op for CMYK -> RGB // TODO: Should do color convert op for CMYK -> RGB
ColorModel cm = image.getColorModel(); ColorModel cm = image.getColorModel();
final boolean isCMYK = cm.getColorSpace().getType() == ColorSpace.TYPE_CMYK; final boolean isCMYK = cm.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
@ -214,17 +237,38 @@ public class PSDImageReader extends ImageReaderBase {
if (!(raster.getDataBuffer() instanceof DataBufferByte)) { if (!(raster.getDataBuffer() instanceof DataBufferByte)) {
throw new IIOException("Unsupported raster type: " + raster); throw new IIOException("Unsupported raster type: " + raster);
} }
byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
// TODO: Maybe a banded raster would be easier than interleaved? // TODO: Maybe a banded raster would be easier than interleaved? We could still convert to interleaved in CCOp
final int channels = raster.getNumBands(); 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("channels: " + channels);
// System.out.println("numColorComponents: " + numColorComponents); // System.out.println("numColorComponents: " + numColorComponents);
// System.out.println("isCMYK: " + isCMYK); // System.out.println("isCMYK: " + isCMYK);
short compression = mImageInput.readShort(); 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 ySub;
if (pParam == null) {
xSub = ySub = 1;
}
else {
xSub = pParam.getSourceXSubsampling();
ySub = pParam.getSourceYSubsampling();
}
// 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) {
@ -271,10 +315,13 @@ public class PSDImageReader extends ImageReaderBase {
for (y = 0; y < mHeader.mHeight; y++) { for (y = 0; y < mHeader.mHeight; y++) {
int length = offsets[c * mHeader.mHeight + y]; int length = offsets[c * mHeader.mHeight + y];
// System.out.println("channel: " + c + " line: " + y + " length: " + length); // System.out.println("channel: " + c + " line: " + y + " length: " + length);
// TODO: Skip rows without decoding
DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length); DataInputStream input = PSDUtil.createPackBitsStream(mImageInput, length);
for (x = 0; x < mHeader.mWidth; x++) {
int offset = (x + y * mHeader.mWidth) * channels;
// 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) {
for (x = 0; x < mHeader.mWidth; x++) {
byte value = input.readByte(); byte value = input.readByte();
// if (c < numColorComponents) { // if (c < numColorComponents) {
@ -287,8 +334,20 @@ public class PSDImageReader extends ImageReaderBase {
} }
// System.out.println("b: " + Integer.toHexString(b & 0xff)); // System.out.println("b: " + Integer.toHexString(b & 0xff));
data[offset + (channels - 1 - c)] = value; 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];
}
}
else {
// TODO: (If not reading compressed) skip data
}
input.close(); input.close();
if (abortRequested()) { if (abortRequested()) {
@ -372,7 +431,6 @@ public class PSDImageReader extends ImageReaderBase {
} }
} }
} }
} }
// System.out.println("PSDImageReader.coerceData: " + cm.getClass()); // System.out.println("PSDImageReader.coerceData: " + cm.getClass());
// System.out.println("other.equals(cm): " + (other == cm)); // System.out.println("other.equals(cm): " + (other == cm));
@ -534,7 +592,7 @@ public class PSDImageReader extends ImageReaderBase {
} }
} }
public static void main(String[] pArgs) throws IOException { public static void main(final String[] pArgs) throws IOException {
PSDImageReader imageReader = new PSDImageReader(null); PSDImageReader imageReader = new PSDImageReader(null);
File file = new File(pArgs[0]); File file = new File(pArgs[0]);
@ -552,7 +610,9 @@ public class PSDImageReader extends ImageReaderBase {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
ImageReadParam param = new ImageReadParam(); ImageReadParam param = new ImageReadParam();
// param.setSourceRegion(new Rectangle(100, 100, 300, 200)); // param.setSourceRegion(new Rectangle(200, 200, 400, 400));
// param.setSourceRegion(new Rectangle(300, 200));
param.setSourceSubsampling(3, 3, 0, 0);
BufferedImage image = imageReader.read(0, param); BufferedImage image = imageReader.read(0, param);
System.out.println("time: " + (System.currentTimeMillis() - start)); System.out.println("time: " + (System.currentTimeMillis() - start));
System.out.println("image: " + image); System.out.println("image: " + image);
@ -572,5 +632,4 @@ public class PSDImageReader extends ImageReaderBase {
showIt(image, file.getName()); showIt(image, file.getName());
} }
} }