mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-01 00:00:02 -04:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 217d14095b | |||
| 1ee21061bd | |||
| 00b15746e4 | |||
| a42ccd031b | |||
| b4fde6ff17 | |||
| b275d7f777 | |||
| c544db9882 | |||
| 9da706dfbb | |||
| 977ecb0482 | |||
| 8143c957bf | |||
| a5d703b29b | |||
| b7265a5117 | |||
| a1769cd40b |
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
+15
-10
@@ -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);
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -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>
|
||||
|
||||
+8
@@ -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:
|
||||
|
||||
+3
@@ -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;
|
||||
|
||||
+11
-13
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
-1
@@ -367,7 +367,6 @@ abstract class LZWDecoder implements Decoder {
|
||||
result = 31 * result + (int) firstChar;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -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;
|
||||
}
|
||||
|
||||
+100
-19
@@ -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:
|
||||
|
||||
+85
-1
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user