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