Compare commits

...

13 Commits

36 changed files with 259 additions and 70 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>common-image</artifactId>
<packaging>jar</packaging>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>common-io</artifactId>
<packaging>jar</packaging>
@@ -156,9 +156,9 @@ public final class DecoderStream extends FilterInputStream {
}
}
// NOTE: Skipped can never be more than avail, which is
// an int, so the cast is safe
// NOTE: Skipped can never be more than avail, which is an int, so the cast is safe
int skipped = (int) Math.min(pLength - total, buffer.remaining());
buffer.position(buffer.position() + skipped);
total += skipped;
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>common-lang</artifactId>
<packaging>jar</packaging>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-batik</artifactId>
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-core</artifactId>
<name>TwelveMonkeys :: ImageIO :: Core</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-icns</artifactId>
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-ico</artifactId>
<name>TwelveMonkeys :: ImageIO :: ICO plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-iff</artifactId>
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-jmagick</artifactId>
<name>TwelveMonkeys :: ImageIO :: JMagick Plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-jpeg</artifactId>
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
@@ -89,20 +89,25 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
// Scan forward
while (true) {
long realPosition = stream.getStreamPosition();
int marker = stream.readUnsignedShort();
// Skip over weird 0x00 padding, but leave in stream, read seems to handle it well with a warning
int trash = 0;
while (marker == 0) {
marker = stream.readUnsignedShort();
trash += 2;
int marker = stream.readUnsignedByte();
// Skip bad padding before the marker
while (marker != 0xff) {
marker = stream.readUnsignedByte();
trash++;
realPosition++;
}
if (marker == 0x00ff) {
trash++;
marker = 0xff00 | stream.readUnsignedByte();
if (trash != 0) {
// NOTE: We previously allowed these bytes to pass through to the native reader, as it could cope
// and issued the correct warning. However, the native metadata chokes on it, so we'll mask it out.
// TODO: Issue warning from the JPEGImageReader, telling how many bytes we skipped
}
marker = 0xff00 | stream.readUnsignedByte();
// Skip over 0xff padding between markers
while (marker == 0xffff) {
realPosition++;
@@ -113,7 +118,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
// TODO: Refactor to make various segments optional, we probably only want the "Adobe" APP14 segment, 'Exif' APP1 and very few others
if (isAppSegmentMarker(marker) && !(marker == JPEG.APP1 && isAppSegmentWithId("Exif", stream)) && marker != JPEG.APP14) {
int length = stream.readUnsignedShort(); // Length including length field itself
stream.seek(realPosition + trash + 2 + length); // Skip marker (2) + length
stream.seek(realPosition + 2 + length); // Skip marker (2) + length
}
else {
if (marker == JPEG.EOI) {
@@ -129,7 +134,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
}
else {
// Length including length field itself
length = trash + stream.readUnsignedShort() + 2;
length = stream.readUnsignedShort() + 2;
}
segment = new Segment(marker, realPosition, segment.end(), length);
@@ -87,7 +87,8 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase<JPEGImageRe
new TestData(getClassLoaderResource("/jpeg/cmyk-sample.jpg"), new Dimension(160, 227)),
new TestData(getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), new Dimension(2707, 3804)),
new TestData(getClassLoaderResource("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"), new Dimension(640, 480)),
new TestData(getClassLoaderResource("/jpeg/jfif-padded-segments.jpg"), new Dimension(20, 45))
new TestData(getClassLoaderResource("/jpeg/jfif-padded-segments.jpg"), new Dimension(20, 45)),
new TestData(getClassLoaderResource("/jpeg/0x00-to-0xFF-between-segments.jpg"), new Dimension(16, 16))
);
// More test data in specific tests below
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>imageio-metadata</artifactId>
@@ -122,6 +122,14 @@ final class EXIFEntry extends AbstractEntry {
return "HostComputer";
case TIFF.TAG_PREDICTOR:
return "Predictor";
case TIFF.TAG_TILE_WIDTH:
return "TileWidth";
case TIFF.TAG_TILE_HEIGTH:
return "TileHeight";
case TIFF.TAG_TILE_OFFSETS:
return "TileOffsets";
case TIFF.TAG_TILE_BYTE_COUNTS:
return "TileByteCounts";
case TIFF.TAG_COPYRIGHT:
return "Copyright";
case TIFF.TAG_YCBCR_SUB_SAMPLING:
@@ -143,6 +143,9 @@ public interface TIFF {
int TAG_WHITE_POINT = 318;
int TAG_PRIMARY_CHROMATICITIES = 319;
int TAG_COLOR_MAP = 320;
int TAG_INK_SET = 332;
int TAG_INK_NAMES = 333;
int TAG_NUMBER_OF_INKS = 334;
int TAG_EXTRA_SAMPLES = 338;
int TAG_TRANSFER_RANGE = 342;
int TAG_YCBCR_COEFFICIENTS = 529;
@@ -159,23 +159,21 @@ public final class JPEGSegmentUtil {
}
static JPEGSegment readSegment(final ImageInputStream stream, final Map<Integer, List<String>> segmentIdentifiers) throws IOException {
int marker = stream.readUnsignedShort();
// int trash = 0;
int marker = stream.readUnsignedByte();
// Skip over weird 0x00 padding...?
int bad = 0;
while (marker == 0) {
marker = stream.readUnsignedShort();
bad += 2;
// Skip trash padding before the marker
while (marker != 0xff) {
marker = stream.readUnsignedByte();
// trash++;
}
if (marker == 0x00ff) {
bad++;
marker = 0xff00 | stream.readUnsignedByte();
}
// if (trash != 0) {
// TODO: Issue warning?
// System.err.println("trash: " + trash);
// }
if (bad != 0) {
// System.err.println("bad: " + bad);
}
marker = 0xff00 | stream.readUnsignedByte();
// Skip over 0xff padding between markers
while (marker == 0xffff) {
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-pdf</artifactId>
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-pict</artifactId>
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-psd</artifactId>
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-reference</artifactId>
<name>TwelveMonkeys :: ImageIO :: reference test cases</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-thumbsdb</artifactId>
<name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<artifactId>imageio-tiff</artifactId>
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
@@ -367,7 +367,6 @@ abstract class LZWDecoder implements Decoder {
result = 31 * result + (int) firstChar;
return result;
}
}
}
@@ -42,7 +42,7 @@ interface TIFFExtension {
int COMPRESSION_CCITT_T6 = 4;
/** LZW Compression. Was baseline, but moved to extension due to license issues in the LZW algorithm. */
int COMPRESSION_LZW = 5;
/** Deprecated. For backwards compatibility only. */
/** Deprecated. For backwards compatibility only ("Old-style" JPEG). */
int COMPRESSION_OLD_JPEG = 6;
/** JPEG Compression (lossy). */
int COMPRESSION_JPEG = 7;
@@ -73,4 +73,14 @@ interface TIFFExtension {
int JPEG_PROC_BASELINE = 1;
/** Deprecated. For backwards compatibility only ("Old-style" JPEG). */
int JPEG_PROC_LOSSLESS = 14;
/** For use with Photometric: 5 (Separated), when image data is in CMYK color space. */
int INKSET_CMYK = 1;
/**
* For use with Photometric: 5 (Separated), when image data is in a color space other than CMYK.
* See {@link com.twelvemonkeys.imageio.metadata.exif.TIFF#TAG_INK_NAMES InkNames} field for a
* description of the inks to be used.
*/
int INKSET_NOT_CMYK = 2;
}
@@ -258,6 +258,11 @@ public class TIFFImageReader extends ImageReaderBase {
case 1:
// TIFF 6.0 Spec says: 1, 4 or 8 for baseline (1 for bi-level, 4/8 for gray)
// ImageTypeSpecifier supports 1, 2, 4, 8 or 16 bits, we'll go with that for now
if (profile != null && profile.getColorSpaceType() != ColorSpace.TYPE_GRAY) {
processWarningOccurred(String.format("Embedded ICC color profile (type %s), is incompatible with image data (GRAY/type 6). Ignoring profile.", profile.getColorSpaceType()));
profile = null;
}
cs = profile == null ? ColorSpace.getInstance(ColorSpace.CS_GRAY) : ColorSpaces.createColorSpace(profile);
if (cs == ColorSpace.getInstance(ColorSpace.CS_GRAY) && (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 || bitsPerSample == 8 || bitsPerSample == 16)) {
@@ -277,6 +282,11 @@ public class TIFFImageReader extends ImageReaderBase {
// TODO: Sanity check that we have SamplesPerPixel == 3, BitsPerSample == [8,8,8] (or [16,16,16]) and Compression == 1 (none), 5 (LZW), or 6 (JPEG)
case TIFFBaseline.PHOTOMETRIC_RGB:
// RGB
if (profile != null && profile.getColorSpaceType() != ColorSpace.TYPE_RGB) {
processWarningOccurred(String.format("Embedded ICC color profile (type %s), is incompatible with image data (RGB/type 5). Ignoring profile.", profile.getColorSpaceType()));
profile = null;
}
cs = profile == null ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : ColorSpaces.createColorSpace(profile);
switch (samplesPerPixel) {
@@ -330,24 +340,28 @@ public class TIFFImageReader extends ImageReaderBase {
throw new IIOException("Missing ColorMap for Palette TIFF");
}
int[] cmapShort = (int[]) colorMap.getValue();
int[] cmap = new int[colorMap.valueCount() / 3];
// All reds, then greens, and finally blues
for (int i = 0; i < cmap.length; i++) {
cmap[i] = (cmapShort[i ] / 256) << 16
| (cmapShort[i + cmap.length] / 256) << 8
| (cmapShort[i + 2 * cmap.length] / 256);
}
IndexColorModel icm = new IndexColorModel(bitsPerSample, cmap.length, cmap, 0, false, -1, dataType);
IndexColorModel icm = createIndexColorModel(bitsPerSample, dataType, (int[]) colorMap.getValue());
return IndexedImageTypeSpecifier.createFromIndexColorModel(icm);
case TIFFExtension.PHOTOMETRIC_SEPARATED:
// Separated (CMYK etc)
// TODO: Consult the 332/InkSet (1=CMYK, 2=Not CMYK; see InkNames), 334/NumberOfInks (def=4) and optionally 333/InkNames
// Consult the 332/InkSet (1=CMYK, 2=Not CMYK; see InkNames), 334/NumberOfInks (def=4) and optionally 333/InkNames
// If "Not CMYK" we'll need an ICC profile to be able to display (in a useful way), readAsRaster should still work.
int inkSet = getValueAsIntWithDefault(TIFF.TAG_INK_SET, TIFFExtension.INKSET_CMYK);
int numberOfInks = getValueAsIntWithDefault(TIFF.TAG_NUMBER_OF_INKS, 4);
// Profile must be CMYK, OR color component must match NumberOfInks
if (inkSet != TIFFExtension.INKSET_CMYK && (profile == null || profile.getNumComponents() != numberOfInks)) {
throw new IIOException(String.format(
"Embedded ICC color profile for Photometric Separated is missing or is incompatible with image data: %s != NumberOfInks (%s).",
profile != null ? profile.getNumComponents() : "null", numberOfInks));
}
if (profile != null && inkSet == TIFFExtension.INKSET_CMYK && profile.getColorSpaceType() != ColorSpace.TYPE_CMYK) {
processWarningOccurred(String.format("Embedded ICC color profile (type %s), is incompatible with image data (CMYK/type 9). Ignoring profile.", profile.getColorSpaceType()));
profile = null;
}
cs = profile == null ? ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK) : ColorSpaces.createColorSpace(profile);
switch (samplesPerPixel) {
@@ -389,6 +403,43 @@ public class TIFFImageReader extends ImageReaderBase {
}
}
private IndexColorModel createIndexColorModel(final int bitsPerSample, final int dataType, final int[] cmapShort) {
// According to the spec, there should be exactly 3 * bitsPerSample^2 entries in the color map for TIFF.
// Should we enforce this?
int[] cmap = new int[cmapShort.length / 3];
// We'll detect whether the color map data is 8 bit, rather than 16 bit while converting
boolean cmapIs8Bit = true;
// All reds, then greens, and finally blues
for (int i = 0; i < cmap.length; i++) {
cmap[i] = (cmapShort[i ] / 256) << 16
| (cmapShort[i + cmap.length] / 256) << 8
| (cmapShort[i + 2 * cmap.length] / 256);
if (cmapIs8Bit && cmap[i] != 0) {
cmapIs8Bit = false;
}
}
if (cmapIs8Bit) {
// This color map is using only the lower 8 bits, making the image all black.
// We'll create a new color map, based on the non-scaled 8 bit values.
processWarningOccurred("8 bit ColorMap detected.");
// All reds, then greens, and finally blues
for (int i = 0; i < cmap.length; i++) {
cmap[i] = (cmapShort[i ]) << 16
| (cmapShort[i + cmap.length]) << 8
| (cmapShort[i + 2 * cmap.length]);
}
}
return new IndexColorModel(bitsPerSample, cmap.length, cmap, 0, false, -1, dataType);
}
private int getSampleFormat() throws IIOException {
long[] value = getValueAsLongArray(TIFF.TAG_SAMPLE_FORMAT, "SampleFormat", false);
@@ -614,8 +665,8 @@ public class TIFFImageReader extends ImageReaderBase {
? IIOUtil.createStreamAdapter(imageInput, stripTileByteCounts[i])
: IIOUtil.createStreamAdapter(imageInput);
adapter = createDecompressorStream(compression, width, adapter);
adapter = createUnpredictorStream(predictor, width, numBands, getBitsPerSample(), adapter, imageInput.getByteOrder());
adapter = createDecompressorStream(compression, stripTileWidth, adapter);
adapter = createUnpredictorStream(predictor, stripTileWidth, numBands, getBitsPerSample(), adapter, imageInput.getByteOrder());
if (interpretation == TIFFExtension.PHOTOMETRIC_YCBCR && rowRaster.getTransferType() == DataBuffer.TYPE_BYTE) {
adapter = new YCbCrUpsamplerStream(adapter, yCbCrSubsampling, yCbCrPos, colsInTile, yCbCrCoefficients);
@@ -634,10 +685,14 @@ public class TIFFImageReader extends ImageReaderBase {
: new LittleEndianDataInputStream(adapter);
}
// Read a full strip/tile
Raster clippedRow = clipRowToRect(rowRaster, srcRegion,
// Clip the stripTile rowRaster to not exceed the srcRegion
Rectangle clip = new Rectangle(srcRegion);
clip.width = Math.min((colsInTile + xSub - 1) / xSub, srcRegion.width);
Raster clippedRow = clipRowToRect(rowRaster, clip,
param != null ? param.getSourceBands() : null,
param != null ? param.getSourceXSubsampling() : 1);
// Read a full strip/tile
readStripTileData(clippedRow, srcRegion, xSub, ySub, numBands, interpretation, destRaster, col, row, colsInTile, rowsInTile, input);
if (abortRequested()) {
@@ -764,7 +819,7 @@ public class TIFFImageReader extends ImageReaderBase {
int jpegLenght = getValueAsIntWithDefault(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, -1);
// TODO: 515/JPEGRestartInterval (may be absent)
// Currently ignored
// Currently ignored (for lossless only)
// 517/JPEGLosslessPredictors
// 518/JPEGPointTransforms
@@ -782,6 +837,33 @@ public class TIFFImageReader extends ImageReaderBase {
}
imageInput.seek(jpegOffset);
// NOTE: Some known TIFF encoder encodes bad JPEGInterchangeFormat tags,
// but has the correct offset to the JPEG stream in the StripOffsets tag.
long realJPEGOffset = jpegOffset;
short expectedSOI = (short) (imageInput.readByte() << 8 | imageInput.readByte());
if (expectedSOI != (short) JPEG.SOI) {
if (stripTileOffsets != null && stripTileOffsets.length == 1) {
imageInput.seek(stripTileOffsets[0]);
expectedSOI = (short) (imageInput.readByte() << 8 | imageInput.readByte());
if (expectedSOI == (short) JPEG.SOI) {
realJPEGOffset = stripTileOffsets[0];
}
}
if (realJPEGOffset != jpegOffset) {
processWarningOccurred("Incorrect JPEGInterchangeFormat tag, using StripOffsets/TileOffsets instead.");
}
else {
processWarningOccurred("Incorrect JPEGInterchangeFormat tag encountered (not a valid SOI marker).");
// We'll fail below, but we don't need to handle this especially
}
}
imageInput.seek(realJPEGOffset);
stream = new SubImageInputStream(imageInput, jpegLenght != -1 ? jpegLenght : Short.MAX_VALUE);
jpegReader.setInput(stream);
@@ -807,7 +889,6 @@ public class TIFFImageReader extends ImageReaderBase {
}
else {
// The hard way: Read tables and re-create a full JFIF stream
processWarningOccurred("Old-style JPEG compressed TIFF without JFIF stream encountered. Attempting to re-create JFIF stream.");
// 519/JPEGQTables
@@ -1189,7 +1270,7 @@ public class TIFFImageReader extends ImageReaderBase {
case TIFFBaseline.COMPRESSION_PACKBITS:
return new DecoderStream(stream, new PackBitsDecoder(), 1024);
case TIFFExtension.COMPRESSION_LZW:
return new DecoderStream(stream, LZWDecoder.create(LZWDecoder.isOldBitReversedStream(stream)), 1024);
return new DecoderStream(stream, LZWDecoder.create(LZWDecoder.isOldBitReversedStream(stream)), width);
case TIFFExtension.COMPRESSION_ZLIB:
// TIFFphotoshop.pdf (aka TIFF specification, supplement 2) says ZLIB (8) and DEFLATE (32946) algorithms are identical
case TIFFExtension.COMPRESSION_DEFLATE:
@@ -29,12 +29,26 @@ package com.twelvemonkeys.imageio.plugins.tiff;/*
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
import org.junit.Test;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.event.IIOReadWarningListener;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.contains;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* TIFFImageReaderTest
*
@@ -63,7 +77,8 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTestCase<TIFFImageRe
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/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
new TestData(getClassLoaderResource("/tiff/test-single-gray-compression-type-2.tiff"), new Dimension(1728, 1146)), // Gray, CCITT type 2 compressed
new TestData(getClassLoaderResource("/tiff/cramps-tile.tif"), new Dimension(800, 607)) // Gray/WhiteIsZero, uncompressed, striped & tiled...
);
}
@@ -120,4 +135,73 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTestCase<TIFFImageRe
}
// TODO: Test YCbCr colors
@Test
public void testReadOldStyleJPEGGrayscale() throws IOException {
TestData testData = new TestData(getClassLoaderResource("/tiff/grayscale-old-style-jpeg.tiff"), new Dimension(600, 600));
ImageInputStream stream = testData.getInputStream();
try {
TIFFImageReader reader = createReader();
reader.setInput(stream);
BufferedImage image = reader.read(0);
assertNotNull(image);
assertEquals(testData.getDimension(0), new Dimension(image.getWidth(), image.getHeight()));
}
finally {
stream.close();
}
}
@Test
public void testReadIncompatibleICCProfileIgnoredWithWarning() throws IOException {
TestData testData = new TestData(getClassLoaderResource("/tiff/rgb-with-embedded-cmyk-icc.tif"), new Dimension(1500, 1500));
ImageInputStream stream = testData.getInputStream();
try {
TIFFImageReader reader = createReader();
reader.setInput(stream);
IIOReadWarningListener warningListener = mock(IIOReadWarningListener.class);
reader.addIIOReadWarningListener(warningListener);
BufferedImage image = reader.read(0);
assertNotNull(image);
assertEquals(testData.getDimension(0), new Dimension(image.getWidth(), image.getHeight()));
verify(warningListener, atLeastOnce()).warningOccurred(eq(reader), contains("ICC"));
}
finally {
stream.close();
}
}
@Test
public void testColorMap8Bit() throws IOException {
TestData testData = new TestData(getClassLoaderResource("/tiff/scan-lzw-8bit-colormap.tiff"), new Dimension(2550, 3300));
ImageInputStream stream = testData.getInputStream();
try {
TIFFImageReader reader = createReader();
reader.setInput(stream);
IIOReadWarningListener warningListener = mock(IIOReadWarningListener.class);
reader.addIIOReadWarningListener(warningListener);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(new Rectangle(8, 8));
BufferedImage image = reader.read(0, param);
assertNotNull(image);
assertEquals(new Dimension(8, 8), new Dimension(image.getWidth(), image.getHeight()));
assertEquals(0xffffffff, image.getRGB(0, 0)); // The pixel at 0, 0 should be white, not black
verify(warningListener, atLeastOnce()).warningOccurred(eq(reader), contains("ColorMap"));
}
finally {
stream.close();
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.twelvemonkeys.imageio</groupId>
+2 -2
View File
@@ -8,7 +8,7 @@
</parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.0</version>
<version>3.0.1</version>
<packaging>pom</packaging>
<name>Twelvemonkeys</name>
@@ -47,7 +47,7 @@
<connection>scm:git:https://github.com/haraldk/TwelveMonkeys</connection>
<developerConnection>scm:git:https://github.com/haraldk/TwelveMonkeys</developerConnection>
<url>https://github.com/haraldk/TwelveMonkeys</url>
<tag>twelvemonkeys-3.0</tag>
<tag>3.0.1</tag>
</scm>
<properties>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>