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