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 */ 045package com.github.jaiimageio.impl.plugins.tiff; 046 047import java.io.IOException; 048 049import javax.imageio.IIOException; 050 051import com.github.jaiimageio.plugins.tiff.BaselineTIFFTagSet; 052import com.github.jaiimageio.plugins.tiff.TIFFDecompressor; 053 054public class TIFFLZWDecompressor extends TIFFDecompressor { 055 056 private static final boolean DEBUG = false; 057 058 private static final int andTable[] = { 059 511, 060 1023, 061 2047, 062 4095 063 }; 064 065 int predictor; 066 067 byte[] srcData; 068 byte[] dstData; 069 070 int srcIndex; 071 int dstIndex; 072 073 byte stringTable[][]; 074 int tableIndex, bitsToGet = 9; 075 076 int nextData = 0; 077 int nextBits = 0; 078 079 public TIFFLZWDecompressor(int predictor) throws IIOException { 080 super(); 081 082 if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE && 083 predictor != 084 BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) { 085 throw new IIOException("Illegal value for Predictor in " + 086 "TIFF file"); 087 } 088 089 if(DEBUG) { 090 System.out.println("Using horizontal differencing predictor"); 091 } 092 093 this.predictor = predictor; 094 } 095 096 public void decodeRaw(byte[] b, 097 int dstOffset, 098 int bitsPerPixel, 099 int scanlineStride) throws IOException { 100 101 // Check bitsPerSample. 102 if (predictor == 103 BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) { 104 int len = bitsPerSample.length; 105 for(int i = 0; i < len; i++) { 106 if(bitsPerSample[i] != 8) { 107 throw new IIOException 108 (bitsPerSample[i] + "-bit samples "+ 109 "are not supported for Horizontal "+ 110 "differencing Predictor"); 111 } 112 } 113 } 114 115 stream.seek(offset); 116 117 byte[] sdata = new byte[byteCount]; 118 stream.readFully(sdata); 119 120 int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8; 121 byte[] buf; 122 int bufOffset; 123 if(bytesPerRow == scanlineStride) { 124 buf = b; 125 bufOffset = dstOffset; 126 } else { 127 buf = new byte[bytesPerRow*srcHeight]; 128 bufOffset = 0; 129 } 130 131 int numBytesDecoded = decode(sdata, 0, buf, bufOffset); 132 133 if(bytesPerRow != scanlineStride) { 134 if(DEBUG) { 135 System.out.println("bytesPerRow != scanlineStride"); 136 } 137 int off = 0; 138 for (int y = 0; y < srcHeight; y++) { 139 System.arraycopy(buf, off, b, dstOffset, bytesPerRow); 140 off += bytesPerRow; 141 dstOffset += scanlineStride; 142 } 143 } 144 } 145 146 public int decode(byte[] sdata, int srcOffset, 147 byte[] ddata, int dstOffset) 148 throws IOException { 149 if (sdata[0] == (byte)0x00 && sdata[1] == (byte)0x01) { 150 throw new IIOException 151 ("TIFF 5.0-style LZW compression is not supported!"); 152 } 153 154 this.srcData = sdata; 155 this.dstData = ddata; 156 157 this.srcIndex = srcOffset; 158 this.dstIndex = dstOffset; 159 160 this.nextData = 0; 161 this.nextBits = 0; 162 163 initializeStringTable(); 164 165 int code, oldCode = 0; 166 byte[] string; 167 168 while ((code = getNextCode()) != 257) { 169 if (code == 256) { 170 initializeStringTable(); 171 code = getNextCode(); 172 if (code == 257) { 173 break; 174 } 175 176 writeString(stringTable[code]); 177 oldCode = code; 178 } else { 179 if (code < tableIndex) { 180 string = stringTable[code]; 181 182 writeString(string); 183 addStringToTable(stringTable[oldCode], string[0]); 184 oldCode = code; 185 } else { 186 string = stringTable[oldCode]; 187 string = composeString(string, string[0]); 188 writeString(string); 189 addStringToTable(string); 190 oldCode = code; 191 } 192 } 193 } 194 195 if (predictor == 196 BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) { 197 198 for (int j = 0; j < srcHeight; j++) { 199 200 int count = dstOffset + samplesPerPixel * (j * srcWidth + 1); 201 202 for (int i = samplesPerPixel; i < srcWidth * samplesPerPixel; i++) { 203 204 dstData[count] += dstData[count - samplesPerPixel]; 205 count++; 206 } 207 } 208 } 209 210 return dstIndex - dstOffset; 211 } 212 213 /** 214 * Initialize the string table. 215 */ 216 public void initializeStringTable() { 217 stringTable = new byte[4096][]; 218 219 for (int i = 0; i < 256; i++) { 220 stringTable[i] = new byte[1]; 221 stringTable[i][0] = (byte)i; 222 } 223 224 tableIndex = 258; 225 bitsToGet = 9; 226 } 227 228 /** 229 * Write out the string just uncompressed. 230 */ 231 public void writeString(byte string[]) { 232 if(dstIndex < dstData.length) { 233 int maxIndex = Math.min(string.length, 234 dstData.length - dstIndex); 235 236 for (int i=0; i < maxIndex; i++) { 237 dstData[dstIndex++] = string[i]; 238 } 239 } 240 } 241 242 /** 243 * Add a new string to the string table. 244 */ 245 public void addStringToTable(byte oldString[], byte newString) { 246 int length = oldString.length; 247 byte string[] = new byte[length + 1]; 248 System.arraycopy(oldString, 0, string, 0, length); 249 string[length] = newString; 250 251 // Add this new String to the table 252 stringTable[tableIndex++] = string; 253 254 if (tableIndex == 511) { 255 bitsToGet = 10; 256 } else if (tableIndex == 1023) { 257 bitsToGet = 11; 258 } else if (tableIndex == 2047) { 259 bitsToGet = 12; 260 } 261 } 262 263 /** 264 * Add a new string to the string table. 265 */ 266 public void addStringToTable(byte string[]) { 267 // Add this new String to the table 268 stringTable[tableIndex++] = string; 269 270 if (tableIndex == 511) { 271 bitsToGet = 10; 272 } else if (tableIndex == 1023) { 273 bitsToGet = 11; 274 } else if (tableIndex == 2047) { 275 bitsToGet = 12; 276 } 277 } 278 279 /** 280 * Append <code>newString</code> to the end of <code>oldString</code>. 281 */ 282 public byte[] composeString(byte oldString[], byte newString) { 283 int length = oldString.length; 284 byte string[] = new byte[length + 1]; 285 System.arraycopy(oldString, 0, string, 0, length); 286 string[length] = newString; 287 288 return string; 289 } 290 291 // Returns the next 9, 10, 11 or 12 bits 292 public int getNextCode() { 293 // Attempt to get the next code. The exception is caught to make 294 // this robust to cases wherein the EndOfInformation code has been 295 // omitted from a strip. Examples of such cases have been observed 296 // in practice. 297 298 try { 299 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff); 300 nextBits += 8; 301 302 if (nextBits < bitsToGet) { 303 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff); 304 nextBits += 8; 305 } 306 307 int code = 308 (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9]; 309 nextBits -= bitsToGet; 310 311 return code; 312 } catch (ArrayIndexOutOfBoundsException e) { 313 // Strip not terminated as expected: return EndOfInformation code. 314 return 257; 315 } 316 } 317} 318