TMI-TIFF: Test case for CCITT modified huffman (type 2), source region support for JPEG and tiled images + minor bug fixes.

This commit is contained in:
Harald Kuhr 2014-09-26 16:01:04 +02:00
parent 8c93be05a5
commit a67c0fb456
7 changed files with 74 additions and 38 deletions

View File

@ -179,7 +179,7 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
throw new IOException("Sum of run-lengths does not equal scan line width: " + index + " > " + columns); throw new IOException("Sum of run-lengths does not equal scan line width: " + index + " > " + columns);
} }
decodedLength = (index / 8) + 1; decodedLength = (index + 7) / 8;
} }
private int decodeRun(short[][] codes, short[][] runLengths, int minCodeSize) throws IOException { private int decodeRun(short[][] codes, short[][] runLengths, int minCodeSize) throws IOException {

View File

@ -55,4 +55,8 @@ interface TIFFBaseline {
int EXTRASAMPLE_UNASSOCIATED_ALPHA = 2; int EXTRASAMPLE_UNASSOCIATED_ALPHA = 2;
int PREDICTOR_NONE = 1; int PREDICTOR_NONE = 1;
int RESOLUTION_UNIT_NONE = 1;
int RESOLUTION_UNIT_DPI = 2; // Default
int RESOLUTION_UNIT_CENTIMETER = 3;
} }

View File

@ -54,9 +54,9 @@ interface TIFFCustom {
int PHOTOMETRIC_LOGL = 32844; int PHOTOMETRIC_LOGL = 32844;
int PHOTOMETRIC_LOGLUV = 32845; int PHOTOMETRIC_LOGLUV = 32845;
/** DNG: CFA (Color Filter Array)*/ /** DNG: CFA (Color Filter Array). */
int PHOTOMETRIC_CFA = 32803; int PHOTOMETRIC_CFA = 32803;
/** DNG: LinearRaw*/ /** DNG: LinearRaw. */
int PHOTOMETRIC_LINEAR_RAW = 34892; int PHOTOMETRIC_LINEAR_RAW = 34892;
int SAMPLEFORMAT_COMPLEX_INT = 5; int SAMPLEFORMAT_COMPLEX_INT = 5;

View File

@ -69,7 +69,8 @@ interface TIFFExtension {
int YCBCR_POSITIONING_CENTERED = 1; int YCBCR_POSITIONING_CENTERED = 1;
int YCBCR_POSITIONING_COSITED = 2; int YCBCR_POSITIONING_COSITED = 2;
// "Old-style" JPEG (obsolete) /** Deprecated. For backwards compatibility only ("Old-style" JPEG). */
int JPEG_PROC_BASELINE = 1; int JPEG_PROC_BASELINE = 1;
/** Deprecated. For backwards compatibility only ("Old-style" JPEG). */
int JPEG_PROC_LOSSLESS = 14; int JPEG_PROC_LOSSLESS = 14;
} }

View File

@ -593,7 +593,6 @@ public class TIFFImageReader extends ImageReaderBase {
// Read data // Read data
processImageStarted(imageIndex); processImageStarted(imageIndex);
// TODO: Read only tiles that lies within region
// General uncompressed/compressed reading // General uncompressed/compressed reading
for (int y = 0; y < tilesDown; y++) { for (int y = 0; y < tilesDown; y++) {
int col = 0; int col = 0;
@ -699,20 +698,24 @@ public class TIFFImageReader extends ImageReaderBase {
int i = y * tilesAcross + x; int i = y * tilesAcross + x;
int colsInTile = Math.min(stripTileWidth, width - col); int colsInTile = Math.min(stripTileWidth, width - col);
imageInput.seek(stripTileOffsets[i]); // Read only tiles that lies within region
ImageInputStream subStream = new SubImageInputStream(imageInput, stripTileByteCounts != null ? (int) stripTileByteCounts[i] : Short.MAX_VALUE); if (new Rectangle(col, row, colsInTile, rowsInTile).intersects(srcRegion)) {
imageInput.seek(stripTileOffsets[i]);
ImageInputStream subStream = new SubImageInputStream(imageInput, stripTileByteCounts != null ? (int) stripTileByteCounts[i] : Short.MAX_VALUE);
try {
jpegReader.setInput(subStream);
jpegParam.setSourceRegion(new Rectangle(0, 0, colsInTile, rowsInTile));
jpegParam.setDestinationOffset(new Point(col - srcRegion.x, row - srcRegion.y));
jpegParam.setDestination(destination);
// TODO: This works only if Gray/YCbCr/RGB, not CMYK/LAB/etc...
// In the latter case we will have to use readAsRaster and do color conversion ourselves
jpegReader.read(0, jpegParam);
}
finally {
subStream.close();
}
try {
jpegReader.setInput(subStream);
jpegParam.setSourceRegion(new Rectangle(0, 0, colsInTile, rowsInTile));
jpegParam.setDestinationOffset(new Point(col, row));
jpegParam.setDestination(destination);
// TODO: This works only if Gray/YCbCr/RGB, not CMYK/LAB/etc...
// In the latter case we will have to use readAsRaster and do color conversion ourselves
jpegReader.read(0, jpegParam);
}
finally {
subStream.close();
} }
if (abortRequested()) { if (abortRequested()) {
@ -865,27 +868,30 @@ public class TIFFImageReader extends ImageReaderBase {
int colsInTile = Math.min(stripTileWidth, width - col); int colsInTile = Math.min(stripTileWidth, width - col);
int i = y * tilesAcross + x; int i = y * tilesAcross + x;
imageInput.seek(stripTileOffsets[i]); // Read only tiles that lies within region
stream = ImageIO.createImageInputStream(new SequenceInputStream(Collections.enumeration( if (new Rectangle(col, row, colsInTile, rowsInTile).intersects(srcRegion)) {
Arrays.asList( imageInput.seek(stripTileOffsets[i]);
createJFIFStream(destRaster, stripTileWidth, stripTileHeight, qTables, dcTables, acTables), stream = ImageIO.createImageInputStream(new SequenceInputStream(Collections.enumeration(
IIOUtil.createStreamAdapter(imageInput, stripTileByteCounts != null ? (int) stripTileByteCounts[i] : Short.MAX_VALUE), Arrays.asList(
new ByteArrayInputStream(new byte[] {(byte) 0xff, (byte) 0xd9}) // EOI createJFIFStream(destRaster, stripTileWidth, stripTileHeight, qTables, dcTables, acTables),
) IIOUtil.createStreamAdapter(imageInput, stripTileByteCounts != null ? (int) stripTileByteCounts[i] : Short.MAX_VALUE),
))); new ByteArrayInputStream(new byte[] {(byte) 0xff, (byte) 0xd9}) // EOI
)
)));
jpegReader.setInput(stream); jpegReader.setInput(stream);
try { try {
jpegParam.setSourceRegion(new Rectangle(0, 0, colsInTile, rowsInTile)); jpegParam.setSourceRegion(new Rectangle(0, 0, colsInTile, rowsInTile));
jpegParam.setDestinationOffset(new Point(col, row)); jpegParam.setDestinationOffset(new Point(col - srcRegion.x, row - srcRegion.y));
jpegParam.setDestination(destination); jpegParam.setDestination(destination);
// TODO: This works only if Gray/YCbCr/RGB, not CMYK/LAB/etc... // TODO: This works only if Gray/YCbCr/RGB, not CMYK/LAB/etc...
// In the latter case we will have to use readAsRaster and do color conversion ourselves // In the latter case we will have to use readAsRaster and do color conversion ourselves
jpegReader.read(0, jpegParam); jpegReader.read(0, jpegParam);
} }
finally { finally {
stream.close(); stream.close();
}
} }
if (abortRequested()) { if (abortRequested()) {

View File

@ -27,9 +27,11 @@ package com.twelvemonkeys.imageio.plugins.tiff;/*
*/ */
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase; import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
import org.junit.Test;
import javax.imageio.spi.ImageReaderSpi; import javax.imageio.spi.ImageReaderSpi;
import java.awt.*; import java.awt.*;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -60,7 +62,8 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTestCase<TIFFImageRe
new TestData(getClassLoaderResource("/tiff/ycbcr-cat.tif"), new Dimension(250, 325)), // YCbCr, LZW compressed new TestData(getClassLoaderResource("/tiff/ycbcr-cat.tif"), new Dimension(250, 325)), // YCbCr, LZW compressed
new TestData(getClassLoaderResource("/tiff/quad-jpeg.tif"), new Dimension(512, 384)), // YCbCr, JPEG compressed, striped new TestData(getClassLoaderResource("/tiff/quad-jpeg.tif"), new Dimension(512, 384)), // YCbCr, JPEG compressed, striped
new TestData(getClassLoaderResource("/tiff/smallliz.tif"), new Dimension(160, 160)), // YCbCr, Old-Style JPEG compressed (full JFIF stream) new TestData(getClassLoaderResource("/tiff/smallliz.tif"), new Dimension(160, 160)), // YCbCr, Old-Style JPEG compressed (full JFIF stream)
new TestData(getClassLoaderResource("/tiff/zackthecat.tif"), new Dimension(234, 213)) // YCbCr, Old-Style JPEG compressed (tables, no JFIF stream) new TestData(getClassLoaderResource("/tiff/zackthecat.tif"), new Dimension(234, 213)), // YCbCr, Old-Style JPEG compressed (tables, no JFIF stream)
new TestData(getClassLoaderResource("/tiff/test-single-gray-compression-type-2.tiff"), new Dimension(1728, 1146)) // Gray, CCITT type 2 compressed
); );
} }
@ -94,5 +97,27 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTestCase<TIFFImageRe
return Arrays.asList("image/tiff"); return Arrays.asList("image/tiff");
} }
@Test
public void testReadWithSourceRegionParamEqualImageTiled() throws IOException {
assertReadWithSourceRegionParamEqualImage(
new Rectangle(23, 23, 15, 15),
new TestData(getClassLoaderResource("/tiff/sm_colors_pb_tile.tif"), new Dimension(64, 64)),
0
);
}
// TODO: Should test USHORT & INT datatypes
@Test
public void testReadWithSourceRegionParamEqualImageJPEG() throws IOException {
// The tiles are 512 x 16, make sure we read across tiles
assertReadWithSourceRegionParamEqualImage(
new Rectangle(71, 71, 17, 21),
new TestData(getClassLoaderResource("/tiff/quad-jpeg.tif"), new Dimension(512, 384)),
0
);
}
// TODO: Test YCbCr colors // TODO: Test YCbCr colors
} }