#626 TIFF CCITT detection only once per IFD

(cherry picked from commit 9d3f271867ebe2babfb7cb0ff1a3bc7f57b2e2b9)
This commit is contained in:
Harald Kuhr 2021-09-16 22:25:06 +02:00
parent b55c623b87
commit df068e350d
2 changed files with 62 additions and 45 deletions

View File

@ -30,14 +30,14 @@
package com.twelvemonkeys.imageio.plugins.tiff;
import com.twelvemonkeys.lang.Validate;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import com.twelvemonkeys.lang.Validate;
/**
* CCITT Modified Huffman RLE, Group 3 (T4) and Group 4 (T6) fax compression.
*
@ -149,23 +149,23 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
this(stream, columns, type, fillOrder, options, type == TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE);
}
static int findCompressionType(final int type, final InputStream in) throws IOException {
// Discover possible incorrect type, revert to RLE
if (type == TIFFExtension.COMPRESSION_CCITT_T4 && in.markSupported()) {
int limit = 500;
static int findCompressionType(final int encodedType, final InputStream stream) throws IOException {
// Discover possible incorrect compression type, revert to RLE if no EOLs found
if (encodedType == TIFFExtension.COMPRESSION_CCITT_T4 && stream.markSupported()) {
int limit = 512;
try {
in.mark(limit);
stream.mark(limit);
int first = in.read();
int second = in.read();
int first = stream.read();
int second = stream.read();
if (first == -1 || second == -1) {
// stream to short
return type;
return encodedType;
}
else if (first == 0 && (((byte) second) >> 4 == 1 || ((byte) second) == 1)) {
// correct, starts with EOL or byte aligned EOL
return type;
return encodedType;
}
short b = (short) (((((byte) first) << 8) + ((byte) second)) >> 4);
int limitBits = limit * 8;
@ -173,7 +173,7 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
byte streamByte = (byte) read;
for (int i = 12; i < limitBits; i++) {
if (i % 8 == 0) {
read = in.read();
read = stream.read();
if (read == -1) {
// no EOL before stream end
return TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE;
@ -192,11 +192,11 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
return TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE;
}
finally {
in.reset();
stream.reset();
}
}
return type;
return encodedType;
}
private void fetch() throws IOException {
@ -212,7 +212,7 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
throw e;
}
// ..otherwise, just let client code try to read past the
// ...otherwise, just let client code try to read past the
// end of stream
decodedLength = -1;
}

View File

@ -30,6 +30,45 @@
package com.twelvemonkeys.imageio.plugins.tiff;
import static com.twelvemonkeys.imageio.util.IIOUtil.createStreamAdapter;
import static com.twelvemonkeys.imageio.util.IIOUtil.subsampleRow;
import static java.util.Arrays.asList;
import java.awt.*;
import java.awt.color.CMMException;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.*;
import java.io.*;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.event.IIOReadWarningListener;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.plugins.jpeg.JPEGImageReadParam;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.color.CIELabColorConverter;
import com.twelvemonkeys.imageio.color.CIELabColorConverter.Illuminant;
@ -60,35 +99,6 @@ import com.twelvemonkeys.io.enc.PackBitsDecoder;
import com.twelvemonkeys.lang.StringUtil;
import com.twelvemonkeys.xml.XMLSerializer;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.imageio.*;
import javax.imageio.event.IIOReadWarningListener;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.plugins.jpeg.JPEGImageReadParam;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.color.CMMException;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.*;
import java.io.*;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import static com.twelvemonkeys.imageio.util.IIOUtil.createStreamAdapter;
import static com.twelvemonkeys.imageio.util.IIOUtil.subsampleRow;
import static java.util.Arrays.asList;
/**
* ImageReader implementation for Aldus/Adobe Tagged Image File Format (TIFF).
* <p>
@ -164,6 +174,7 @@ public final class TIFFImageReader extends ImageReaderBase {
private CompoundDirectory IFDs;
private Directory currentIFD;
private int overrideCCITTCompression = -1;
TIFFImageReader(final ImageReaderSpi provider) {
super(provider);
@ -173,6 +184,7 @@ public final class TIFFImageReader extends ImageReaderBase {
protected void resetMembers() {
IFDs = null;
currentIFD = null;
overrideCCITTCompression = -1;
}
private void readMetadata() throws IOException {
@ -377,6 +389,7 @@ public final class TIFFImageReader extends ImageReaderBase {
readMetadata();
checkBounds(imageIndex);
currentIFD = IFDs.getDirectory(imageIndex);
overrideCCITTCompression = -1; // Reset override for next image
}
@Override
@ -2330,7 +2343,11 @@ public final class TIFFImageReader extends ImageReaderBase {
case TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE:
case TIFFExtension.COMPRESSION_CCITT_T4:
case TIFFExtension.COMPRESSION_CCITT_T6:
return new CCITTFaxDecoderStream(stream, width, findCCITTType(compression, stream), fillOrder, getCCITTOptions(compression), compression == TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE);
// TODO: Find a better way to test for incorrect CCITT type ONCE per IFD
if (overrideCCITTCompression == -1) {
overrideCCITTCompression = findCCITTType(compression, stream);
}
return new CCITTFaxDecoderStream(stream, width, overrideCCITTCompression, fillOrder, getCCITTOptions(compression), compression == TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE);
default:
throw new IllegalArgumentException("Unsupported TIFF compression: " + compression);
}