001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: TIFFLZWDecoder.java 496559 2007-01-16 01:10:29Z cam $ */
019:
020: package org.apache.xmlgraphics.image.codec.tiff;
021:
022: /**
023: * A class for performing LZW decoding.
024: *
025: *
026: */
027: public class TIFFLZWDecoder {
028:
029: byte[][] stringTable;
030: byte[] data = null;
031: byte[] uncompData;
032: int tableIndex, bitsToGet = 9;
033: int bytePointer, bitPointer;
034: int dstIndex;
035: int w, h;
036: int predictor, samplesPerPixel;
037: int nextData = 0;
038: int nextBits = 0;
039:
040: int[] andTable = { 511, 1023, 2047, 4095 };
041:
042: public TIFFLZWDecoder(int w, int predictor, int samplesPerPixel) {
043: this .w = w;
044: this .predictor = predictor;
045: this .samplesPerPixel = samplesPerPixel;
046: }
047:
048: /**
049: * Method to decode LZW compressed data.
050: *
051: * @param data The compressed data.
052: * @param uncompData Array to return the uncompressed data in.
053: * @param h The number of rows the compressed data contains.
054: */
055: public byte[] decode(byte[] data, byte[] uncompData, int h) {
056:
057: if (data[0] == (byte) 0x00 && data[1] == (byte) 0x01) {
058: throw new UnsupportedOperationException("TIFFLZWDecoder0");
059: }
060:
061: initializeStringTable();
062:
063: this .data = data;
064: this .h = h;
065: this .uncompData = uncompData;
066:
067: // Initialize pointers
068: bytePointer = 0;
069: bitPointer = 0;
070: dstIndex = 0;
071:
072: nextData = 0;
073: nextBits = 0;
074:
075: int code, oldCode = 0;
076: byte[] string;
077:
078: while ((code = getNextCode()) != 257
079: && dstIndex != uncompData.length) {
080:
081: if (code == 256) {
082:
083: initializeStringTable();
084: code = getNextCode();
085:
086: if (code == 257) {
087: break;
088: }
089:
090: writeString(stringTable[code]);
091: oldCode = code;
092:
093: } else {
094:
095: if (code < tableIndex) {
096:
097: string = stringTable[code];
098:
099: writeString(string);
100: addStringToTable(stringTable[oldCode], string[0]);
101: oldCode = code;
102:
103: } else {
104:
105: string = stringTable[oldCode];
106: string = composeString(string, string[0]);
107: writeString(string);
108: addStringToTable(string);
109: oldCode = code;
110: }
111:
112: }
113:
114: }
115:
116: // Horizontal Differencing Predictor
117: if (predictor == 2) {
118:
119: int count;
120: for (int j = 0; j < h; j++) {
121:
122: count = samplesPerPixel * (j * w + 1);
123:
124: for (int i = samplesPerPixel; i < w * samplesPerPixel; i++) {
125:
126: uncompData[count] += uncompData[count
127: - samplesPerPixel];
128: count++;
129: }
130: }
131: }
132:
133: return uncompData;
134: }
135:
136: /**
137: * Initialize the string table.
138: */
139: public void initializeStringTable() {
140:
141: stringTable = new byte[4096][];
142:
143: for (int i = 0; i < 256; i++) {
144: stringTable[i] = new byte[1];
145: stringTable[i][0] = (byte) i;
146: }
147:
148: tableIndex = 258;
149: bitsToGet = 9;
150: }
151:
152: /**
153: * Write out the string just uncompressed.
154: */
155: public void writeString(byte[] string) {
156:
157: for (int i = 0; i < string.length; i++) {
158: uncompData[dstIndex++] = string[i];
159: }
160: }
161:
162: /**
163: * Add a new string to the string table.
164: */
165: public void addStringToTable(byte[] oldString, byte newString) {
166: int length = oldString.length;
167: byte[] string = new byte[length + 1];
168: System.arraycopy(oldString, 0, string, 0, length);
169: string[length] = newString;
170:
171: // Add this new String to the table
172: stringTable[tableIndex++] = string;
173:
174: if (tableIndex == 511) {
175: bitsToGet = 10;
176: } else if (tableIndex == 1023) {
177: bitsToGet = 11;
178: } else if (tableIndex == 2047) {
179: bitsToGet = 12;
180: }
181: }
182:
183: /**
184: * Add a new string to the string table.
185: */
186: public void addStringToTable(byte[] string) {
187:
188: // Add this new String to the table
189: stringTable[tableIndex++] = string;
190:
191: if (tableIndex == 511) {
192: bitsToGet = 10;
193: } else if (tableIndex == 1023) {
194: bitsToGet = 11;
195: } else if (tableIndex == 2047) {
196: bitsToGet = 12;
197: }
198: }
199:
200: /**
201: * Append <code>newString</code> to the end of <code>oldString</code>.
202: */
203: public byte[] composeString(byte[] oldString, byte newString) {
204: int length = oldString.length;
205: byte[] string = new byte[length + 1];
206: System.arraycopy(oldString, 0, string, 0, length);
207: string[length] = newString;
208:
209: return string;
210: }
211:
212: // Returns the next 9, 10, 11 or 12 bits
213: public int getNextCode() {
214: // Attempt to get the next code. The exception is caught to make
215: // this robust to cases wherein the EndOfInformation code has been
216: // omitted from a strip. Examples of such cases have been observed
217: // in practice.
218: try {
219: nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
220: nextBits += 8;
221:
222: if (nextBits < bitsToGet) {
223: nextData = (nextData << 8)
224: | (data[bytePointer++] & 0xff);
225: nextBits += 8;
226: }
227:
228: int code = (nextData >> (nextBits - bitsToGet))
229: & andTable[bitsToGet - 9];
230: nextBits -= bitsToGet;
231:
232: return code;
233: } catch (ArrayIndexOutOfBoundsException e) {
234: // Strip not terminated as expected: return EndOfInformation code.
235: return 257;
236: }
237: }
238: }
|