001: /*
002: * $RCSfile: TIFFLZWDecoder.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:55:40 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.codecimpl;
013:
014: /**
015: * A class for performing LZW decoding.
016: *
017: * @since FCS
018: *
019: */
020: public class TIFFLZWDecoder {
021:
022: byte stringTable[][];
023: byte data[] = null, uncompData[];
024: int tableIndex, bitsToGet = 9;
025: int bytePointer, bitPointer;
026: int dstIndex;
027: int w, h;
028: int predictor, samplesPerPixel;
029: int nextData = 0;
030: int nextBits = 0;
031:
032: int andTable[] = { 511, 1023, 2047, 4095 };
033:
034: public TIFFLZWDecoder(int w, int predictor, int samplesPerPixel) {
035: this .w = w;
036: this .predictor = predictor;
037: this .samplesPerPixel = samplesPerPixel;
038: }
039:
040: /**
041: * Method to decode LZW compressed data.
042: *
043: * @param data The compressed data.
044: * @param uncompData Array to return the uncompressed data in.
045: * @param h The number of rows the compressed data contains.
046: */
047: public byte[] decode(byte data[], byte uncompData[], int h) {
048:
049: if (data[0] == (byte) 0x00 && data[1] == (byte) 0x01) {
050: throw new UnsupportedOperationException(JaiI18N
051: .getString("TIFFLZWDecoder0"));
052: }
053:
054: initializeStringTable();
055:
056: this .data = data;
057: this .h = h;
058: this .uncompData = uncompData;
059:
060: // Initialize pointers
061: bytePointer = 0;
062: bitPointer = 0;
063: dstIndex = 0;
064:
065: nextData = 0;
066: nextBits = 0;
067:
068: int code, oldCode = 0;
069: byte string[];
070:
071: int uncompDataLength = uncompData.length;
072: while (((code = getNextCode()) != 257)
073: && dstIndex < uncompDataLength) {
074:
075: if (code == 256) {
076:
077: initializeStringTable();
078: code = getNextCode();
079:
080: if (code == 257) {
081: break;
082: }
083:
084: writeString(stringTable[code]);
085: oldCode = code;
086:
087: } else {
088:
089: if (code < tableIndex) {
090:
091: string = stringTable[code];
092:
093: writeString(string);
094: addStringToTable(stringTable[oldCode], string[0]);
095: oldCode = code;
096:
097: } else {
098:
099: string = stringTable[oldCode];
100: string = composeString(string, string[0]);
101: writeString(string);
102: addStringToTable(string);
103: oldCode = code;
104: }
105:
106: }
107:
108: }
109:
110: // Horizontal Differencing Predictor
111: if (predictor == 2) {
112:
113: int count;
114: for (int j = 0; j < h; j++) {
115:
116: count = samplesPerPixel * (j * w + 1);
117:
118: for (int i = samplesPerPixel; i < w * samplesPerPixel; i++) {
119:
120: uncompData[count] += uncompData[count
121: - samplesPerPixel];
122: count++;
123: }
124: }
125: }
126:
127: return uncompData;
128: }
129:
130: /**
131: * Initialize the string table.
132: */
133: public void initializeStringTable() {
134:
135: stringTable = new byte[4096][];
136:
137: for (int i = 0; i < 256; i++) {
138: stringTable[i] = new byte[1];
139: stringTable[i][0] = (byte) i;
140: }
141:
142: tableIndex = 258;
143: bitsToGet = 9;
144: }
145:
146: /**
147: * Write out the string just uncompressed.
148: */
149: public void writeString(byte string[]) {
150:
151: if (dstIndex < uncompData.length) {
152: int maxIndex = Math.min(string.length, uncompData.length
153: - dstIndex);
154:
155: for (int i = 0; i < maxIndex; i++) {
156: uncompData[dstIndex++] = string[i];
157: }
158: }
159: }
160:
161: /**
162: * Add a new string to the string table.
163: */
164: public void addStringToTable(byte oldString[], byte newString) {
165: int length = oldString.length;
166: byte string[] = new byte[length + 1];
167: System.arraycopy(oldString, 0, string, 0, length);
168: string[length] = newString;
169:
170: // Add this new String to the table
171: stringTable[tableIndex++] = string;
172:
173: if (tableIndex == 511) {
174: bitsToGet = 10;
175: } else if (tableIndex == 1023) {
176: bitsToGet = 11;
177: } else if (tableIndex == 2047) {
178: bitsToGet = 12;
179: }
180: }
181:
182: /**
183: * Add a new string to the string table.
184: */
185: public void addStringToTable(byte string[]) {
186:
187: // Add this new String to the table
188: stringTable[tableIndex++] = string;
189:
190: if (tableIndex == 511) {
191: bitsToGet = 10;
192: } else if (tableIndex == 1023) {
193: bitsToGet = 11;
194: } else if (tableIndex == 2047) {
195: bitsToGet = 12;
196: }
197: }
198:
199: /**
200: * Append <code>newString</code> to the end of <code>oldString</code>.
201: */
202: public byte[] composeString(byte oldString[], byte newString) {
203: int length = oldString.length;
204: byte string[] = new byte[length + 1];
205: System.arraycopy(oldString, 0, string, 0, length);
206: string[length] = newString;
207:
208: return string;
209: }
210:
211: // Returns the next 9, 10, 11 or 12 bits
212: public int getNextCode() {
213: // Attempt to get the next code. The exception is caught to make
214: // this robust to cases wherein the EndOfInformation code has been
215: // omitted from a strip. Examples of such cases have been observed
216: // in practice.
217: try {
218: nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
219: nextBits += 8;
220:
221: if (nextBits < bitsToGet) {
222: nextData = (nextData << 8)
223: | (data[bytePointer++] & 0xff);
224: nextBits += 8;
225: }
226:
227: int code = (nextData >> (nextBits - bitsToGet))
228: & andTable[bitsToGet - 9];
229: nextBits -= bitsToGet;
230:
231: return code;
232: } catch (ArrayIndexOutOfBoundsException e) {
233: // Strip not terminated as expected: return EndOfInformation code.
234: return 257;
235: }
236: }
237: }
|