commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dam...@apache.org
Subject svn commit: r1221170 - in /commons/proper/sanselan/trunk/src: main/java/org/apache/commons/sanselan/common/itu_t4/ main/java/org/apache/commons/sanselan/formats/tiff/ main/java/org/apache/commons/sanselan/formats/tiff/datareaders/ site/xdoc/ test/data/...
Date Tue, 20 Dec 2011 09:44:32 GMT
Author: damjan
Date: Tue Dec 20 09:44:31 2011
New Revision: 1221170

URL: http://svn.apache.org/viewvc?rev=1221170&view=rev
Log:
Pass the TIFF directory to the DataReader so it can be used
to determine compression options.
Simplify the Modified Huffman TIFF decompression.
Add support for CCITT T.4 and T.6 decompression,
and comprehensive tests for these.
Update the website's format support accordingly.

Jira issue key: SANSELAN-48


Added:
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4AndT6Compression.java
  (with props)
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639 - DSC_0307
- small CCITT T.4 1D fill.tiff   (with props)
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639 - DSC_0307
- small CCITT T.4 1D no fill.tiff   (with props)
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639 - DSC_0307
- small CCITT T.4 2D fill.tiff   (with props)
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639 - DSC_0307
- small CCITT T.4 2D no fill.tiff   (with props)
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639 - DSC_0307
- small CCITT T.6.tiff   (with props)
Modified:
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4Compression.java
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4_T6_Tables.java
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageData.java
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderStrips.java
    commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderTiled.java
    commons/proper/sanselan/trunk/src/site/xdoc/formatsupport.xml
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt

Added: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4AndT6Compression.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4AndT6Compression.java?rev=1221170&view=auto
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4AndT6Compression.java
(added)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4AndT6Compression.java
Tue Dec 20 09:44:31 2011
@@ -0,0 +1,400 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.common.itu_t4;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.apache.commons.sanselan.ImageReadException;
+import org.apache.commons.sanselan.common.BitArrayOutputStream;
+import org.apache.commons.sanselan.common.BitInputStreamFlexible;
+
+
+public class T4AndT6Compression {
+    private static final HuffmanTree whiteRunLengths = new HuffmanTree();
+    private static final HuffmanTree blackRunLengths = new HuffmanTree();
+    private static final HuffmanTree controlCodes = new HuffmanTree();
+    
+    private static final int WHITE = 0;
+    private static final int BLACK = 1;
+    
+    static {
+        try {
+            for (int i = 0; i < T4_T6_Tables.whiteTerminatingCodes.length; i++) {
+                T4_T6_Tables.Entry entry = T4_T6_Tables.whiteTerminatingCodes[i];
+                whiteRunLengths.insert(entry.bitString, entry.value);
+            }
+            for (int i = 0; i < T4_T6_Tables.whiteMakeUpCodes.length; i++) {
+                T4_T6_Tables.Entry entry = T4_T6_Tables.whiteMakeUpCodes[i];
+                whiteRunLengths.insert(entry.bitString, entry.value);
+            }
+            for (int i = 0; i < T4_T6_Tables.blackTerminatingCodes.length; i++) {
+                T4_T6_Tables.Entry entry = T4_T6_Tables.blackTerminatingCodes[i];
+                blackRunLengths.insert(entry.bitString, entry.value);
+            }
+            for (int i = 0; i < T4_T6_Tables.blackMakeUpCodes.length; i++) {
+                T4_T6_Tables.Entry entry = T4_T6_Tables.blackMakeUpCodes[i];
+                blackRunLengths.insert(entry.bitString, entry.value);
+            }
+            for (int i = 0; i < T4_T6_Tables.additionalMakeUpCodes.length; i++) {
+                T4_T6_Tables.Entry entry = T4_T6_Tables.additionalMakeUpCodes[i];
+                whiteRunLengths.insert(entry.bitString, entry.value);
+                blackRunLengths.insert(entry.bitString, entry.value);
+            }
+            controlCodes.insert(T4_T6_Tables.EOL.bitString, T4_T6_Tables.EOL);
+            controlCodes.insert(T4_T6_Tables.EOL13.bitString, T4_T6_Tables.EOL13);
+            controlCodes.insert(T4_T6_Tables.EOL14.bitString, T4_T6_Tables.EOL14);
+            controlCodes.insert(T4_T6_Tables.EOL15.bitString, T4_T6_Tables.EOL15);
+            controlCodes.insert(T4_T6_Tables.EOL16.bitString, T4_T6_Tables.EOL16);
+            controlCodes.insert(T4_T6_Tables.EOL17.bitString, T4_T6_Tables.EOL17);
+            controlCodes.insert(T4_T6_Tables.EOL18.bitString, T4_T6_Tables.EOL18);
+            controlCodes.insert(T4_T6_Tables.EOL19.bitString, T4_T6_Tables.EOL19);
+            controlCodes.insert(T4_T6_Tables.P.bitString, T4_T6_Tables.P);
+            controlCodes.insert(T4_T6_Tables.H.bitString, T4_T6_Tables.H);
+            controlCodes.insert(T4_T6_Tables.V0.bitString, T4_T6_Tables.V0);
+            controlCodes.insert(T4_T6_Tables.VL1.bitString, T4_T6_Tables.VL1);
+            controlCodes.insert(T4_T6_Tables.VL2.bitString, T4_T6_Tables.VL2);
+            controlCodes.insert(T4_T6_Tables.VL3.bitString, T4_T6_Tables.VL3);
+            controlCodes.insert(T4_T6_Tables.VR1.bitString, T4_T6_Tables.VR1);
+            controlCodes.insert(T4_T6_Tables.VR2.bitString, T4_T6_Tables.VR2);
+            controlCodes.insert(T4_T6_Tables.VR3.bitString, T4_T6_Tables.VR3);
+        } catch (HuffmanTreeException cannotHappen) {
+        }
+    }
+    
+    /**
+     * Decompresses the "Modified Huffman" encoding of section 10 in the TIFF6 specification.
+     * No EOLs, no RTC, rows are padded to end on a byte boundary.
+     * @param compressed
+     * @param width
+     * @param height
+     * @return
+     * @throws
+     */
+    public static byte[] decompressModifiedHuffman(byte[] compressed, int width, int height)
throws ImageReadException {
+        BitInputStreamFlexible inputStream = new BitInputStreamFlexible(
+                new ByteArrayInputStream(compressed));
+        BitArrayOutputStream outputStream = new BitArrayOutputStream();
+        for (int y = 0; y < height; y++) {
+            int color = WHITE;
+            int rowLength;
+            for (rowLength = 0; rowLength < width;) {
+                int runLength = readTotalRunLength(inputStream, color);
+                for (int i = 0; i < runLength; i++) {
+                    outputStream.writeBit(color);
+                }
+                color = 1 - color;
+                rowLength += runLength;
+            }
+            
+            if (rowLength == width) {
+                inputStream.flushCache();
+                outputStream.flush();
+            } else if (rowLength > width) {
+                throw new ImageReadException("Unrecoverable row length error in image row
" + y);
+            }
+        }
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * Decompresses T.4 1D encoded data. EOL at the beginning and after each row,
+     * can be preceded by fill bits to fit on a byte boundary, no RTC.
+     * @param compressed
+     * @param width
+     * @param height
+     * @return
+     * @throws ImageReadException
+     */
+    public static byte[] decompressT4_1D(byte[] compressed, int width, int height, boolean
hasFill) throws ImageReadException {
+        BitInputStreamFlexible inputStream = new BitInputStreamFlexible(
+                new ByteArrayInputStream(compressed));
+        BitArrayOutputStream outputStream = new BitArrayOutputStream();
+        for (int y = 0; y < height; y++) {
+            T4_T6_Tables.Entry entry;
+            int rowLength;
+            try {
+                entry = (T4_T6_Tables.Entry) controlCodes.decode(inputStream);
+                if (entry != T4_T6_Tables.EOL &&
+                        entry != T4_T6_Tables.EOL13 &&
+                        entry != T4_T6_Tables.EOL14 &&
+                        entry != T4_T6_Tables.EOL15 &&
+                        entry != T4_T6_Tables.EOL16 &&
+                        entry != T4_T6_Tables.EOL17 &&
+                        entry != T4_T6_Tables.EOL18 &&
+                        entry != T4_T6_Tables.EOL19) {
+                    throw new ImageReadException("Expected EOL not found");
+                }
+                int color = WHITE;
+                for (rowLength = 0; rowLength < width;) {
+                    int runLength = readTotalRunLength(inputStream, color);
+                    for (int i = 0; i < runLength; i++) {
+                        outputStream.writeBit(color);
+                    }
+                    color = 1 - color;
+                    rowLength += runLength;
+                }
+            } catch (HuffmanTreeException huffmanException) {
+                throw new ImageReadException("Decompression error", huffmanException);
+            }
+            
+            if (rowLength == width) {
+                outputStream.flush();
+            } else if (rowLength > width) {
+                throw new ImageReadException("Unrecoverable row length error in image row
" + y);
+            }
+        }
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * Decompressed T.4 2D encoded data. EOL at the beginning and after each row,
+     * can be preceded by fill bits to fit on a byte boundary, and is succeeded
+     * by a tag bit determining whether the next line is encoded using 1D or 2D.
+     * No RTC.
+     * @param compressed
+     * @param width
+     * @param height
+     * @return
+     * @throws ImageReadException
+     */
+    public static byte[] decompressT4_2D(byte[] compressed, int width, int height, boolean
hasFill) throws ImageReadException {
+        BitInputStreamFlexible inputStream = new BitInputStreamFlexible(
+                new ByteArrayInputStream(compressed));
+        BitArrayOutputStream outputStream = new BitArrayOutputStream();
+        int[] referenceLine = new int[width];
+        for (int y = 0; y < height; y++) {
+            T4_T6_Tables.Entry entry;
+            int rowLength = 0;
+            try {
+                entry = (T4_T6_Tables.Entry) controlCodes.decode(inputStream);
+                if (entry != T4_T6_Tables.EOL &&
+                        entry != T4_T6_Tables.EOL13 &&
+                        entry != T4_T6_Tables.EOL14 &&
+                        entry != T4_T6_Tables.EOL15 &&
+                        entry != T4_T6_Tables.EOL16 &&
+                        entry != T4_T6_Tables.EOL17 &&
+                        entry != T4_T6_Tables.EOL18 &&
+                        entry != T4_T6_Tables.EOL19) {
+                    throw new ImageReadException("Expected EOL not found");
+                }
+                int tagBit = inputStream.readBits(1);
+                if (tagBit == 0) {
+                    // 2D
+                    int codingA0Color = WHITE;
+                    int referenceA0Color = WHITE;
+                    int b1 = nextChangingElement(referenceLine, referenceA0Color, 0);
+                    int b2 = nextChangingElement(referenceLine, 1 - referenceA0Color, b1
+ 1);
+                    for (int a0 = 0; a0 < width; ) {
+                        int a1, a2;
+                        entry = (T4_T6_Tables.Entry) controlCodes.decode(inputStream);
+                        if (entry == T4_T6_Tables.P) {
+                            fillRange(outputStream, referenceLine, a0, b2, codingA0Color);
+                            a0 = b2;
+                        } else if (entry == T4_T6_Tables.H) {
+                            int a0a1 = readTotalRunLength(inputStream, codingA0Color);
+                            a1 = a0 + a0a1;
+                            fillRange(outputStream, referenceLine, a0, a1, codingA0Color);
+                            int a1a2 = readTotalRunLength(inputStream, 1 - codingA0Color);
+                            a2 = a1 + a1a2;
+                            fillRange(outputStream, referenceLine, a1, a2, 1 - codingA0Color);
+                            a0 = a2;
+                        } else {
+                            int a1b1;
+                            if (entry == T4_T6_Tables.V0) {
+                                a1b1 = 0;
+                            } else if (entry == T4_T6_Tables.VL1) {
+                                a1b1 = -1;
+                            } else if (entry == T4_T6_Tables.VL2) {
+                                a1b1 = -2;
+                            } else if (entry == T4_T6_Tables.VL3) {
+                                a1b1 = -3;
+                            } else if (entry == T4_T6_Tables.VR1) {
+                                a1b1 = 1;
+                            } else if (entry == T4_T6_Tables.VR2) {
+                                a1b1 = 2;
+                            } else if (entry == T4_T6_Tables.VR3) {
+                                a1b1 = 3;
+                            } else {
+                                throw new ImageReadException("Invalid/unknown T.4 control
code " + entry.bitString);
+                            }
+                            a1 = b1 + a1b1;
+                            fillRange(outputStream, referenceLine, a0, a1, codingA0Color);
+                            a0 = a1;
+                            codingA0Color = 1 - codingA0Color;
+                        }
+                        referenceA0Color = changingElementAt(referenceLine, a0);
+                        if (codingA0Color == referenceA0Color) {
+                            b1 = nextChangingElement(referenceLine, referenceA0Color, a0
+ 1);
+                        } else {
+                            b1 = nextChangingElement(referenceLine, referenceA0Color, a0
+ 1);
+                            b1 = nextChangingElement(referenceLine, 1 - referenceA0Color,
b1 + 1);
+                        }
+                        b2 = nextChangingElement(referenceLine, 1 - codingA0Color, b1 + 1);
+                        rowLength = a0;
+                    }
+                } else {
+                    // 1D
+                    int color = WHITE;
+                    for (rowLength = 0; rowLength < width;) {
+                        int runLength = readTotalRunLength(inputStream, color);
+                        for (int i = 0; i < runLength; i++) {
+                            outputStream.writeBit(color);
+                            referenceLine[rowLength + i] = color;
+                        }
+                        color = 1 - color;
+                        rowLength += runLength;
+                    }
+                }
+            } catch (IOException ioException) {
+                throw new ImageReadException("Decompression error", ioException);
+            } catch (HuffmanTreeException huffmanException) {
+                throw new ImageReadException("Decompression error", huffmanException);
+            }
+            
+            if (rowLength == width) {
+                outputStream.flush();
+            } else if (rowLength > width) {
+                throw new ImageReadException("Unrecoverable row length error in image row
" + y);
+            }
+        }
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * Decompress T.6 encoded data. No EOLs, except for 2 consecutive ones at the end
+     * (the EOFB, end of fax block). No RTC. No fill bits anywhere. All data is 2D encoded.
+     * @param compressed
+     * @param width
+     * @param height
+     * @return
+     * @throws ImageReadException
+     */
+    public static byte[] decompressT6(byte[] compressed, int width, int height) throws ImageReadException
{
+        BitInputStreamFlexible inputStream = new BitInputStreamFlexible(
+                new ByteArrayInputStream(compressed));
+        BitArrayOutputStream outputStream = new BitArrayOutputStream();
+        int[] referenceLine = new int[width];
+        for (int y = 0; y < height; y++) {
+            T4_T6_Tables.Entry entry;
+            int rowLength = 0;
+            try {
+                int codingA0Color = WHITE;
+                int referenceA0Color = WHITE;
+                int b1 = nextChangingElement(referenceLine, referenceA0Color, 0);
+                int b2 = nextChangingElement(referenceLine, 1 - referenceA0Color, b1 + 1);
+                for (int a0 = 0; a0 < width; ) {
+                    int a1, a2;
+                    entry = (T4_T6_Tables.Entry) controlCodes.decode(inputStream);
+                    if (entry == T4_T6_Tables.P) {
+                        fillRange(outputStream, referenceLine, a0, b2, codingA0Color);
+                        a0 = b2;
+                    } else if (entry == T4_T6_Tables.H) {
+                        int a0a1 = readTotalRunLength(inputStream, codingA0Color);
+                        a1 = a0 + a0a1;
+                        fillRange(outputStream, referenceLine, a0, a1, codingA0Color);
+                        int a1a2 = readTotalRunLength(inputStream, 1 - codingA0Color);
+                        a2 = a1 + a1a2;
+                        fillRange(outputStream, referenceLine, a1, a2, 1 - codingA0Color);
+                        a0 = a2;
+                    } else {
+                        int a1b1;
+                        if (entry == T4_T6_Tables.V0) {
+                            a1b1 = 0;
+                        } else if (entry == T4_T6_Tables.VL1) {
+                            a1b1 = -1;
+                        } else if (entry == T4_T6_Tables.VL2) {
+                            a1b1 = -2;
+                        } else if (entry == T4_T6_Tables.VL3) {
+                            a1b1 = -3;
+                        } else if (entry == T4_T6_Tables.VR1) {
+                            a1b1 = 1;
+                        } else if (entry == T4_T6_Tables.VR2) {
+                            a1b1 = 2;
+                        } else if (entry == T4_T6_Tables.VR3) {
+                            a1b1 = 3;
+                        } else {
+                            throw new ImageReadException("Invalid/unknown T.6 control code
" + entry.bitString);
+                        }
+                        a1 = b1 + a1b1;
+                        fillRange(outputStream, referenceLine, a0, a1, codingA0Color);
+                        a0 = a1;
+                        codingA0Color = 1 - codingA0Color;
+                    }
+                    referenceA0Color = changingElementAt(referenceLine, a0);
+                    if (codingA0Color == referenceA0Color) {
+                        b1 = nextChangingElement(referenceLine, referenceA0Color, a0 + 1);
+                    } else {
+                        b1 = nextChangingElement(referenceLine, referenceA0Color, a0 + 1);
+                        b1 = nextChangingElement(referenceLine, 1 - referenceA0Color, b1
+ 1);
+                    }
+                    b2 = nextChangingElement(referenceLine, 1 - codingA0Color, b1 + 1);
+                    rowLength = a0;
+                }
+            } catch (HuffmanTreeException huffmanException) {
+                throw new ImageReadException("Decompression error", huffmanException);
+            }
+            
+            if (rowLength == width) {
+                outputStream.flush();
+            } else if (rowLength > width) {
+                throw new ImageReadException("Unrecoverable row length error in image row
" + y);
+            }
+        }
+        return outputStream.toByteArray();
+    }
+    
+    private static int readTotalRunLength(BitInputStreamFlexible bitStream, int color) throws
ImageReadException {
+        try {
+            int totalLength = 0;
+            Integer runLength;
+            do {
+                if (color == WHITE) {
+                    runLength = (Integer)whiteRunLengths.decode(bitStream);
+                } else {
+                    runLength = (Integer)blackRunLengths.decode(bitStream);
+                }
+                totalLength += runLength.intValue();
+            } while (runLength.intValue() > 63);
+            return totalLength;
+        } catch (HuffmanTreeException huffmanException) {
+            throw new ImageReadException("Decompression error", huffmanException);
+        }
+    }
+    
+    private static int changingElementAt(int[] line, int position) {
+        if (position < 0 || position >= line.length) {
+            return WHITE;
+        }
+        return line[position];
+    }
+    
+    private static int nextChangingElement(int[] line, int currentColour, int start) {
+        int position;
+        for (position = start; position < line.length && line[position] == currentColour;
position++)
+            ;
+        return position < line.length ? position : line.length;
+    }
+    
+    private static void fillRange(BitArrayOutputStream outputStream, int[] referenceRow,
+            int a0, int end, int color) {
+        for (int i = a0; i < end; i++) {
+            referenceRow[i] = color;
+            outputStream.writeBit(color);
+        }
+    }
+}

Propchange: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4AndT6Compression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4Compression.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4Compression.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4Compression.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4Compression.java
Tue Dec 20 09:44:31 2011
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.sanselan.common.itu_t4;
-
-import java.io.ByteArrayInputStream;
-
-import org.apache.commons.sanselan.ImageReadException;
-import org.apache.commons.sanselan.common.BitArrayOutputStream;
-import org.apache.commons.sanselan.common.BitInputStreamFlexible;
-
-
-public class T4Compression {
-    private static final HuffmanTree whiteRunLengths = new HuffmanTree();
-    private static final HuffmanTree blackRunLengths = new HuffmanTree();
-    
-    static {
-        try {
-            for (int i = 0; i < T4_T6_Tables.whiteTerminatingCodes.length; i++) {
-                T4_T6_Tables.Entry entry = T4_T6_Tables.whiteTerminatingCodes[i];
-                whiteRunLengths.insert(entry.bitString, entry.value);
-            }
-            for (int i = 0; i < T4_T6_Tables.whiteMakeUpCodes.length; i++) {
-                T4_T6_Tables.Entry entry = T4_T6_Tables.whiteMakeUpCodes[i];
-                whiteRunLengths.insert(entry.bitString, entry.value);
-            }
-            for (int i = 0; i < T4_T6_Tables.blackTerminatingCodes.length; i++) {
-                T4_T6_Tables.Entry entry = T4_T6_Tables.blackTerminatingCodes[i];
-                blackRunLengths.insert(entry.bitString, entry.value);
-            }
-            for (int i = 0; i < T4_T6_Tables.blackMakeUpCodes.length; i++) {
-                T4_T6_Tables.Entry entry = T4_T6_Tables.blackMakeUpCodes[i];
-                blackRunLengths.insert(entry.bitString, entry.value);
-            }
-            for (int i = 0; i < T4_T6_Tables.additionalMakeUpCodes.length; i++) {
-                T4_T6_Tables.Entry entry = T4_T6_Tables.additionalMakeUpCodes[i];
-                whiteRunLengths.insert(entry.bitString, entry.value);
-                blackRunLengths.insert(entry.bitString, entry.value);
-            }
-        } catch (HuffmanTreeException cannotHappen) {
-        }
-    }
-    
-    public static byte[] decompress1D(byte[] compressed, int width, int height) throws ImageReadException
{
-        BitInputStreamFlexible inputStream = new BitInputStreamFlexible(
-                new ByteArrayInputStream(compressed));
-        BitArrayOutputStream outputStream = new BitArrayOutputStream();
-        for (int y = 0; y < height; y++) {
-            int totalRunLength = 0;
-            boolean isWhite = true;
-            boolean isTerminated = false;
-            int rowLength;
-            for (rowLength = 0; rowLength < width || !isTerminated;) {
-                Integer runLength;
-                int color;
-                try {
-                    if (isWhite) {
-                        runLength = (Integer)whiteRunLengths.decode(inputStream);
-                        color = 0x00;
-                    } else {
-                        runLength = (Integer)blackRunLengths.decode(inputStream);
-                        color = 0x01;
-                    }
-                } catch (HuffmanTreeException huffmanException) {
-                    throw new ImageReadException("Decompression error", huffmanException);
-                }
-
-                totalRunLength += runLength.intValue();
-                rowLength += runLength.intValue();
-                if (runLength.intValue() <= 63) {
-                    for (int i = 0; i < totalRunLength; i++) {
-                        outputStream.writeBit(color);
-                    }
-                    totalRunLength = 0;
-                    isWhite = !isWhite;
-                    isTerminated = true;
-                } else {
-                    isTerminated = false;
-                }
-            }
-            
-            if (rowLength == width) {
-                inputStream.flushCache();
-                outputStream.flush();
-            } else if (rowLength > width) {
-                throw new ImageReadException("Unrecoverable row length error in image row
" + y);
-            }
-        }
-        return outputStream.toByteArray();
-    }
-}

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4_T6_Tables.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4_T6_Tables.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4_T6_Tables.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/common/itu_t4/T4_T6_Tables.java
Tue Dec 20 09:44:31 2011
@@ -189,7 +189,6 @@ class T4_T6_Tables {
         new Entry("010011010", Integer.valueOf(1600)),
         new Entry("011000", Integer.valueOf(1664)),
         new Entry("010011011", Integer.valueOf(1728)),
-        new Entry("000000000001", Integer.valueOf(0)) // EOL
     };
     
     public static final Entry[] blackMakeUpCodes = {
@@ -220,7 +219,6 @@ class T4_T6_Tables {
         new Entry("0000001011011", Integer.valueOf(1600)),
         new Entry("0000001100100", Integer.valueOf(1664)),
         new Entry("0000001100101", Integer.valueOf(1728)),
-        new Entry("00000000000", Integer.valueOf(0)) // EOL
     };
     
     public static final Entry[] additionalMakeUpCodes = {
@@ -238,4 +236,23 @@ class T4_T6_Tables {
         new Entry("000000011110", Integer.valueOf(2496)),
         new Entry("000000011111", Integer.valueOf(2560)),
     };
+    
+    public static final Entry EOL = new Entry("000000000001", Integer.valueOf(0));
+    public static final Entry EOL13 = new Entry("0000000000001", Integer.valueOf(0));
+    public static final Entry EOL14 = new Entry("00000000000001", Integer.valueOf(0));
+    public static final Entry EOL15 = new Entry("000000000000001", Integer.valueOf(0));
+    public static final Entry EOL16 = new Entry("0000000000000001", Integer.valueOf(0));
+    // FIXME: why are there EOLs with more than 16 bits?
+    public static final Entry EOL17 = new Entry("00000000000000001", Integer.valueOf(0));
+    public static final Entry EOL18 = new Entry("000000000000000001", Integer.valueOf(0));
+    public static final Entry EOL19 = new Entry("0000000000000000001", Integer.valueOf(0));
+    public static final Entry P = new Entry("0001", Integer.valueOf(0));
+    public static final Entry H = new Entry("001", Integer.valueOf(0));
+    public static final Entry V0 = new Entry("1", Integer.valueOf(0));
+    public static final Entry VR1 = new Entry("011", Integer.valueOf(0));
+    public static final Entry VR2 = new Entry("000011", Integer.valueOf(0));
+    public static final Entry VR3 = new Entry("0000011", Integer.valueOf(0));
+    public static final Entry VL1 = new Entry("010", Integer.valueOf(0));
+    public static final Entry VL2 = new Entry("000010", Integer.valueOf(0));
+    public static final Entry VL3 = new Entry("0000010", Integer.valueOf(0));
 }

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageData.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageData.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageData.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageData.java
Tue Dec 20 09:44:31 2011
@@ -53,15 +53,15 @@ public abstract class TiffImageData
             return false;
         }
 
-        public DataReader getDataReader(List entries,
+        public DataReader getDataReader(TiffDirectory directory,
                 PhotometricInterpreter photometricInterpreter,
                 int bitsPerPixel, int bitsPerSample[], int predictor,
                 int samplesPerPixel, int width, int height, int compression)
                 throws IOException, ImageReadException
         {
-            return new DataReaderTiled(photometricInterpreter, tileWidth,
-                    tileLength, bitsPerPixel, bitsPerSample, predictor,
-                    samplesPerPixel, width, height, compression, this);
+            return new DataReaderTiled(directory, photometricInterpreter,
+                    tileWidth, tileLength, bitsPerPixel, bitsPerSample,
+                    predictor, samplesPerPixel, width, height, compression, this);
         }
 
         //        public TiffElement[] getElements()
@@ -93,15 +93,15 @@ public abstract class TiffImageData
             return true;
         }
 
-        public DataReader getDataReader(List entries,
+        public DataReader getDataReader(TiffDirectory directory,
                 PhotometricInterpreter photometricInterpreter,
                 int bitsPerPixel, int bitsPerSample[], int predictor,
                 int samplesPerPixel, int width, int height, int compression)
                 throws IOException, ImageReadException
         {
-            return new DataReaderStrips(photometricInterpreter, bitsPerPixel,
-                    bitsPerSample, predictor, samplesPerPixel, width, height,
-                    compression, rowsPerStrip, this);
+            return new DataReaderStrips(directory, photometricInterpreter,
+                    bitsPerPixel, bitsPerSample, predictor, samplesPerPixel,
+                    width, height, compression, rowsPerStrip, this);
         }
 
         //        public TiffElement[] getElements()
@@ -117,7 +117,7 @@ public abstract class TiffImageData
 
     public abstract boolean stripsNotTiles();
 
-    public abstract DataReader getDataReader(List entries,
+    public abstract DataReader getDataReader(TiffDirectory directory,
             PhotometricInterpreter photometricInterpreter, int bitsPerPixel,
             int bitsPerSample[], int predictor, int samplesPerPixel, int width,
             int height, int compression) throws IOException, ImageReadException;

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
Tue Dec 20 09:44:31 2011
@@ -520,7 +520,7 @@ public class TiffImageParser extends Ima
 
         TiffImageData imageData = directory.getTiffImageData();
 
-        DataReader dataReader = imageData.getDataReader(entries,
+        DataReader dataReader = imageData.getDataReader(directory,
                 photometricInterpreter, bitsPerPixel, bitsPerSample, predictor,
                 samplesPerPixel, width, height, compression);
 

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
Tue Dec 20 09:44:31 2011
@@ -25,13 +25,16 @@ import org.apache.commons.sanselan.Image
 import org.apache.commons.sanselan.common.BinaryConstants;
 import org.apache.commons.sanselan.common.BitInputStream;
 import org.apache.commons.sanselan.common.PackBits;
-import org.apache.commons.sanselan.common.itu_t4.T4Compression;
+import org.apache.commons.sanselan.common.itu_t4.T4AndT6Compression;
 import org.apache.commons.sanselan.common.mylzw.MyLzwDecompressor;
+import org.apache.commons.sanselan.formats.tiff.TiffDirectory;
+import org.apache.commons.sanselan.formats.tiff.TiffField;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
 import org.apache.commons.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreter;
 
 public abstract class DataReader implements TiffConstants, BinaryConstants
 {
+    protected final TiffDirectory directory;
     protected final PhotometricInterpreter photometricInterpreter;
     protected final int bitsPerSample[];
     protected final int last[];
@@ -40,10 +43,12 @@ public abstract class DataReader impleme
     protected final int samplesPerPixel;
     protected final int width, height;
 
-    public DataReader(PhotometricInterpreter photometricInterpreter,
+    public DataReader(TiffDirectory directory,
+            PhotometricInterpreter photometricInterpreter,
             int bitsPerSample[], int predictor, int samplesPerPixel,
             int width, int height)
     {
+        this.directory = directory;
         this.photometricInterpreter = photometricInterpreter;
         this.bitsPerSample = bitsPerSample;
         this.samplesPerPixel = samplesPerPixel;
@@ -109,7 +114,39 @@ public abstract class DataReader impleme
             case TIFF_COMPRESSION_UNCOMPRESSED : // None;
                 return compressed;
             case TIFF_COMPRESSION_CCITT_1D : // CCITT Group 3 1-Dimensional Modified Huffman
run-length encoding.
-                return T4Compression.decompress1D(compressed, width, height);
+                return T4AndT6Compression.decompressModifiedHuffman(compressed, width, height);
+            case TIFF_COMPRESSION_CCITT_GROUP_3 :
+            {
+                int t4Options = 0;
+                TiffField field = directory.findField(TIFF_TAG_T4_OPTIONS);
+                if (field != null) {
+                    t4Options = field.getIntValue();
+                }
+                boolean is2D = (t4Options & 1) != 0;
+                boolean usesUncompressedMode = (t4Options & 2) != 0;
+                if (usesUncompressedMode) {
+                    throw new ImageReadException("T.4 compression with the uncompressed mode
extension is not yet supported");
+                }
+                boolean hasFillBitsBeforeEOL = (t4Options & 4) != 0;
+                if (is2D) {
+                    return T4AndT6Compression.decompressT4_2D(compressed, width, height,
hasFillBitsBeforeEOL);
+                } else {
+                    return T4AndT6Compression.decompressT4_1D(compressed, width, height,
hasFillBitsBeforeEOL);
+                }
+            }
+            case TIFF_COMPRESSION_CCITT_GROUP_4 :
+            {
+                int t6Options = 0;
+                TiffField field = directory.findField(TIFF_TAG_T6_OPTIONS);
+                if (field != null) {
+                    t6Options = field.getIntValue();
+                }
+                boolean usesUncompressedMode = (t6Options & 2) != 0;
+                if (usesUncompressedMode) {
+                    throw new ImageReadException("T.6 compression with the uncompressed mode
extension is not yet supported");
+                }
+                return T4AndT6Compression.decompressT6(compressed, width, height);
+            }
             case TIFF_COMPRESSION_LZW : // LZW
             {
                 InputStream is = new ByteArrayInputStream(compressed);

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderStrips.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderStrips.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderStrips.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderStrips.java
Tue Dec 20 09:44:31 2011
@@ -22,6 +22,7 @@ import java.io.IOException;
 
 import org.apache.commons.sanselan.ImageReadException;
 import org.apache.commons.sanselan.common.BitInputStream;
+import org.apache.commons.sanselan.formats.tiff.TiffDirectory;
 import org.apache.commons.sanselan.formats.tiff.TiffImageData;
 import org.apache.commons.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreter;
 
@@ -34,12 +35,13 @@ public final class DataReaderStrips exte
 
     private final TiffImageData.Strips imageData;
 
-    public DataReaderStrips(PhotometricInterpreter photometricInterpreter,
+    public DataReaderStrips(TiffDirectory directory,
+            PhotometricInterpreter photometricInterpreter,
             int bitsPerPixel, int bitsPerSample[], int predictor,
             int samplesPerPixel, int width, int height, int compression,
             int rowsPerStrip, TiffImageData.Strips imageData)
     {
-        super(photometricInterpreter, bitsPerSample, predictor, samplesPerPixel, width, height);
+        super(directory, photometricInterpreter, bitsPerSample, predictor, samplesPerPixel,
width, height);
 
         this.bitsPerPixel = bitsPerPixel;
         this.compression = compression;

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderTiled.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderTiled.java?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderTiled.java
(original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReaderTiled.java
Tue Dec 20 09:44:31 2011
@@ -22,6 +22,7 @@ import java.io.IOException;
 
 import org.apache.commons.sanselan.ImageReadException;
 import org.apache.commons.sanselan.common.BitInputStream;
+import org.apache.commons.sanselan.formats.tiff.TiffDirectory;
 import org.apache.commons.sanselan.formats.tiff.TiffImageData;
 import org.apache.commons.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreter;
 
@@ -37,12 +38,13 @@ public final class DataReaderTiled exten
 
     private final TiffImageData.Tiles imageData;
 
-    public DataReaderTiled(PhotometricInterpreter photometricInterpreter,
+    public DataReaderTiled(TiffDirectory directory,
+            PhotometricInterpreter photometricInterpreter,
             int tileWidth, int tileLength, int bitsPerPixel,
             int bitsPerSample[], int predictor, int samplesPerPixel, int width,
             int height, int compression, TiffImageData.Tiles imageData)
     {
-        super(photometricInterpreter, bitsPerSample, predictor, samplesPerPixel, width, height);
+        super(directory, photometricInterpreter, bitsPerSample, predictor, samplesPerPixel,
width, height);
 
         this.tileWidth = tileWidth;
         this.tileLength = tileLength;

Modified: commons/proper/sanselan/trunk/src/site/xdoc/formatsupport.xml
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/site/xdoc/formatsupport.xml?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/site/xdoc/formatsupport.xml (original)
+++ commons/proper/sanselan/trunk/src/site/xdoc/formatsupport.xml Tue Dec 20 09:44:31 2011
@@ -158,10 +158,10 @@ limitations under the License.
     <td>TIFF</td><td>yes</td><td>yes</td>
     <td>
         Supported through version 6.0. TIFFs is a open-ended container format, so it's not
-        possible to support every possibly variation. JPEG-compressed TIFFs are not supported.
+        possible to support every possibly variation.
         Supports Bi-Level, Palette/Indexed, RGB, CMYK, YCbCr, CIELab and LOGLUV images.
-        Supports LZW, CCITT/Huffman and Packbits/RLE compression. Notably missing other forms
-        of compression, though, including CCITT 4 and 6 bilevel and JPEG.
+        Supports LZW, CCITT Modified Huffman/T.4/T.6 and Packbits/RLE compression.
+        Notably missing other forms of compression, though, including JPEG.
         Supports Tiled images.
     </td>
     <td>

Added: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 1D fill.tiff
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon%20Scientific%20DS6639%20-%20DSC_0307%20-%20small%20CCITT%20T.4%201D%20fill.tiff?rev=1221170&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 1D fill.tiff
------------------------------------------------------------------------------
    svn:mime-type = image/tiff

Added: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 1D no fill.tiff
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon%20Scientific%20DS6639%20-%20DSC_0307%20-%20small%20CCITT%20T.4%201D%20no%20fill.tiff?rev=1221170&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 1D no fill.tiff
------------------------------------------------------------------------------
    svn:mime-type = image/tiff

Added: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 2D fill.tiff
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon%20Scientific%20DS6639%20-%20DSC_0307%20-%20small%20CCITT%20T.4%202D%20fill.tiff?rev=1221170&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 2D fill.tiff
------------------------------------------------------------------------------
    svn:mime-type = image/tiff

Added: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 2D no fill.tiff
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon%20Scientific%20DS6639%20-%20DSC_0307%20-%20small%20CCITT%20T.4%202D%20no%20fill.tiff?rev=1221170&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.4 2D no fill.tiff
------------------------------------------------------------------------------
    svn:mime-type = image/tiff

Added: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.6.tiff
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon%20Scientific%20DS6639%20-%20DSC_0307%20-%20small%20CCITT%20T.6.tiff?rev=1221170&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/Oregon Scientific DS6639
- DSC_0307 - small CCITT T.6.tiff
------------------------------------------------------------------------------
    svn:mime-type = image/tiff

Modified: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt?rev=1221170&r1=1221169&r2=1221170&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt (original)
+++ commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt Tue Dec 20 09:44:31
2011
@@ -7,3 +7,8 @@ in compression=2 format.
 
 It was generated from a similarly blank PDF using Ghostscript:
 gs -q -sDEVICE=tiffcrle -r204x98 -dBATCH -dPDFFitPage -dNOPAUSE -sOutputFile=1pagefax.tif
1pagefax.pdf
+
+Oregon Scientific DS6639 - DSC_0307 - small
+-------------------------------------------
+Converted from ../../pbm/1/Oregon Scientific DS6639 - DSC_0307 - small.pbm
+using ppm2tiff with various T.4 and T.6 compression options.



Mime
View raw message