001/* 002 * $RCSfile: TIFFLZWUtil.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.TIFFTag; 055 056public class TIFFLZWUtil { 057 058 private static final boolean debug = false; 059 060 public TIFFLZWUtil() { 061 } 062 063 byte[] srcData; 064 int srcIndex; 065 066 byte[] dstData; 067 int dstIndex = 0; 068 069 byte stringTable[][]; 070 int tableIndex, bitsToGet = 9; 071 072 int predictor, samplesPerPixel; 073 int nextData = 0; 074 int nextBits = 0; 075 076 private static final int andTable[] = { 077 511, 078 1023, 079 2047, 080 4095 081 }; 082 083 public byte[] decode(byte[] data, int predictor, int samplesPerPixel, 084 int width, int height) throws IOException { 085 if (data[0] == (byte)0x00 && data[1] == (byte)0x01) { 086 throw new IIOException("TIFF 5.0-style LZW compression is not supported!"); 087 } 088 089 this.srcData = data; 090 this.srcIndex = 0; 091 this.nextData = 0; 092 this.nextBits = 0; 093 094 this.dstData = new byte[8192]; 095 this.dstIndex = 0; 096 097 initializeStringTable(); 098 099 int code, oldCode = 0; 100 byte[] string; 101 102 while ((code = getNextCode()) != 257) { 103 if (code == 256) { 104 initializeStringTable(); 105 code = getNextCode(); 106 if (code == 257) { 107 break; 108 } 109 110 writeString(stringTable[code]); 111 oldCode = code; 112 } else { 113 if (code < tableIndex) { 114 string = stringTable[code]; 115 116 writeString(string); 117 addStringToTable(stringTable[oldCode], string[0]); 118 oldCode = code; 119 } else { 120 string = stringTable[oldCode]; 121 string = composeString(string, string[0]); 122 writeString(string); 123 addStringToTable(string); 124 oldCode = code; 125 } 126 } 127 } 128 129 if (predictor == 2) { 130 131 int count; 132 for (int j = 0; j < height; j++) { 133 134 count = samplesPerPixel * (j * width + 1); 135 136 for (int i = samplesPerPixel; i < width * samplesPerPixel; i++) { 137 138 dstData[count] += dstData[count - samplesPerPixel]; 139 count++; 140 } 141 } 142 } 143 144 byte[] newDstData = new byte[dstIndex]; 145 System.arraycopy(dstData, 0, newDstData, 0, dstIndex); 146 return newDstData; 147 } 148 149 /** 150 * Initialize the string table. 151 */ 152 public void initializeStringTable() { 153 stringTable = new byte[4096][]; 154 155 for (int i = 0; i < 256; i++) { 156 stringTable[i] = new byte[1]; 157 stringTable[i][0] = (byte)i; 158 } 159 160 tableIndex = 258; 161 bitsToGet = 9; 162 } 163 164 private void ensureCapacity(int bytesToAdd) { 165 if (dstIndex + bytesToAdd > dstData.length) { 166 byte[] newDstData = new byte[Math.max((int)(dstData.length*1.2f), 167 dstIndex + bytesToAdd)]; 168 System.arraycopy(dstData, 0, newDstData, 0, dstData.length); 169 dstData = newDstData; 170 } 171 } 172 173 /** 174 * Write out the string just uncompressed. 175 */ 176 public void writeString(byte string[]) { 177 ensureCapacity(string.length); 178 for (int i = 0; i < string.length; i++) { 179 dstData[dstIndex++] = string[i]; 180 } 181 } 182 183 /** 184 * Add a new string to the string table. 185 */ 186 public void addStringToTable(byte oldString[], byte newString) { 187 int length = oldString.length; 188 byte string[] = new byte[length + 1]; 189 System.arraycopy(oldString, 0, string, 0, length); 190 string[length] = newString; 191 192 // Add this new String to the table 193 stringTable[tableIndex++] = string; 194 195 if (tableIndex == 511) { 196 bitsToGet = 10; 197 } else if (tableIndex == 1023) { 198 bitsToGet = 11; 199 } else if (tableIndex == 2047) { 200 bitsToGet = 12; 201 } 202 } 203 204 /** 205 * Add a new string to the string table. 206 */ 207 public void addStringToTable(byte string[]) { 208 // Add this new String to the table 209 stringTable[tableIndex++] = string; 210 211 if (tableIndex == 511) { 212 bitsToGet = 10; 213 } else if (tableIndex == 1023) { 214 bitsToGet = 11; 215 } else if (tableIndex == 2047) { 216 bitsToGet = 12; 217 } 218 } 219 220 /** 221 * Append <code>newString</code> to the end of <code>oldString</code>. 222 */ 223 public byte[] composeString(byte oldString[], byte newString) { 224 int length = oldString.length; 225 byte string[] = new byte[length + 1]; 226 System.arraycopy(oldString, 0, string, 0, length); 227 string[length] = newString; 228 229 return string; 230 } 231 232 // Returns the next 9, 10, 11 or 12 bits 233 public int getNextCode() { 234 // Attempt to get the next code. The exception is caught to make 235 // this robust to cases wherein the EndOfInformation code has been 236 // omitted from a strip. Examples of such cases have been observed 237 // in practice. 238 239 try { 240 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff); 241 nextBits += 8; 242 243 if (nextBits < bitsToGet) { 244 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff); 245 nextBits += 8; 246 } 247 248 int code = 249 (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9]; 250 nextBits -= bitsToGet; 251 252 return code; 253 } catch (ArrayIndexOutOfBoundsException e) { 254 // Strip not terminated as expected: return EndOfInformation code. 255 return 257; 256 } 257 } 258}