Author: damjan
Date: Sat Dec 10 10:14:26 2011
New Revision: 1212757

URL: http://svn.apache.org/viewvc?rev=1212757&view=rev
Log:
Add support for TIFF files with compression=2,
(CCITT Group 3 1-Dimensional Modified Huffman
run length encoding), and a sample image
that tests this. CCITT is now the ITU,
so the naming reflects this.

Jira issue key: SANSELAN-48


Added:
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitArrayOutputStream.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTree.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTreeException.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4Compression.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4_T6_Tables.java
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/1pagefax.tif   
(with props)
    commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt
Modified:
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReader.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderStrips.java
    
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderTiled.java

Added: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitArrayOutputStream.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitArrayOutputStream.java?rev=1212757&view=auto
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitArrayOutputStream.java
 (added)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitArrayOutputStream.java
 Sat Dec 10 10:14:26 2011
@@ -0,0 +1,82 @@
+/*
+ * 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.sanselan.common;
+
+public class BitArrayOutputStream {
+    private byte[] buffer;
+    private int bytesWritten = 0;
+    private int cache = 0;
+    private int cacheMask = 0x80;
+
+    public BitArrayOutputStream() {
+        buffer = new byte[16];
+    }
+
+    public BitArrayOutputStream(int size) {
+        buffer = new byte[size];
+    }
+
+    public int size() {
+        return bytesWritten;
+    }
+
+    public byte[] toByteArray() {
+        flush();
+        if (bytesWritten == buffer.length) {
+            return buffer;
+        }
+        byte[] out = new byte[bytesWritten];
+        System.arraycopy(buffer, 0, out, 0, bytesWritten);
+        return out;
+    }
+
+    public void close() {
+        flush();
+    }
+
+    public void flush() {
+        if (cacheMask != 0x80) {
+            writeByte(cache);
+            cache = 0;
+            cacheMask = 0x80;
+        }
+    }
+
+    public void write(int b) {
+        flush();
+        writeByte(b);
+    }
+
+    public void writeBit(int bit) {
+        if (bit != 0) {
+            cache |= cacheMask;
+        }
+        cacheMask >>>= 1;
+        if (cacheMask == 0) {
+            flush();
+        }
+    }
+
+    private void writeByte(int b) {
+        if (bytesWritten >= buffer.length) {
+            byte[] bigger = new byte[buffer.length * 2];
+            System.arraycopy(buffer, 0, bigger, 0, bytesWritten);
+            buffer = bigger;
+        }
+        buffer[bytesWritten++] = (byte)b;
+    }
+}

Modified: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java?rev=1212757&r1=1212756&r2=1212757&view=diff
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java
 (original)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java
 Sat Dec 10 10:14:26 2011
@@ -73,9 +73,9 @@ public class BitInputStreamFlexible exte
                 cache = is.read();
                 if (cache < 0)
                     throw new IOException("couldn't read bits");
-                System.out.println("cache 1: " + cache + " ("
-                        + Integer.toHexString(cache) + ", "
-                        + Integer.toBinaryString(cache) + ")");
+//                System.out.println("cache 1: " + cache + " ("
+//                        + Integer.toHexString(cache) + ", "
+//                        + Integer.toBinaryString(cache) + ")");
                 bytesRead++;
                 result = (result << 8) | (0xff & cache);
                 count -= 8;
@@ -85,9 +85,9 @@ public class BitInputStreamFlexible exte
                 cache = is.read();
                 if (cache < 0)
                     throw new IOException("couldn't read bits");
-                System.out.println("cache 2: " + cache + " ("
-                        + Integer.toHexString(cache) + ", "
-                        + Integer.toBinaryString(cache) + ")");
+//                System.out.println("cache 2: " + cache + " ("
+//                        + Integer.toHexString(cache) + ", "
+//                        + Integer.toBinaryString(cache) + ")");
                 bytesRead++;
                 cacheBitsRemaining = 8 - count;
                 result = (result << count)

Added: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTree.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTree.java?rev=1212757&view=auto
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTree.java
 (added)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTree.java
 Sat Dec 10 10:14:26 2011
@@ -0,0 +1,89 @@
+/*
+ * 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.sanselan.common.itu_t4;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.sanselan.common.BitInputStreamFlexible;
+
+/**
+ * A Huffman tree implemented as 1 array for high locality of reference.
+ */
+public class HuffmanTree {
+    private static class Node {
+        boolean isEmpty = true;
+        Object value = null;
+    }
+    private ArrayList nodes = new ArrayList();
+
+    public final void insert(String pattern, Object value) throws 
HuffmanTreeException {
+        int position = 0;
+        Node node = growAndGetNode(position);
+        if (node.value != null) {
+            throw new HuffmanTreeException("Can't add child to a leaf");
+        }
+        for(int patternPosition = 0; patternPosition < pattern.length(); 
patternPosition++) {
+            char nextChar = pattern.charAt(patternPosition);
+            if (nextChar == '0') {
+                position = (position << 1) + 1;
+            } else {
+                position = (position + 1) << 1;
+            }
+            node = growAndGetNode(position);
+            if (node.value != null) {
+                throw new HuffmanTreeException("Can't add child to a leaf");
+            }
+        }
+        node.value = value;
+    }
+    
+    private Node growAndGetNode(int position) {
+        while (position >= nodes.size()) {
+            nodes.add(new Node());
+        }
+        Node node = (Node) nodes.get(position);
+        node.isEmpty = false;
+        return node;
+    }
+    
+    public final Object decode(BitInputStreamFlexible bitStream) throws 
HuffmanTreeException {
+        int position = 0;
+        Node node = (Node) nodes.get(0);
+        while (node.value == null) {
+            int nextBit;
+            try {
+                nextBit = bitStream.readBits(1);
+            } catch (IOException ioEx) {
+                throw new HuffmanTreeException("Error reading stream for 
huffman tree", ioEx);
+            }
+            if (nextBit == 0) {
+                position = (position << 1) + 1;
+            } else {
+                position = (position + 1) << 1;
+            }
+            if (position >= nodes.size()) {
+                throw new HuffmanTreeException("Invalid bit pattern");
+            }
+            node = (Node) nodes.get(position);
+            if (node.isEmpty) {
+                throw new HuffmanTreeException("Invalid bit pattern");
+            }
+        }
+        return node.value;
+    }
+}

Added: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTreeException.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTreeException.java?rev=1212757&view=auto
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTreeException.java
 (added)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/HuffmanTreeException.java
 Sat Dec 10 10:14:26 2011
@@ -0,0 +1,29 @@
+/*
+ * 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.sanselan.common.itu_t4;
+
+public class HuffmanTreeException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public HuffmanTreeException(String message) {
+        super(message);
+    }
+    
+    public HuffmanTreeException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+}

Added: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4Compression.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4Compression.java?rev=1212757&view=auto
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4Compression.java
 (added)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4Compression.java
 Sat Dec 10 10:14:26 2011
@@ -0,0 +1,104 @@
+/*
+ * 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.sanselan.common.itu_t4;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.BitArrayOutputStream;
+import org.apache.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();
+    }
+}

Added: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4_T6_Tables.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4_T6_Tables.java?rev=1212757&view=auto
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4_T6_Tables.java
 (added)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/common/itu_t4/T4_T6_Tables.java
 Sat Dec 10 10:14:26 2011
@@ -0,0 +1,241 @@
+/*
+ * 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.sanselan.common.itu_t4;
+
+public class T4_T6_Tables {
+    public static class Entry {
+        String bitString;
+        Integer value;
+        
+        public Entry(String bitString, Integer value) {
+            this.bitString = bitString;
+            this.value = value;
+        }
+    }
+    
+    public static final Entry[] whiteTerminatingCodes = {
+        new Entry("00110101", Integer.valueOf(0)),
+        new Entry("000111", Integer.valueOf(1)),
+        new Entry("0111", Integer.valueOf(2)),
+        new Entry("1000", Integer.valueOf(3)),
+        new Entry("1011", Integer.valueOf(4)),
+        new Entry("1100", Integer.valueOf(5)),
+        new Entry("1110", Integer.valueOf(6)),
+        new Entry("1111", Integer.valueOf(7)),
+        new Entry("10011", Integer.valueOf(8)),
+        new Entry("10100", Integer.valueOf(9)),
+        new Entry("00111", Integer.valueOf(10)),
+        new Entry("01000", Integer.valueOf(11)),
+        new Entry("001000", Integer.valueOf(12)),
+        new Entry("000011", Integer.valueOf(13)),
+        new Entry("110100", Integer.valueOf(14)),
+        new Entry("110101", Integer.valueOf(15)),
+        new Entry("101010", Integer.valueOf(16)),
+        new Entry("101011", Integer.valueOf(17)),
+        new Entry("0100111", Integer.valueOf(18)),
+        new Entry("0001100", Integer.valueOf(19)),
+        new Entry("0001000", Integer.valueOf(20)),
+        new Entry("0010111", Integer.valueOf(21)),
+        new Entry("0000011", Integer.valueOf(22)),
+        new Entry("0000100", Integer.valueOf(23)),
+        new Entry("0101000", Integer.valueOf(24)),
+        new Entry("0101011", Integer.valueOf(25)),
+        new Entry("0010011", Integer.valueOf(26)),
+        new Entry("0100100", Integer.valueOf(27)),
+        new Entry("0011000", Integer.valueOf(28)),
+        new Entry("00000010", Integer.valueOf(29)),
+        new Entry("00000011", Integer.valueOf(30)),
+        new Entry("00011010", Integer.valueOf(31)),
+        new Entry("00011011", Integer.valueOf(32)),
+        new Entry("00010010", Integer.valueOf(33)),
+        new Entry("00010011", Integer.valueOf(34)),
+        new Entry("00010100", Integer.valueOf(35)),
+        new Entry("00010101", Integer.valueOf(36)),
+        new Entry("00010110", Integer.valueOf(37)),
+        new Entry("00010111", Integer.valueOf(38)),
+        new Entry("00101000", Integer.valueOf(39)),
+        new Entry("00101001", Integer.valueOf(40)),
+        new Entry("00101010", Integer.valueOf(41)),
+        new Entry("00101011", Integer.valueOf(42)),
+        new Entry("00101100", Integer.valueOf(43)),
+        new Entry("00101101", Integer.valueOf(44)),
+        new Entry("00000100", Integer.valueOf(45)),
+        new Entry("00000101", Integer.valueOf(46)),
+        new Entry("00001010", Integer.valueOf(47)),
+        new Entry("00001011", Integer.valueOf(48)),
+        new Entry("01010010", Integer.valueOf(49)),
+        new Entry("01010011", Integer.valueOf(50)),
+        new Entry("01010100", Integer.valueOf(51)),
+        new Entry("01010101", Integer.valueOf(52)),
+        new Entry("00100100", Integer.valueOf(53)),
+        new Entry("00100101", Integer.valueOf(54)),
+        new Entry("01011000", Integer.valueOf(55)),
+        new Entry("01011001", Integer.valueOf(56)),
+        new Entry("01011010", Integer.valueOf(57)),
+        new Entry("01011011", Integer.valueOf(58)),
+        new Entry("01001010", Integer.valueOf(59)),
+        new Entry("01001011", Integer.valueOf(60)),
+        new Entry("00110010", Integer.valueOf(61)),
+        new Entry("00110011", Integer.valueOf(62)),
+        new Entry("00110100", Integer.valueOf(63)),
+    };
+    
+    public static final Entry[] blackTerminatingCodes = {
+        new Entry("0000110111", Integer.valueOf(0)),
+        new Entry("010", Integer.valueOf(1)),
+        new Entry("11", Integer.valueOf(2)),
+        new Entry("10", Integer.valueOf(3)),
+        new Entry("011", Integer.valueOf(4)),
+        new Entry("0011", Integer.valueOf(5)),
+        new Entry("0010", Integer.valueOf(6)),
+        new Entry("00011", Integer.valueOf(7)),
+        new Entry("000101", Integer.valueOf(8)),
+        new Entry("000100", Integer.valueOf(9)),
+        new Entry("0000100", Integer.valueOf(10)),
+        new Entry("0000101", Integer.valueOf(11)),
+        new Entry("0000111", Integer.valueOf(12)),
+        new Entry("00000100", Integer.valueOf(13)),
+        new Entry("00000111", Integer.valueOf(14)),
+        new Entry("000011000", Integer.valueOf(15)),
+        new Entry("0000010111", Integer.valueOf(16)),
+        new Entry("0000011000", Integer.valueOf(17)),
+        new Entry("0000001000", Integer.valueOf(18)),
+        new Entry("00001100111", Integer.valueOf(19)),
+        new Entry("00001101000", Integer.valueOf(20)),
+        new Entry("00001101100", Integer.valueOf(21)),
+        new Entry("00000110111", Integer.valueOf(22)),
+        new Entry("00000101000", Integer.valueOf(23)),
+        new Entry("00000010111", Integer.valueOf(24)),
+        new Entry("00000011000", Integer.valueOf(25)),
+        new Entry("000011001010", Integer.valueOf(26)),
+        new Entry("000011001011", Integer.valueOf(27)),
+        new Entry("000011001100", Integer.valueOf(28)),
+        new Entry("000011001101", Integer.valueOf(29)),
+        new Entry("000001101000", Integer.valueOf(30)),
+        new Entry("000001101001", Integer.valueOf(31)),
+        new Entry("000001101010", Integer.valueOf(32)),
+        new Entry("000001101011", Integer.valueOf(33)),
+        new Entry("000011010010", Integer.valueOf(34)),
+        new Entry("000011010011", Integer.valueOf(35)),
+        new Entry("000011010100", Integer.valueOf(36)),
+        new Entry("000011010101", Integer.valueOf(37)),
+        new Entry("000011010110", Integer.valueOf(38)),
+        new Entry("000011010111", Integer.valueOf(39)),
+        new Entry("000001101100", Integer.valueOf(40)),
+        new Entry("000001101101", Integer.valueOf(41)),
+        new Entry("000011011010", Integer.valueOf(42)),
+        new Entry("000011011011", Integer.valueOf(43)),
+        new Entry("000001010100", Integer.valueOf(44)),
+        new Entry("000001010101", Integer.valueOf(45)),
+        new Entry("000001010110", Integer.valueOf(46)),
+        new Entry("000001010111", Integer.valueOf(47)),
+        new Entry("000001100100", Integer.valueOf(48)),
+        new Entry("000001100101", Integer.valueOf(49)),
+        new Entry("000001010010", Integer.valueOf(50)),
+        new Entry("000001010011", Integer.valueOf(51)),
+        new Entry("000000100100", Integer.valueOf(52)),
+        new Entry("000000110111", Integer.valueOf(53)),
+        new Entry("000000111000", Integer.valueOf(54)),
+        new Entry("000000100111", Integer.valueOf(55)),
+        new Entry("000000101000", Integer.valueOf(56)),
+        new Entry("000001011000", Integer.valueOf(57)),
+        new Entry("000001011001", Integer.valueOf(58)),
+        new Entry("000000101011", Integer.valueOf(59)),
+        new Entry("000000101100", Integer.valueOf(60)),
+        new Entry("000001011010", Integer.valueOf(61)),
+        new Entry("000001100110", Integer.valueOf(62)),
+        new Entry("000001100111", Integer.valueOf(63)),
+    };
+    
+    public static final Entry[] whiteMakeUpCodes = {
+        new Entry("11011", Integer.valueOf(64)),
+        new Entry("10010", Integer.valueOf(128)),
+        new Entry("010111", Integer.valueOf(192)),
+        new Entry("0110111", Integer.valueOf(256)),
+        new Entry("00110110", Integer.valueOf(320)),
+        new Entry("00110111", Integer.valueOf(384)),
+        new Entry("01100100", Integer.valueOf(448)),
+        new Entry("01100101", Integer.valueOf(512)),
+        new Entry("01101000", Integer.valueOf(576)),
+        new Entry("01100111", Integer.valueOf(640)),
+        new Entry("011001100", Integer.valueOf(704)),
+        new Entry("011001101", Integer.valueOf(768)),
+        new Entry("011010010", Integer.valueOf(832)),
+        new Entry("011010011", Integer.valueOf(896)),
+        new Entry("011010100", Integer.valueOf(960)),
+        new Entry("011010101", Integer.valueOf(1024)),
+        new Entry("011010110", Integer.valueOf(1088)),
+        new Entry("011010111", Integer.valueOf(1152)),
+        new Entry("011011000", Integer.valueOf(1216)),
+        new Entry("011011001", Integer.valueOf(1280)),
+        new Entry("011011010", Integer.valueOf(1344)),
+        new Entry("011011011", Integer.valueOf(1408)),
+        new Entry("010011000", Integer.valueOf(1472)),
+        new Entry("010011001", Integer.valueOf(1536)),
+        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 = {
+        new Entry("0000001111", Integer.valueOf(64)),
+        new Entry("000011001000", Integer.valueOf(128)),
+        new Entry("000011001001", Integer.valueOf(192)),
+        new Entry("000001011011", Integer.valueOf(256)),
+        new Entry("000000110011", Integer.valueOf(320)),
+        new Entry("000000110100", Integer.valueOf(384)),
+        new Entry("000000110101", Integer.valueOf(448)),
+        new Entry("0000001101100", Integer.valueOf(512)),
+        new Entry("0000001101101", Integer.valueOf(576)),
+        new Entry("0000001001010", Integer.valueOf(640)),
+        new Entry("0000001001011", Integer.valueOf(704)),
+        new Entry("0000001001100", Integer.valueOf(768)),
+        new Entry("0000001001101", Integer.valueOf(832)),
+        new Entry("0000001110010", Integer.valueOf(896)),
+        new Entry("0000001110011", Integer.valueOf(960)),
+        new Entry("0000001110100", Integer.valueOf(1024)),
+        new Entry("0000001110101", Integer.valueOf(1088)),
+        new Entry("0000001110110", Integer.valueOf(1152)),
+        new Entry("0000001110111", Integer.valueOf(1216)),
+        new Entry("0000001010010", Integer.valueOf(1280)),
+        new Entry("0000001010011", Integer.valueOf(1344)),
+        new Entry("0000001010100", Integer.valueOf(1408)),
+        new Entry("0000001010101", Integer.valueOf(1472)),
+        new Entry("0000001011010", Integer.valueOf(1536)),
+        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 = {
+        new Entry("00000001000", Integer.valueOf(1792)),
+        new Entry("00000001100", Integer.valueOf(1856)),
+        new Entry("00000001101", Integer.valueOf(1920)),
+        new Entry("000000010010", Integer.valueOf(1984)),
+        new Entry("000000010011", Integer.valueOf(2048)),
+        new Entry("000000010100", Integer.valueOf(2112)),
+        new Entry("000000010101", Integer.valueOf(2176)),
+        new Entry("000000010110", Integer.valueOf(2240)),
+        new Entry("000000010111", Integer.valueOf(2304)),
+        new Entry("000000011100", Integer.valueOf(2368)),
+        new Entry("000000011101", Integer.valueOf(2432)),
+        new Entry("000000011110", Integer.valueOf(2496)),
+        new Entry("000000011111", Integer.valueOf(2560)),
+    };
+}

Modified: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReader.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReader.java?rev=1212757&r1=1212756&r2=1212757&view=diff
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReader.java
 (original)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReader.java
 Sat Dec 10 10:14:26 2011
@@ -25,6 +25,7 @@ import org.apache.sanselan.ImageReadExce
 import org.apache.sanselan.common.BinaryConstants;
 import org.apache.sanselan.common.BitInputStream;
 import org.apache.sanselan.common.PackBits;
+import org.apache.sanselan.common.itu_t4.T4Compression;
 import org.apache.sanselan.common.mylzw.MyLZWDecompressor;
 import org.apache.sanselan.formats.tiff.constants.TiffConstants;
 import 
org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreter;
@@ -37,14 +38,18 @@ public abstract class DataReader impleme
 
     protected final int predictor;
     protected final int samplesPerPixel;
+    protected final int width, height;
 
     public DataReader(PhotometricInterpreter photometricInterpreter,
-            int bitsPerSample[], int predictor, int samplesPerPixel)
+            int bitsPerSample[], int predictor, int samplesPerPixel,
+            int width, int height)
     {
         this.photometricInterpreter = photometricInterpreter;
         this.bitsPerSample = bitsPerSample;
         this.samplesPerPixel = samplesPerPixel;
         this.predictor = predictor;
+        this.width = width;
+        this.height = height;
         last = new int[samplesPerPixel];
     }
 
@@ -101,11 +106,10 @@ public abstract class DataReader impleme
     {
         switch (compression)
         {
-            case 1 : // None;
+            case TIFF_COMPRESSION_UNCOMPRESSED : // None;
                 return compressed;
-            case 2 : // CCITT Group 3 1-Dimensional Modified Huffman 
run-length encoding.
-                throw new ImageReadException("Tiff: unknown compression: "
-                        + compression);
+            case TIFF_COMPRESSION_CCITT_1D : // CCITT Group 3 1-Dimensional 
Modified Huffman run-length encoding.
+                return T4Compression.decompress1D(compressed, width, height);
             case TIFF_COMPRESSION_LZW : // LZW
             {
                 InputStream is = new ByteArrayInputStream(compressed);
@@ -132,7 +136,7 @@ public abstract class DataReader impleme
             }
 
             default :
-                throw new ImageReadException("Tiff: unknown compression: "
+                throw new ImageReadException("Tiff: unknown/unsupported 
compression: "
                         + compression);
         }
     }

Modified: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderStrips.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderStrips.java?rev=1212757&r1=1212756&r2=1212757&view=diff
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderStrips.java
 (original)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderStrips.java
 Sat Dec 10 10:14:26 2011
@@ -29,7 +29,6 @@ public final class DataReaderStrips exte
 {
 
     private final int bitsPerPixel;
-    private final int width, height;
     private final int compression;
     private final int rowsPerStrip;
 
@@ -40,11 +39,9 @@ public final class DataReaderStrips exte
             int samplesPerPixel, int width, int height, int compression,
             int rowsPerStrip, TiffImageData.Strips imageData)
     {
-        super(photometricInterpreter, bitsPerSample, predictor, 
samplesPerPixel);
+        super(photometricInterpreter, bitsPerSample, predictor, 
samplesPerPixel, width, height);
 
         this.bitsPerPixel = bitsPerPixel;
-        this.width = width;
-        this.height = height;
         this.compression = compression;
         this.rowsPerStrip = rowsPerStrip;
         this.imageData = imageData;

Modified: 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderTiled.java
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderTiled.java?rev=1212757&r1=1212756&r2=1212757&view=diff
==============================================================================
--- 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderTiled.java
 (original)
+++ 
commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/datareaders/DataReaderTiled.java
 Sat Dec 10 10:14:26 2011
@@ -33,8 +33,6 @@ public final class DataReaderTiled exten
 
     private final int bitsPerPixel;
 
-    private final int width, height;
-
     private final int compression;
 
     private final TiffImageData.Tiles imageData;
@@ -44,14 +42,12 @@ public final class DataReaderTiled exten
             int bitsPerSample[], int predictor, int samplesPerPixel, int width,
             int height, int compression, TiffImageData.Tiles imageData)
     {
-        super(photometricInterpreter, bitsPerSample, predictor, 
samplesPerPixel);
+        super(photometricInterpreter, bitsPerSample, predictor, 
samplesPerPixel, width, height);
 
         this.tileWidth = tileWidth;
         this.tileLength = tileLength;
 
         this.bitsPerPixel = bitsPerPixel;
-        this.width = width;
-        this.height = height;
         this.compression = compression;
 
         this.imageData = imageData;

Added: commons/proper/sanselan/trunk/src/test/data/images/tiff/3/1pagefax.tif
URL: 
http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/data/images/tiff/3/1pagefax.tif?rev=1212757&view=auto
==============================================================================
Binary file - no diff available.

Propchange: 
commons/proper/sanselan/trunk/src/test/data/images/tiff/3/1pagefax.tif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: 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=1212757&view=auto
==============================================================================
--- commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt (added)
+++ commons/proper/sanselan/trunk/src/test/data/images/tiff/3/info.txt Sat Dec 
10 10:14:26 2011
@@ -0,0 +1,9 @@
+1pagefax.tiff
+-------------
+Contributed to the project by Damjan Jovanovic
+
+This is a completely blank standard resolution fax,
+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


Reply via email to