1/* 2 * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package com.sun.imageio.plugins.tiff; 26 27import javax.imageio.metadata.IIOMetadata; 28import javax.imageio.plugins.tiff.BaselineTIFFTagSet; 29import javax.imageio.plugins.tiff.TIFFField; 30 31/** 32 * 33 */ 34abstract class TIFFFaxCompressor extends TIFFCompressor { 35 36 /** 37 * The CCITT numerical definition of white. 38 */ 39 protected static final int WHITE = 0; 40 41 /** 42 * The CCITT numerical definition of black. 43 */ 44 protected static final int BLACK = 1; 45 46 // --- Begin tables for CCITT compression --- 47 48 protected static final byte[] byteTable = new byte[] { 49 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, // 0 to 15 50 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16 to 31 51 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 32 to 47 52 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 48 to 63 53 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 to 79 54 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 to 95 55 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 to 111 56 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 112 to 127 57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 to 143 58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144 to 159 59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 to 175 60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176 to 191 61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 to 207 62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208 to 223 63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224 to 239 64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240 to 255 65 }; 66 67 /** 68 * Terminating codes for black runs. 69 */ 70 protected static final int[] termCodesBlack = new int[] { 71 /* 0 0x0000 */ 0x0dc0000a, 0x40000003, 0xc0000002, 0x80000002, 72 /* 4 0x0004 */ 0x60000003, 0x30000004, 0x20000004, 0x18000005, 73 /* 8 0x0008 */ 0x14000006, 0x10000006, 0x08000007, 0x0a000007, 74 /* 12 0x000c */ 0x0e000007, 0x04000008, 0x07000008, 0x0c000009, 75 /* 16 0x0010 */ 0x05c0000a, 0x0600000a, 0x0200000a, 0x0ce0000b, 76 /* 20 0x0014 */ 0x0d00000b, 0x0d80000b, 0x06e0000b, 0x0500000b, 77 /* 24 0x0018 */ 0x02e0000b, 0x0300000b, 0x0ca0000c, 0x0cb0000c, 78 /* 28 0x001c */ 0x0cc0000c, 0x0cd0000c, 0x0680000c, 0x0690000c, 79 /* 32 0x0020 */ 0x06a0000c, 0x06b0000c, 0x0d20000c, 0x0d30000c, 80 /* 36 0x0024 */ 0x0d40000c, 0x0d50000c, 0x0d60000c, 0x0d70000c, 81 /* 40 0x0028 */ 0x06c0000c, 0x06d0000c, 0x0da0000c, 0x0db0000c, 82 /* 44 0x002c */ 0x0540000c, 0x0550000c, 0x0560000c, 0x0570000c, 83 /* 48 0x0030 */ 0x0640000c, 0x0650000c, 0x0520000c, 0x0530000c, 84 /* 52 0x0034 */ 0x0240000c, 0x0370000c, 0x0380000c, 0x0270000c, 85 /* 56 0x0038 */ 0x0280000c, 0x0580000c, 0x0590000c, 0x02b0000c, 86 /* 60 0x003c */ 0x02c0000c, 0x05a0000c, 0x0660000c, 0x0670000c 87 }; 88 89 /** 90 * Terminating codes for white runs. 91 */ 92 protected static final int[] termCodesWhite = new int[] { 93 /* 0 0x0000 */ 0x35000008, 0x1c000006, 0x70000004, 0x80000004, 94 /* 4 0x0004 */ 0xb0000004, 0xc0000004, 0xe0000004, 0xf0000004, 95 /* 8 0x0008 */ 0x98000005, 0xa0000005, 0x38000005, 0x40000005, 96 /* 12 0x000c */ 0x20000006, 0x0c000006, 0xd0000006, 0xd4000006, 97 /* 16 0x0010 */ 0xa8000006, 0xac000006, 0x4e000007, 0x18000007, 98 /* 20 0x0014 */ 0x10000007, 0x2e000007, 0x06000007, 0x08000007, 99 /* 24 0x0018 */ 0x50000007, 0x56000007, 0x26000007, 0x48000007, 100 /* 28 0x001c */ 0x30000007, 0x02000008, 0x03000008, 0x1a000008, 101 /* 32 0x0020 */ 0x1b000008, 0x12000008, 0x13000008, 0x14000008, 102 /* 36 0x0024 */ 0x15000008, 0x16000008, 0x17000008, 0x28000008, 103 /* 40 0x0028 */ 0x29000008, 0x2a000008, 0x2b000008, 0x2c000008, 104 /* 44 0x002c */ 0x2d000008, 0x04000008, 0x05000008, 0x0a000008, 105 /* 48 0x0030 */ 0x0b000008, 0x52000008, 0x53000008, 0x54000008, 106 /* 52 0x0034 */ 0x55000008, 0x24000008, 0x25000008, 0x58000008, 107 /* 56 0x0038 */ 0x59000008, 0x5a000008, 0x5b000008, 0x4a000008, 108 /* 60 0x003c */ 0x4b000008, 0x32000008, 0x33000008, 0x34000008 109 }; 110 111 /** 112 * Make-up codes for black runs. 113 */ 114 protected static final int[] makeupCodesBlack = new int[] { 115 /* 0 0x0000 */ 0x00000000, 0x03c0000a, 0x0c80000c, 0x0c90000c, 116 /* 4 0x0004 */ 0x05b0000c, 0x0330000c, 0x0340000c, 0x0350000c, 117 /* 8 0x0008 */ 0x0360000d, 0x0368000d, 0x0250000d, 0x0258000d, 118 /* 12 0x000c */ 0x0260000d, 0x0268000d, 0x0390000d, 0x0398000d, 119 /* 16 0x0010 */ 0x03a0000d, 0x03a8000d, 0x03b0000d, 0x03b8000d, 120 /* 20 0x0014 */ 0x0290000d, 0x0298000d, 0x02a0000d, 0x02a8000d, 121 /* 24 0x0018 */ 0x02d0000d, 0x02d8000d, 0x0320000d, 0x0328000d, 122 /* 28 0x001c */ 0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c, 123 /* 32 0x0020 */ 0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c, 124 /* 36 0x0024 */ 0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c, 125 /* 40 0x0028 */ 0x01f0000c, 0x00000000, 0x00000000, 0x00000000, 126 /* 44 0x002c */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 127 /* 48 0x0030 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 128 /* 52 0x0034 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 129 /* 56 0x0038 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000 130 }; 131 132 /** 133 * Make-up codes for white runs. 134 */ 135 protected static final int[] makeupCodesWhite = new int[] { 136 /* 0 0x0000 */ 0x00000000, 0xd8000005, 0x90000005, 0x5c000006, 137 /* 4 0x0004 */ 0x6e000007, 0x36000008, 0x37000008, 0x64000008, 138 /* 8 0x0008 */ 0x65000008, 0x68000008, 0x67000008, 0x66000009, 139 /* 12 0x000c */ 0x66800009, 0x69000009, 0x69800009, 0x6a000009, 140 /* 16 0x0010 */ 0x6a800009, 0x6b000009, 0x6b800009, 0x6c000009, 141 /* 20 0x0014 */ 0x6c800009, 0x6d000009, 0x6d800009, 0x4c000009, 142 /* 24 0x0018 */ 0x4c800009, 0x4d000009, 0x60000006, 0x4d800009, 143 /* 28 0x001c */ 0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c, 144 /* 32 0x0020 */ 0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c, 145 /* 36 0x0024 */ 0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c, 146 /* 40 0x0028 */ 0x01f0000c, 0x00000000, 0x00000000, 0x00000000, 147 /* 44 0x002c */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 148 /* 48 0x0030 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 149 /* 52 0x0034 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 150 /* 56 0x0038 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000 151 }; 152 153 /** 154 * Pass mode table. 155 */ 156 protected static final int[] passMode = new int[] { 157 0x10000004 // 0001 158 }; 159 160 /** 161 * Vertical mode table. 162 */ 163 protected static final int[] vertMode = new int[] { 164 0x06000007, // 0000011 165 0x0c000006, // 000011 166 0x60000003, // 011 167 0x80000001, // 1 168 0x40000003, // 010 169 0x08000006, // 000010 170 0x04000007 // 0000010 171 }; 172 173 /** 174 * Horizontal mode table. 175 */ 176 protected static final int[] horzMode = new int[] { 177 0x20000003 // 001 178 }; 179 180 /** 181 * Black and white terminating code table. 182 */ 183 protected static final int[][] termCodes = 184 new int[][] {termCodesWhite, termCodesBlack}; 185 186 /** 187 * Black and white make-up code table. 188 */ 189 protected static final int[][] makeupCodes = 190 new int[][] {makeupCodesWhite, makeupCodesBlack}; 191 192 /** 193 * Black and white pass mode table. 194 */ 195 protected static final int[][] pass = new int[][] {passMode, passMode}; 196 197 /** 198 * Black and white vertical mode table. 199 */ 200 protected static final int[][] vert = new int[][] {vertMode, vertMode}; 201 202 /** 203 * Black and white horizontal mode table. 204 */ 205 protected static final int[][] horz = new int[][] {horzMode, horzMode}; 206 207 // --- End tables for CCITT compression --- 208 209 /** 210 * Whether bits are inserted in reverse order (TIFF FillOrder 2). 211 */ 212 protected boolean inverseFill = false; 213 214 /** 215 * Output bit buffer. 216 */ 217 protected int bits; 218 219 /** 220 * Number of bits in the output bit buffer. 221 */ 222 protected int ndex; 223 224 /** 225 * Constructor. The superclass constructor is merely invoked with the 226 * same parameters. 227 */ 228 protected TIFFFaxCompressor(String compressionType, 229 int compressionTagValue, 230 boolean isCompressionLossless) { 231 super(compressionType, compressionTagValue, isCompressionLossless); 232 } 233 234 /** 235 * Sets the value of the {@code metadata} field. 236 * 237 * <p> The implementation in this class also sets local options 238 * from the FILL_ORDER field if it exists.</p> 239 * 240 * @param metadata the {@code IIOMetadata} object for the 241 * image being written. 242 * 243 * @see #getMetadata() 244 */ 245 public void setMetadata(IIOMetadata metadata) { 246 super.setMetadata(metadata); 247 248 if (metadata instanceof TIFFImageMetadata) { 249 TIFFImageMetadata tim = (TIFFImageMetadata)metadata; 250 TIFFField f = tim.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER); 251 inverseFill = (f != null && f.getAsInt(0) == 2); 252 } 253 } 254 255 /** 256 * Return min of {@code maxOffset} or offset of first pixel 257 * different from pixel at {@code bitOffset}. 258 */ 259 public int nextState(byte[] data, 260 int base, 261 int bitOffset, 262 int maxOffset) 263 { 264 if(data == null) { 265 return maxOffset; 266 } 267 268 int next = base + (bitOffset>>>3); 269 // If the offset is beyond the data already then the minimum of the 270 // current offset and maxOffset must be maxOffset. 271 if(next >= data.length) { 272 return maxOffset; 273 } 274 int end = base + (maxOffset>>>3); 275 if(end == data.length) { // Prevents out of bounds exception below 276 end--; 277 } 278 int extra = bitOffset & 0x7; 279 280 int testbyte; 281 282 if((data[next] & (0x80 >>> extra)) != 0) { // look for "0" 283 testbyte = ~(data[next]) & (0xff >>> extra); 284 while (next < end) { 285 if (testbyte != 0) { 286 break; 287 } 288 testbyte = ~(data[++next]) & 0xff; 289 } 290 } else { // look for "1" 291 if ((testbyte = (data[next] & (0xff >>> extra))) != 0) { 292 bitOffset = (next-base)*8 + byteTable[testbyte]; 293 return ((bitOffset < maxOffset) ? bitOffset : maxOffset); 294 } 295 while (next < end) { 296 if ((testbyte = data[++next]&0xff) != 0) { 297 // "1" is in current byte 298 bitOffset = (next-base)*8 + byteTable[testbyte]; 299 return ((bitOffset < maxOffset) ? bitOffset : maxOffset); 300 } 301 } 302 } 303 bitOffset = (next-base)*8 + byteTable[testbyte]; 304 return ((bitOffset < maxOffset) ? bitOffset : maxOffset); 305 } 306 307 /** 308 * Initialize bit buffer machinery. 309 */ 310 public void initBitBuf() 311 { 312 ndex = 0; 313 bits = 0x00000000; 314 } 315 316 /** 317 * Get code for run and add to compressed bitstream. 318 */ 319 public int add1DBits(byte[] buf, 320 int where, // byte offs 321 int count, // #pixels in run 322 int color) // color of run 323 { 324 int sixtyfours; 325 int mask; 326 int len = where; 327 328 sixtyfours = count >>> 6; // count / 64; 329 count = count & 0x3f; // count % 64 330 if (sixtyfours != 0) { 331 for ( ; sixtyfours > 40; sixtyfours -= 40) { 332 mask = makeupCodes[color][40]; 333 bits |= (mask & 0xfff80000) >>> ndex; 334 ndex += (mask & 0x0000ffff); 335 while (ndex > 7) { 336 buf[len++] = (byte)(bits >>> 24); 337 bits <<= 8; 338 ndex -= 8; 339 } 340 } 341 342 mask = makeupCodes[color][sixtyfours]; 343 bits |= (mask & 0xfff80000) >>> ndex; 344 ndex += (mask & 0x0000ffff); 345 while (ndex > 7) { 346 buf[len++] = (byte)(bits >>> 24); 347 bits <<= 8; 348 ndex -= 8; 349 } 350 } 351 352 mask = termCodes[color][count]; 353 bits |= (mask & 0xfff80000) >>> ndex; 354 ndex += (mask & 0x0000ffff); 355 while (ndex > 7) { 356 buf[len++] = (byte)(bits >>> 24); 357 bits <<= 8; 358 ndex -= 8; 359 } 360 361 return(len - where); 362 } 363 364 /** 365 * Place entry from mode table into compressed bitstream. 366 */ 367 public int add2DBits(byte[] buf, // compressed buffer 368 int where, // byte offset into compressed buffer 369 int[][] mode, // 2-D mode to be encoded 370 int entry) // mode entry (0 unless vertical) 371 { 372 int mask; 373 int len = where; 374 int color = 0; 375 376 mask = mode[color][entry]; 377 bits |= (mask & 0xfff80000) >>> ndex; 378 ndex += (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 * Add an End-of-Line (EOL == 0x001) to the compressed bitstream 390 * with optional byte alignment. 391 */ 392 public int addEOL(boolean is1DMode,// 1D encoding 393 boolean addFill, // byte aligned EOLs 394 boolean add1, // add1 ? EOL+1 : EOL+0 395 byte[] buf, // compressed buffer address 396 int where) // current byte offset into buffer 397 { 398 int len = where; 399 400 // 401 // Add zero-valued fill bits such that the EOL is aligned as 402 // 403 // xxxx 0000 0000 0001 404 // 405 if(addFill) { 406 // 407 // Simply increment the bit count. No need to feed bits into 408 // the output buffer at this point as there are at most 7 bits 409 // in the bit buffer, at most 7 are added here, and at most 410 // 13 below making the total 7+7+13 = 27 before the bit feed 411 // at the end of this routine. 412 // 413 ndex += ((ndex <= 4) ? 4 - ndex : 12 - ndex); 414 } 415 416 // 417 // Write EOL into buffer 418 // 419 if(is1DMode) { 420 bits |= 0x00100000 >>> ndex; 421 ndex += 12; 422 } else { 423 bits |= (add1 ? 0x00180000 : 0x00100000) >>> ndex; 424 ndex += 13; 425 } 426 427 while (ndex > 7) { 428 buf[len++] = (byte)(bits >>> 24); 429 bits <<= 8; 430 ndex -= 8; 431 } 432 433 return(len - where); 434 } 435 436 /** 437 * Add an End-of-Facsimile-Block (EOFB == 0x001001) to the compressed 438 * bitstream. 439 */ 440 public int addEOFB(byte[] buf, // compressed buffer 441 int where) // byte offset into compressed buffer 442 { 443 int len = where; 444 445 // 446 // eofb code 447 // 448 bits |= 0x00100100 >>> ndex; 449 450 // 451 // eofb code length 452 // 453 ndex += 24; 454 455 // 456 // flush all pending bits 457 // 458 while(ndex > 0) { 459 buf[len++] = (byte)(bits >>> 24); 460 bits <<= 8; 461 ndex -= 8; 462 } 463 464 return(len - where); 465 } 466 467 /** 468 * One-dimensionally encode a row of data using CCITT Huffman compression. 469 * The bit buffer should be initialized as required before invoking this 470 * method and should be flushed after the method returns. The fill order 471 * is always highest-order to lowest-order bit so the calling routine 472 * should handle bit inversion. 473 */ 474 public int encode1D(byte[] data, 475 int rowOffset, 476 int colOffset, 477 int rowLength, 478 byte[] compData, 479 int compOffset) { 480 int lineAddr = rowOffset; 481 int bitIndex = colOffset; 482 483 int last = bitIndex + rowLength; 484 int outIndex = compOffset; 485 486 // 487 // Is first pixel black 488 // 489 int testbit = 490 ((data[lineAddr + (bitIndex>>>3)]&0xff) >>> 491 (7-(bitIndex & 0x7))) & 0x1; 492 int currentColor = BLACK; 493 if (testbit != 0) { 494 outIndex += add1DBits(compData, outIndex, 0, WHITE); 495 } else { 496 currentColor = WHITE; 497 } 498 499 // 500 // Run-length encode line 501 // 502 while (bitIndex < last) { 503 int bitCount = 504 nextState(data, lineAddr, bitIndex, last) - bitIndex; 505 outIndex += 506 add1DBits(compData, outIndex, bitCount, currentColor); 507 bitIndex += bitCount; 508 currentColor ^= 0x00000001; 509 } 510 511 return outIndex - compOffset; 512 } 513} 514