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