001: /*
002: * $RCSfile: TIFFLZWDecompressor.java,v $
003: *
004: *
005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * - Redistribution of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * - Redistribution in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * Neither the name of Sun Microsystems, Inc. or the names of
020: * contributors may be used to endorse or promote products derived
021: * from this software without specific prior written permission.
022: *
023: * This software is provided "AS IS," without a warranty of any
024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
035: * POSSIBILITY OF SUCH DAMAGES.
036: *
037: * You acknowledge that this software is not designed or intended for
038: * use in the design, construction, operation or maintenance of any
039: * nuclear facility.
040: *
041: * $Revision: 1.1 $
042: * $Date: 2005/02/11 05:01:48 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.tiff;
046:
047: import java.awt.Rectangle;
048: import java.io.IOException;
049: import javax.imageio.IIOException;
050: import javax.imageio.ImageReader;
051: import com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet;
052: import com.sun.media.imageio.plugins.tiff.TIFFDecompressor;
053: import com.sun.media.imageio.plugins.tiff.TIFFTag;
054:
055: public class TIFFLZWDecompressor extends TIFFDecompressor {
056:
057: private static final boolean DEBUG = false;
058:
059: private static final int andTable[] = { 511, 1023, 2047, 4095 };
060:
061: int predictor;
062:
063: byte[] srcData;
064: byte[] dstData;
065:
066: int srcIndex;
067: int dstIndex;
068:
069: byte stringTable[][];
070: int tableIndex, bitsToGet = 9;
071:
072: int nextData = 0;
073: int nextBits = 0;
074:
075: public TIFFLZWDecompressor(int predictor) throws IIOException {
076: super ();
077:
078: if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE
079: && predictor != BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
080: throw new IIOException("Illegal value for Predictor in "
081: + "TIFF file");
082: }
083:
084: if (DEBUG) {
085: System.out
086: .println("Using horizontal differencing predictor");
087: }
088:
089: this .predictor = predictor;
090: }
091:
092: public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel,
093: int scanlineStride) throws IOException {
094:
095: // Check bitsPerSample.
096: if (predictor == BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
097: int len = bitsPerSample.length;
098: for (int i = 0; i < len; i++) {
099: if (bitsPerSample[i] != 8) {
100: throw new IIOException(bitsPerSample[i]
101: + "-bit samples "
102: + "are not supported for Horizontal "
103: + "differencing Predictor");
104: }
105: }
106: }
107:
108: stream.seek(offset);
109:
110: byte[] sdata = new byte[byteCount];
111: stream.readFully(sdata);
112:
113: int bytesPerRow = (srcWidth * bitsPerPixel + 7) / 8;
114: byte[] buf;
115: int bufOffset;
116: if (bytesPerRow == scanlineStride) {
117: buf = b;
118: bufOffset = dstOffset;
119: } else {
120: buf = new byte[bytesPerRow * srcHeight];
121: bufOffset = 0;
122: }
123:
124: int numBytesDecoded = decode(sdata, 0, buf, bufOffset);
125:
126: if (bytesPerRow != scanlineStride) {
127: if (DEBUG) {
128: System.out.println("bytesPerRow != scanlineStride");
129: }
130: int off = 0;
131: for (int y = 0; y < srcHeight; y++) {
132: System.arraycopy(buf, off, b, dstOffset, bytesPerRow);
133: off += bytesPerRow;
134: dstOffset += scanlineStride;
135: }
136: }
137: }
138:
139: public int decode(byte[] sdata, int srcOffset, byte[] ddata,
140: int dstOffset) throws IOException {
141: if (sdata[0] == (byte) 0x00 && sdata[1] == (byte) 0x01) {
142: throw new IIOException(
143: "TIFF 5.0-style LZW compression is not supported!");
144: }
145:
146: this .srcData = sdata;
147: this .dstData = ddata;
148:
149: this .srcIndex = srcOffset;
150: this .dstIndex = dstOffset;
151:
152: this .nextData = 0;
153: this .nextBits = 0;
154:
155: initializeStringTable();
156:
157: int code, oldCode = 0;
158: byte[] string;
159:
160: while ((code = getNextCode()) != 257) {
161: if (code == 256) {
162: initializeStringTable();
163: code = getNextCode();
164: if (code == 257) {
165: break;
166: }
167:
168: writeString(stringTable[code]);
169: oldCode = code;
170: } else {
171: if (code < tableIndex) {
172: string = stringTable[code];
173:
174: writeString(string);
175: addStringToTable(stringTable[oldCode], string[0]);
176: oldCode = code;
177: } else {
178: string = stringTable[oldCode];
179: string = composeString(string, string[0]);
180: writeString(string);
181: addStringToTable(string);
182: oldCode = code;
183: }
184: }
185: }
186:
187: if (predictor == BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
188:
189: for (int j = 0; j < srcHeight; j++) {
190:
191: int count = dstOffset + samplesPerPixel
192: * (j * srcWidth + 1);
193:
194: for (int i = samplesPerPixel; i < srcWidth
195: * samplesPerPixel; i++) {
196:
197: dstData[count] += dstData[count - samplesPerPixel];
198: count++;
199: }
200: }
201: }
202:
203: return dstIndex - dstOffset;
204: }
205:
206: /**
207: * Initialize the string table.
208: */
209: public void initializeStringTable() {
210: stringTable = new byte[4096][];
211:
212: for (int i = 0; i < 256; i++) {
213: stringTable[i] = new byte[1];
214: stringTable[i][0] = (byte) i;
215: }
216:
217: tableIndex = 258;
218: bitsToGet = 9;
219: }
220:
221: /**
222: * Write out the string just uncompressed.
223: */
224: public void writeString(byte string[]) {
225: if (dstIndex < dstData.length) {
226: int maxIndex = Math.min(string.length, dstData.length
227: - dstIndex);
228:
229: for (int i = 0; i < maxIndex; i++) {
230: dstData[dstIndex++] = string[i];
231: }
232: }
233: }
234:
235: /**
236: * Add a new string to the string table.
237: */
238: public void addStringToTable(byte oldString[], byte newString) {
239: int length = oldString.length;
240: byte string[] = new byte[length + 1];
241: System.arraycopy(oldString, 0, string, 0, length);
242: string[length] = newString;
243:
244: // Add this new String to the table
245: stringTable[tableIndex++] = string;
246:
247: if (tableIndex == 511) {
248: bitsToGet = 10;
249: } else if (tableIndex == 1023) {
250: bitsToGet = 11;
251: } else if (tableIndex == 2047) {
252: bitsToGet = 12;
253: }
254: }
255:
256: /**
257: * Add a new string to the string table.
258: */
259: public void addStringToTable(byte string[]) {
260: // Add this new String to the table
261: stringTable[tableIndex++] = string;
262:
263: if (tableIndex == 511) {
264: bitsToGet = 10;
265: } else if (tableIndex == 1023) {
266: bitsToGet = 11;
267: } else if (tableIndex == 2047) {
268: bitsToGet = 12;
269: }
270: }
271:
272: /**
273: * Append <code>newString</code> to the end of <code>oldString</code>.
274: */
275: public byte[] composeString(byte oldString[], byte newString) {
276: int length = oldString.length;
277: byte string[] = new byte[length + 1];
278: System.arraycopy(oldString, 0, string, 0, length);
279: string[length] = newString;
280:
281: return string;
282: }
283:
284: // Returns the next 9, 10, 11 or 12 bits
285: public int getNextCode() {
286: // Attempt to get the next code. The exception is caught to make
287: // this robust to cases wherein the EndOfInformation code has been
288: // omitted from a strip. Examples of such cases have been observed
289: // in practice.
290:
291: try {
292: nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
293: nextBits += 8;
294:
295: if (nextBits < bitsToGet) {
296: nextData = (nextData << 8)
297: | (srcData[srcIndex++] & 0xff);
298: nextBits += 8;
299: }
300:
301: int code = (nextData >> (nextBits - bitsToGet))
302: & andTable[bitsToGet - 9];
303: nextBits -= bitsToGet;
304:
305: return code;
306: } catch (ArrayIndexOutOfBoundsException e) {
307: // Strip not terminated as expected: return EndOfInformation code.
308: return 257;
309: }
310: }
311: }
|