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