001/* 002 * $RCSfile: TIFFFaxCompressor.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.3 $ 042 * $Date: 2006/04/11 22:10:35 $ 043 * $State: Exp $ 044 */ 045package com.github.jaiimageio.impl.plugins.tiff; 046 047import java.io.IOException; 048 049import javax.imageio.metadata.IIOMetadata; 050 051import com.github.jaiimageio.plugins.tiff.BaselineTIFFTagSet; 052import com.github.jaiimageio.plugins.tiff.TIFFCompressor; 053import com.github.jaiimageio.plugins.tiff.TIFFField; 054 055/** 056 * 057 */ 058public abstract class TIFFFaxCompressor extends TIFFCompressor { 059 060 /** 061 * The CCITT numerical definition of white. 062 */ 063 public static final int WHITE = 0; 064 065 /** 066 * The CCITT numerical definition of black. 067 */ 068 public static final int BLACK = 1; 069 070 // --- Begin tables for CCITT compression --- 071 072 public static byte[] byteTable = new byte[] { 073 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, // 0 to 15 074 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16 to 31 075 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 32 to 47 076 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 48 to 63 077 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 to 79 078 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 to 95 079 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 to 111 080 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 112 to 127 081 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 to 143 082 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144 to 159 083 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 to 175 084 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176 to 191 085 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 to 207 086 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208 to 223 087 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224 to 239 088 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240 to 255 089 }; 090 091 /** 092 * Terminating codes for black runs. 093 */ 094 public static int[] termCodesBlack = new int[] { 095 /* 0 0x0000 */ 0x0dc0000a, 0x40000003, 0xc0000002, 0x80000002, 096 /* 4 0x0004 */ 0x60000003, 0x30000004, 0x20000004, 0x18000005, 097 /* 8 0x0008 */ 0x14000006, 0x10000006, 0x08000007, 0x0a000007, 098 /* 12 0x000c */ 0x0e000007, 0x04000008, 0x07000008, 0x0c000009, 099 /* 16 0x0010 */ 0x05c0000a, 0x0600000a, 0x0200000a, 0x0ce0000b, 100 /* 20 0x0014 */ 0x0d00000b, 0x0d80000b, 0x06e0000b, 0x0500000b, 101 /* 24 0x0018 */ 0x02e0000b, 0x0300000b, 0x0ca0000c, 0x0cb0000c, 102 /* 28 0x001c */ 0x0cc0000c, 0x0cd0000c, 0x0680000c, 0x0690000c, 103 /* 32 0x0020 */ 0x06a0000c, 0x06b0000c, 0x0d20000c, 0x0d30000c, 104 /* 36 0x0024 */ 0x0d40000c, 0x0d50000c, 0x0d60000c, 0x0d70000c, 105 /* 40 0x0028 */ 0x06c0000c, 0x06d0000c, 0x0da0000c, 0x0db0000c, 106 /* 44 0x002c */ 0x0540000c, 0x0550000c, 0x0560000c, 0x0570000c, 107 /* 48 0x0030 */ 0x0640000c, 0x0650000c, 0x0520000c, 0x0530000c, 108 /* 52 0x0034 */ 0x0240000c, 0x0370000c, 0x0380000c, 0x0270000c, 109 /* 56 0x0038 */ 0x0280000c, 0x0580000c, 0x0590000c, 0x02b0000c, 110 /* 60 0x003c */ 0x02c0000c, 0x05a0000c, 0x0660000c, 0x0670000c 111 }; 112 113 /** 114 * Terminating codes for white runs. 115 */ 116 public static int[] termCodesWhite = new int[] { 117 /* 0 0x0000 */ 0x35000008, 0x1c000006, 0x70000004, 0x80000004, 118 /* 4 0x0004 */ 0xb0000004, 0xc0000004, 0xe0000004, 0xf0000004, 119 /* 8 0x0008 */ 0x98000005, 0xa0000005, 0x38000005, 0x40000005, 120 /* 12 0x000c */ 0x20000006, 0x0c000006, 0xd0000006, 0xd4000006, 121 /* 16 0x0010 */ 0xa8000006, 0xac000006, 0x4e000007, 0x18000007, 122 /* 20 0x0014 */ 0x10000007, 0x2e000007, 0x06000007, 0x08000007, 123 /* 24 0x0018 */ 0x50000007, 0x56000007, 0x26000007, 0x48000007, 124 /* 28 0x001c */ 0x30000007, 0x02000008, 0x03000008, 0x1a000008, 125 /* 32 0x0020 */ 0x1b000008, 0x12000008, 0x13000008, 0x14000008, 126 /* 36 0x0024 */ 0x15000008, 0x16000008, 0x17000008, 0x28000008, 127 /* 40 0x0028 */ 0x29000008, 0x2a000008, 0x2b000008, 0x2c000008, 128 /* 44 0x002c */ 0x2d000008, 0x04000008, 0x05000008, 0x0a000008, 129 /* 48 0x0030 */ 0x0b000008, 0x52000008, 0x53000008, 0x54000008, 130 /* 52 0x0034 */ 0x55000008, 0x24000008, 0x25000008, 0x58000008, 131 /* 56 0x0038 */ 0x59000008, 0x5a000008, 0x5b000008, 0x4a000008, 132 /* 60 0x003c */ 0x4b000008, 0x32000008, 0x33000008, 0x34000008 133 }; 134 135 /** 136 * Make-up codes for black runs. 137 */ 138 public static int[] makeupCodesBlack = new int[] { 139 /* 0 0x0000 */ 0x00000000, 0x03c0000a, 0x0c80000c, 0x0c90000c, 140 /* 4 0x0004 */ 0x05b0000c, 0x0330000c, 0x0340000c, 0x0350000c, 141 /* 8 0x0008 */ 0x0360000d, 0x0368000d, 0x0250000d, 0x0258000d, 142 /* 12 0x000c */ 0x0260000d, 0x0268000d, 0x0390000d, 0x0398000d, 143 /* 16 0x0010 */ 0x03a0000d, 0x03a8000d, 0x03b0000d, 0x03b8000d, 144 /* 20 0x0014 */ 0x0290000d, 0x0298000d, 0x02a0000d, 0x02a8000d, 145 /* 24 0x0018 */ 0x02d0000d, 0x02d8000d, 0x0320000d, 0x0328000d, 146 /* 28 0x001c */ 0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c, 147 /* 32 0x0020 */ 0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c, 148 /* 36 0x0024 */ 0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c, 149 /* 40 0x0028 */ 0x01f0000c, 0x00000000, 0x00000000, 0x00000000, 150 /* 44 0x002c */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 151 /* 48 0x0030 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 152 /* 52 0x0034 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 153 /* 56 0x0038 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000 154 }; 155 156 /** 157 * Make-up codes for white runs. 158 */ 159 public static int[] makeupCodesWhite = new int[] { 160 /* 0 0x0000 */ 0x00000000, 0xd8000005, 0x90000005, 0x5c000006, 161 /* 4 0x0004 */ 0x6e000007, 0x36000008, 0x37000008, 0x64000008, 162 /* 8 0x0008 */ 0x65000008, 0x68000008, 0x67000008, 0x66000009, 163 /* 12 0x000c */ 0x66800009, 0x69000009, 0x69800009, 0x6a000009, 164 /* 16 0x0010 */ 0x6a800009, 0x6b000009, 0x6b800009, 0x6c000009, 165 /* 20 0x0014 */ 0x6c800009, 0x6d000009, 0x6d800009, 0x4c000009, 166 /* 24 0x0018 */ 0x4c800009, 0x4d000009, 0x60000006, 0x4d800009, 167 /* 28 0x001c */ 0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c, 168 /* 32 0x0020 */ 0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c, 169 /* 36 0x0024 */ 0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c, 170 /* 40 0x0028 */ 0x01f0000c, 0x00000000, 0x00000000, 0x00000000, 171 /* 44 0x002c */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 172 /* 48 0x0030 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 173 /* 52 0x0034 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 174 /* 56 0x0038 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000 175 }; 176 177 /** 178 * Pass mode table. 179 */ 180 public static int[] passMode = new int[] { 181 0x10000004 // 0001 182 }; 183 184 /** 185 * Vertical mode table. 186 */ 187 public static int[] vertMode = new int[] { 188 0x06000007, // 0000011 189 0x0c000006, // 000011 190 0x60000003, // 011 191 0x80000001, // 1 192 0x40000003, // 010 193 0x08000006, // 000010 194 0x04000007 // 0000010 195 }; 196 197 /** 198 * Horizontal mode table. 199 */ 200 public static int[] horzMode = new int[] { 201 0x20000003 // 001 202 }; 203 204 /** 205 * Black and white terminating code table. 206 */ 207 public static int[][] termCodes = 208 new int[][] {termCodesWhite, termCodesBlack}; 209 210 /** 211 * Black and white make-up code table. 212 */ 213 public static int[][] makeupCodes = 214 new int[][] {makeupCodesWhite, makeupCodesBlack}; 215 216 /** 217 * Black and white pass mode table. 218 */ 219 public static int[][] pass = new int[][] {passMode, passMode}; 220 221 /** 222 * Black and white vertical mode table. 223 */ 224 public static int[][] vert = new int[][] {vertMode, vertMode}; 225 226 /** 227 * Black and white horizontal mode table. 228 */ 229 public static int[][] horz = new int[][] {horzMode, horzMode}; 230 231 // --- End tables for CCITT compression --- 232 233 /** 234 * Whether bits are inserted in reverse order (TIFF FillOrder 2). 235 */ 236 public boolean inverseFill = false; 237 238 /** 239 * Output bit buffer. 240 */ 241 public int bits; 242 243 /** 244 * Number of bits in the output bit buffer. 245 */ 246 public int ndex; 247 248 /** 249 * Constructor. The superclass constructor is merely invoked with the 250 * same parameters. 251 */ 252 protected TIFFFaxCompressor(String compressionType, 253 int compressionTagValue, 254 boolean isCompressionLossless) { 255 super(compressionType, compressionTagValue, isCompressionLossless); 256 } 257 258 /** 259 * Sets the value of the <code>metadata</code> field. 260 * 261 * <p> The implementation in this class also sets local options 262 * from the FILL_ORDER field if it exists.</p> 263 * 264 * @param metadata the <code>IIOMetadata</code> object for the 265 * image being written. 266 * 267 * @see #getMetadata() 268 */ 269 public void setMetadata(IIOMetadata metadata) { 270 super.setMetadata(metadata); 271 272 if (metadata instanceof TIFFImageMetadata) { 273 TIFFImageMetadata tim = (TIFFImageMetadata)metadata; 274 TIFFField f = tim.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER); 275 inverseFill = (f != null && f.getAsInt(0) == 2); 276 } 277 } 278 279 /** 280 * Return min of <code>maxOffset</code> or offset of first pixel 281 * different from pixel at <code>bitOffset</code>. 282 */ 283 public int nextState(byte[] data, 284 int base, 285 int bitOffset, 286 int maxOffset) 287 { 288 if(data == null) { 289 return maxOffset; 290 } 291 292 int next = base + (bitOffset>>>3); 293 // If the offset is beyond the data already then the minimum of the 294 // current offset and maxOffset must be maxOffset. 295 if(next >= data.length) { 296 return maxOffset; 297 } 298 int end = base + (maxOffset>>>3); 299 if(end == data.length) { // Prevents out of bounds exception below 300 end--; 301 } 302 int extra = bitOffset & 0x7; 303 304 int testbyte; 305 306 if((data[next] & (0x80 >>> extra)) != 0) { // look for "0" 307 testbyte = ~(data[next]) & (0xff >>> extra); 308 while (next < end) { 309 if (testbyte != 0) { 310 break; 311 } 312 testbyte = ~(data[++next]) & 0xff; 313 } 314 } else { // look for "1" 315 if ((testbyte = (data[next] & (0xff >>> extra))) != 0) { 316 bitOffset = (next-base)*8 + byteTable[testbyte]; 317 return ((bitOffset < maxOffset) ? bitOffset : maxOffset); 318 } 319 while (next < end) { 320 if ((testbyte = data[++next]&0xff) != 0) { 321 // "1" is in current byte 322 bitOffset = (next-base)*8 + byteTable[testbyte]; 323 return ((bitOffset < maxOffset) ? bitOffset : maxOffset); 324 } 325 } 326 } 327 bitOffset = (next-base)*8 + byteTable[testbyte]; 328 return ((bitOffset < maxOffset) ? bitOffset : maxOffset); 329 } 330 331 /** 332 * Initialize bit buffer machinery. 333 */ 334 public void initBitBuf() 335 { 336 ndex = 0; 337 bits = 0x00000000; 338 } 339 340 /** 341 * Get code for run and add to compressed bitstream. 342 */ 343 public int add1DBits(byte[] buf, 344 int where, // byte offs 345 int count, // #pixels in run 346 int color) // color of run 347 { 348 int sixtyfours; 349 int mask; 350 int len = where; 351 352 sixtyfours = count >>> 6; // count / 64; 353 count = count & 0x3f; // count % 64 354 if (sixtyfours != 0) { 355 for ( ; sixtyfours > 40; sixtyfours -= 40) { 356 mask = makeupCodes[color][40]; 357 bits |= (mask & 0xfff80000) >>> ndex; 358 ndex += (int)(mask & 0x0000ffff); 359 while (ndex > 7) { 360 buf[len++] = (byte)(bits >>> 24); 361 bits <<= 8; 362 ndex -= 8; 363 } 364 } 365 366 mask = makeupCodes[color][sixtyfours]; 367 bits |= (mask & 0xfff80000) >>> ndex; 368 ndex += (int)(mask & 0x0000ffff); 369 while (ndex > 7) { 370 buf[len++] = (byte)(bits >>> 24); 371 bits <<= 8; 372 ndex -= 8; 373 } 374 } 375 376 mask = termCodes[color][count]; 377 bits |= (mask & 0xfff80000) >>> ndex; 378 ndex += (int)(mask & 0x0000ffff); 379 while (ndex > 7) { 380 buf[len++] = (byte)(bits >>> 24); 381 bits <<= 8; 382 ndex -= 8; 383 } 384 385 return(len - where); 386 } 387 388 /** 389 * Place entry from mode table into compressed bitstream. 390 */ 391 public int add2DBits(byte[] buf, // compressed buffer 392 int where, // byte offset into compressed buffer 393 int[][] mode, // 2-D mode to be encoded 394 int entry) // mode entry (0 unless vertical) 395 { 396 int mask; 397 int len = where; 398 int color = 0; 399 400 mask = mode[color][entry]; 401 bits |= (mask & 0xfff80000) >>> ndex; 402 ndex += (int)(mask & 0x0000ffff); 403 while (ndex > 7) { 404 buf[len++] = (byte)(bits >>> 24); 405 bits <<= 8; 406 ndex -= 8; 407 } 408 409 return(len - where); 410 } 411 412 /** 413 * Add an End-of-Line (EOL == 0x001) to the compressed bitstream 414 * with optional byte alignment. 415 */ 416 public int addEOL(boolean is1DMode,// 1D encoding 417 boolean addFill, // byte aligned EOLs 418 boolean add1, // add1 ? EOL+1 : EOL+0 419 byte[] buf, // compressed buffer address 420 int where) // current byte offset into buffer 421 { 422 int len = where; 423 424 // 425 // Add zero-valued fill bits such that the EOL is aligned as 426 // 427 // xxxx 0000 0000 0001 428 // 429 if(addFill) { 430 // 431 // Simply increment the bit count. No need to feed bits into 432 // the output buffer at this point as there are at most 7 bits 433 // in the bit buffer, at most 7 are added here, and at most 434 // 13 below making the total 7+7+13 = 27 before the bit feed 435 // at the end of this routine. 436 // 437 ndex += ((ndex <= 4) ? 4 - ndex : 12 - ndex); 438 } 439 440 // 441 // Write EOL into buffer 442 // 443 if(is1DMode) { 444 bits |= 0x00100000 >>> ndex; 445 ndex += 12; 446 } else { 447 bits |= (add1 ? 0x00180000 : 0x00100000) >>> ndex; 448 ndex += 13; 449 } 450 451 while (ndex > 7) { 452 buf[len++] = (byte)(bits >>> 24); 453 bits <<= 8; 454 ndex -= 8; 455 } 456 457 return(len - where); 458 } 459 460 /** 461 * Add an End-of-Facsimile-Block (EOFB == 0x001001) to the compressed 462 * bitstream. 463 */ 464 public int addEOFB(byte[] buf, // compressed buffer 465 int where) // byte offset into compressed buffer 466 { 467 int len = where; 468 469 // 470 // eofb code 471 // 472 bits |= 0x00100100 >>> ndex; 473 474 // 475 // eofb code length 476 // 477 ndex += 24; 478 479 // 480 // flush all pending bits 481 // 482 while(ndex > 0) { 483 buf[len++] = (byte)(bits >>> 24); 484 bits <<= 8; 485 ndex -= 8; 486 } 487 488 return(len - where); 489 } 490 491 /** 492 * One-dimensionally encode a row of data using CCITT Huffman compression. 493 * The bit buffer should be initialized as required before invoking this 494 * method and should be flushed after the method returns. The fill order 495 * is always highest-order to lowest-order bit so the calling routine 496 * should handle bit inversion. 497 */ 498 public int encode1D(byte[] data, 499 int rowOffset, 500 int colOffset, 501 int rowLength, 502 byte[] compData, 503 int compOffset) { 504 int lineAddr = rowOffset; 505 int bitIndex = colOffset; 506 507 int last = bitIndex + rowLength; 508 int outIndex = compOffset; 509 510 // 511 // Is first pixel black 512 // 513 int testbit = 514 ((data[lineAddr + (bitIndex>>>3)]&0xff) >>> 515 (7-(bitIndex & 0x7))) & 0x1; 516 int currentColor = BLACK; 517 if (testbit != 0) { 518 outIndex += add1DBits(compData, outIndex, 0, WHITE); 519 } else { 520 currentColor = WHITE; 521 } 522 523 // 524 // Run-length encode line 525 // 526 while (bitIndex < last) { 527 int bitCount = 528 nextState(data, lineAddr, bitIndex, last) - bitIndex; 529 outIndex += 530 add1DBits(compData, outIndex, bitCount, currentColor); 531 bitIndex += bitCount; 532 currentColor ^= 0x00000001; 533 } 534 535 return outIndex - compOffset; 536 } 537}