diff --git a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStream.java b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStream.java index 68a10284..ff037af3 100644 --- a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStream.java +++ b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStream.java @@ -71,6 +71,8 @@ final class CCITTFaxDecoderStream extends FilterInputStream { private boolean optionUncompressed = false; + private boolean optionByteAligned = false; + public CCITTFaxDecoderStream(final InputStream stream, final int columns, final int type, final int fillOrder, final long options) { super(Validate.notNull(stream, "stream")); @@ -92,6 +94,9 @@ final class CCITTFaxDecoderStream extends FilterInputStream { this.changesCurrentRow = new int[columns + 2]; switch (type) { + case TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE: + optionByteAligned = true; + break; case TIFFExtension.COMPRESSION_CCITT_T4: optionG32D = (options & TIFFExtension.GROUP3OPT_2DENCODING) != 0; optionG3Fill = (options & TIFFExtension.GROUP3OPT_FILLBITS) != 0; @@ -106,6 +111,15 @@ final class CCITTFaxDecoderStream extends FilterInputStream { "CCITT GROUP 3/4 OPTION UNCOMPRESSED is not supported"); } + /** + * This is used for CCITT streams from PDF files, which use EncodedByteAlign + * + * @param enable enable byte alignment + */ + public void setOptionByteAligned(boolean enable) { + optionByteAligned = enable; + } + private void fetch() throws IOException { if (decodedPos >= decodedLength) { decodedLength = 0; @@ -241,11 +255,16 @@ final class CCITTFaxDecoderStream extends FilterInputStream { } private void decodeRowType2() throws IOException { - resetBuffer(); + if (optionByteAligned) { + resetBuffer(); + } decode1D(); } private void decodeRowType4() throws IOException { + if (optionByteAligned) { + resetBuffer(); + } eof: while (true) { // read till next EOL code Node n = eolOnlyTree.root; @@ -272,6 +291,9 @@ final class CCITTFaxDecoderStream extends FilterInputStream { } private void decodeRowType6() throws IOException { + if (optionByteAligned) { + resetBuffer(); + } decode2D(); } @@ -369,17 +391,7 @@ final class CCITTFaxDecoderStream extends FilterInputStream { } private void resetBuffer() throws IOException { - for (int i = 0; i < decodedRow.length; i++) { - decodedRow[i] = 0; - } - - while (true) { - if (bufferPos == -1) { - return; - } - - readBit(); - } + bufferPos = -1; } int buffer = -1; diff --git a/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStreamTest.java b/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStreamTest.java index 0f72542e..8f6c02da 100644 --- a/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStreamTest.java +++ b/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStreamTest.java @@ -74,6 +74,13 @@ public class CCITTFaxDecoderStreamTest { // Line 4: V-1, V0, V0 EOL EOL static final byte[] DATA_G4 = { 0x04, 0x17, (byte) 0xF5, (byte) 0x80, 0x08, 0x00, (byte) 0x80 }; + static final byte[] DATA_G4_ALIGNED = { + 0x04, 0x14, // 00000100 000101(00) + (byte) 0xE0, // 111 (00000) + (byte) 0xE0, // 111 (00000) + 0x58 // 01011 (000) + }; + // TODO: Better tests (full A4 width scan lines?) // From http://www.mikekohn.net/file_formats/tiff.php @@ -262,6 +269,18 @@ public class CCITTFaxDecoderStreamTest { assertEquals((byte) 0b10101010, decoded); } + @Test + public void testDecodeType4ByteAligned() throws IOException { + CCITTFaxDecoderStream stream = new CCITTFaxDecoderStream(new ByteArrayInputStream(DATA_G4_ALIGNED), 6, + TIFFExtension.COMPRESSION_CCITT_T6, 1, 0L); + stream.setOptionByteAligned(true); + + byte[] imageData = ((DataBufferByte) image.getData().getDataBuffer()).getData(); + byte[] bytes = new byte[imageData.length]; + new DataInputStream(stream).readFully(bytes); + assertArrayEquals(imageData, bytes); + } + @Test public void testG3AOE() throws IOException { InputStream inputStream = getClass().getResourceAsStream("/tiff/ccitt/g3aoe.tif");