001: /*
002: * $RCSfile: TIFFFaxEncoder.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.2 $
009: * $Date: 2005/09/13 17:52:33 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.codecimpl;
013:
014: class TIFFFaxEncoder {
015:
016: /**
017: * The CCITT numerical definition of white.
018: */
019: private static final int WHITE = 0;
020:
021: /**
022: * The CCITT numerical definition of black.
023: */
024: private static final int BLACK = 1;
025:
026: // --- Begin tables for CCITT compression ---
027:
028: private static byte[] byteTable = new byte[] { 8, 7, 6, 6, 5, 5, 5,
029: 5, 4, 4, 4, 4, 4, 4, 4, 4, // 0 to 15
030: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16 to 31
031: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 32 to 47
032: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 48 to 63
033: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 to 79
034: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 to 95
035: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 to 111
036: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 112 to 127
037: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 to 143
038: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144 to 159
039: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 to 175
040: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176 to 191
041: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 to 207
042: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208 to 223
043: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224 to 239
044: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240 to 255
045: };
046:
047: /**
048: * Terminating codes for black runs.
049: */
050: private static int[] termCodesBlack = new int[] {
051: /* 0 0x0000 */0x0dc0000a, 0x40000003, 0xc0000002, 0x80000002,
052: /* 4 0x0004 */0x60000003, 0x30000004, 0x20000004, 0x18000005,
053: /* 8 0x0008 */0x14000006, 0x10000006, 0x08000007, 0x0a000007,
054: /* 12 0x000c */0x0e000007, 0x04000008, 0x07000008, 0x0c000009,
055: /* 16 0x0010 */0x05c0000a, 0x0600000a, 0x0200000a, 0x0ce0000b,
056: /* 20 0x0014 */0x0d00000b, 0x0d80000b, 0x06e0000b, 0x0500000b,
057: /* 24 0x0018 */0x02e0000b, 0x0300000b, 0x0ca0000c, 0x0cb0000c,
058: /* 28 0x001c */0x0cc0000c, 0x0cd0000c, 0x0680000c, 0x0690000c,
059: /* 32 0x0020 */0x06a0000c, 0x06b0000c, 0x0d20000c, 0x0d30000c,
060: /* 36 0x0024 */0x0d40000c, 0x0d50000c, 0x0d60000c, 0x0d70000c,
061: /* 40 0x0028 */0x06c0000c, 0x06d0000c, 0x0da0000c, 0x0db0000c,
062: /* 44 0x002c */0x0540000c, 0x0550000c, 0x0560000c, 0x0570000c,
063: /* 48 0x0030 */0x0640000c, 0x0650000c, 0x0520000c, 0x0530000c,
064: /* 52 0x0034 */0x0240000c, 0x0370000c, 0x0380000c, 0x0270000c,
065: /* 56 0x0038 */0x0280000c, 0x0580000c, 0x0590000c, 0x02b0000c,
066: /* 60 0x003c */0x02c0000c, 0x05a0000c, 0x0660000c, 0x0670000c };
067:
068: /**
069: * Terminating codes for white runs.
070: */
071: private static int[] termCodesWhite = new int[] {
072: /* 0 0x0000 */0x35000008, 0x1c000006, 0x70000004, 0x80000004,
073: /* 4 0x0004 */0xb0000004, 0xc0000004, 0xe0000004, 0xf0000004,
074: /* 8 0x0008 */0x98000005, 0xa0000005, 0x38000005, 0x40000005,
075: /* 12 0x000c */0x20000006, 0x0c000006, 0xd0000006, 0xd4000006,
076: /* 16 0x0010 */0xa8000006, 0xac000006, 0x4e000007, 0x18000007,
077: /* 20 0x0014 */0x10000007, 0x2e000007, 0x06000007, 0x08000007,
078: /* 24 0x0018 */0x50000007, 0x56000007, 0x26000007, 0x48000007,
079: /* 28 0x001c */0x30000007, 0x02000008, 0x03000008, 0x1a000008,
080: /* 32 0x0020 */0x1b000008, 0x12000008, 0x13000008, 0x14000008,
081: /* 36 0x0024 */0x15000008, 0x16000008, 0x17000008, 0x28000008,
082: /* 40 0x0028 */0x29000008, 0x2a000008, 0x2b000008, 0x2c000008,
083: /* 44 0x002c */0x2d000008, 0x04000008, 0x05000008, 0x0a000008,
084: /* 48 0x0030 */0x0b000008, 0x52000008, 0x53000008, 0x54000008,
085: /* 52 0x0034 */0x55000008, 0x24000008, 0x25000008, 0x58000008,
086: /* 56 0x0038 */0x59000008, 0x5a000008, 0x5b000008, 0x4a000008,
087: /* 60 0x003c */0x4b000008, 0x32000008, 0x33000008, 0x34000008 };
088:
089: /**
090: * Make-up codes for black runs.
091: */
092: private static int[] makeupCodesBlack = new int[] {
093: /* 0 0x0000 */0x00000000, 0x03c0000a, 0x0c80000c, 0x0c90000c,
094: /* 4 0x0004 */0x05b0000c, 0x0330000c, 0x0340000c, 0x0350000c,
095: /* 8 0x0008 */0x0360000d, 0x0368000d, 0x0250000d, 0x0258000d,
096: /* 12 0x000c */0x0260000d, 0x0268000d, 0x0390000d, 0x0398000d,
097: /* 16 0x0010 */0x03a0000d, 0x03a8000d, 0x03b0000d, 0x03b8000d,
098: /* 20 0x0014 */0x0290000d, 0x0298000d, 0x02a0000d, 0x02a8000d,
099: /* 24 0x0018 */0x02d0000d, 0x02d8000d, 0x0320000d, 0x0328000d,
100: /* 28 0x001c */0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c,
101: /* 32 0x0020 */0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c,
102: /* 36 0x0024 */0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c,
103: /* 40 0x0028 */0x01f0000c, 0x00000000, 0x00000000, 0x00000000,
104: /* 44 0x002c */0x00000000, 0x00000000, 0x00000000, 0x00000000,
105: /* 48 0x0030 */0x00000000, 0x00000000, 0x00000000, 0x00000000,
106: /* 52 0x0034 */0x00000000, 0x00000000, 0x00000000, 0x00000000,
107: /* 56 0x0038 */0x00000000, 0x00000000, 0x00000000, 0x00000000 };
108:
109: /**
110: * Make-up codes for white runs.
111: */
112: private static int[] makeupCodesWhite = new int[] {
113: /* 0 0x0000 */0x00000000, 0xd8000005, 0x90000005, 0x5c000006,
114: /* 4 0x0004 */0x6e000007, 0x36000008, 0x37000008, 0x64000008,
115: /* 8 0x0008 */0x65000008, 0x68000008, 0x67000008, 0x66000009,
116: /* 12 0x000c */0x66800009, 0x69000009, 0x69800009, 0x6a000009,
117: /* 16 0x0010 */0x6a800009, 0x6b000009, 0x6b800009, 0x6c000009,
118: /* 20 0x0014 */0x6c800009, 0x6d000009, 0x6d800009, 0x4c000009,
119: /* 24 0x0018 */0x4c800009, 0x4d000009, 0x60000006, 0x4d800009,
120: /* 28 0x001c */0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c,
121: /* 32 0x0020 */0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c,
122: /* 36 0x0024 */0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c,
123: /* 40 0x0028 */0x01f0000c, 0x00000000, 0x00000000, 0x00000000,
124: /* 44 0x002c */0x00000000, 0x00000000, 0x00000000, 0x00000000,
125: /* 48 0x0030 */0x00000000, 0x00000000, 0x00000000, 0x00000000,
126: /* 52 0x0034 */0x00000000, 0x00000000, 0x00000000, 0x00000000,
127: /* 56 0x0038 */0x00000000, 0x00000000, 0x00000000, 0x00000000 };
128:
129: /**
130: * Pass mode table.
131: */
132: private static int[] passMode = new int[] { 0x10000004 // 0001
133: };
134:
135: /**
136: * Vertical mode table.
137: */
138: private static int[] vertMode = new int[] { 0x06000007, // 0000011
139: 0x0c000006, // 000011
140: 0x60000003, // 011
141: 0x80000001, // 1
142: 0x40000003, // 010
143: 0x08000006, // 000010
144: 0x04000007 // 0000010
145: };
146:
147: /**
148: * Horizontal mode table.
149: */
150: private static int[] horzMode = new int[] { 0x20000003 // 001
151: };
152:
153: /**
154: * Black and white terminating code table.
155: */
156: private static int[][] termCodes = new int[][] { termCodesWhite,
157: termCodesBlack };
158:
159: /**
160: * Black and white make-up code table.
161: */
162: private static int[][] makeupCodes = new int[][] {
163: makeupCodesWhite, makeupCodesBlack };
164:
165: /**
166: * Black and white pass mode table.
167: */
168: private static int[][] pass = new int[][] { passMode, passMode };
169:
170: /**
171: * Black and white vertical mode table.
172: */
173: private static int[][] vert = new int[][] { vertMode, vertMode };
174:
175: /**
176: * Black and white horizontal mode table.
177: */
178: private static int[][] horz = new int[][] { horzMode, horzMode };
179:
180: // --- End tables for CCITT compression ---
181:
182: /**
183: * Whether bits are inserted in reverse order (TIFF FillOrder 2).
184: */
185: private boolean inverseFill;
186:
187: /**
188: * Output bit buffer.
189: */
190: private int bits;
191:
192: /**
193: * Number of bits in the output bit buffer.
194: */
195: private int ndex;
196:
197: /**
198: * Constructs a <code>TIFFFaxEncoder</code> for CCITT bilevel encoding.
199: *
200: * @param inverseFill Whether bits are inserted in reverse order
201: * (TIFF FillOrder 2).
202: */
203: TIFFFaxEncoder(boolean inverseFill) {
204: this .inverseFill = inverseFill;
205: }
206:
207: /**
208: * Return min of <code>maxOffset</code> or offset of first pixel
209: * different from pixel at <code>bitOffset</code>.
210: */
211: private int nextState(byte[] data, int base, int bitOffset,
212: int maxOffset) {
213: if (data == null) {
214: return maxOffset;
215: }
216:
217: int next = base + (bitOffset >>> 3);
218: // If the offset is beyond the data already then the minimum of the
219: // current offset and maxOffset must be maxOffset.
220: if (next >= data.length) {
221: return maxOffset;
222: }
223: int end = base + (maxOffset >>> 3);
224: if (end == data.length) { // Prevents out of bounds exception below
225: end--;
226: }
227: int extra = bitOffset & 0x7;
228:
229: int testbyte;
230:
231: if ((data[next] & (0x80 >>> extra)) != 0) { // look for "0"
232: testbyte = ~(data[next]) & (0xff >>> extra);
233: while (next < end) {
234: if (testbyte != 0) {
235: break;
236: }
237: testbyte = ~(data[++next]) & 0xff;
238: }
239: } else { // look for "1"
240: if ((testbyte = (data[next] & (0xff >>> extra))) != 0) {
241: bitOffset = (next - base) * 8 + byteTable[testbyte];
242: return ((bitOffset < maxOffset) ? bitOffset : maxOffset);
243: }
244: while (next < end) {
245: if ((testbyte = data[++next] & 0xff) != 0) {
246: // "1" is in current byte
247: bitOffset = (next - base) * 8 + byteTable[testbyte];
248: return ((bitOffset < maxOffset) ? bitOffset
249: : maxOffset);
250: }
251: }
252: }
253: bitOffset = (next - base) * 8 + byteTable[testbyte];
254: return ((bitOffset < maxOffset) ? bitOffset : maxOffset);
255: }
256:
257: /**
258: * Initialize bit buffer machinery.
259: */
260: private void initBitBuf() {
261: ndex = 0;
262: bits = 0x00000000;
263: }
264:
265: /**
266: * Get code for run and add to compressed bitstream.
267: */
268: private int add1DBits(byte[] buf, int where, // byte offs
269: int count, // #pixels in run
270: int color) // color of run
271: {
272: int sixtyfours;
273: int mask;
274: int len = where;
275:
276: sixtyfours = count >>> 6; // count / 64;
277: count = count & 0x3f; // count % 64
278: if (sixtyfours != 0) {
279: for (; sixtyfours > 40; sixtyfours -= 40) {
280: mask = makeupCodes[color][40];
281: bits |= (mask & 0xfff80000) >>> ndex;
282: ndex += (int) (mask & 0x0000ffff);
283: while (ndex > 7) {
284: buf[len++] = (byte) (bits >>> 24);
285: bits <<= 8;
286: ndex -= 8;
287: }
288: }
289:
290: mask = makeupCodes[color][sixtyfours];
291: bits |= (mask & 0xfff80000) >>> ndex;
292: ndex += (int) (mask & 0x0000ffff);
293: while (ndex > 7) {
294: buf[len++] = (byte) (bits >>> 24);
295: bits <<= 8;
296: ndex -= 8;
297: }
298: }
299:
300: mask = termCodes[color][count];
301: bits |= (mask & 0xfff80000) >>> ndex;
302: ndex += (int) (mask & 0x0000ffff);
303: while (ndex > 7) {
304: buf[len++] = (byte) (bits >>> 24);
305: bits <<= 8;
306: ndex -= 8;
307: }
308:
309: return (len - where);
310: }
311:
312: /**
313: * Place entry from mode table into compressed bitstream.
314: */
315: private int add2DBits(byte[] buf, // compressed buffer
316: int where, // byte offset into compressed buffer
317: int[][] mode, // 2-D mode to be encoded
318: int entry) // mode entry (0 unless vertical)
319: {
320: int mask;
321: int len = where;
322: int color = 0;
323:
324: mask = mode[color][entry];
325: bits |= (mask & 0xfff80000) >>> ndex;
326: ndex += (int) (mask & 0x0000ffff);
327: while (ndex > 7) {
328: buf[len++] = (byte) (bits >>> 24);
329: bits <<= 8;
330: ndex -= 8;
331: }
332:
333: return (len - where);
334: }
335:
336: /**
337: * Add an End-of-Line (EOL == 0x001) to the compressed bitstream
338: * with optional byte alignment.
339: */
340: private int addEOL(boolean is1DMode,// 1D encoding
341: boolean addFill, // byte aligned EOLs
342: boolean add1, // add1 ? EOL+1 : EOL+0
343: byte[] buf, // compressed buffer address
344: int where) // current byte offset into buffer
345: {
346: int len = where;
347:
348: //
349: // Add zero-valued fill bits such that the EOL is aligned as
350: //
351: // xxxx 0000 0000 0001
352: //
353: if (addFill) {
354: //
355: // Simply increment the bit count. No need to feed bits into
356: // the output buffer at this point as there are at most 7 bits
357: // in the bit buffer, at most 7 are added here, and at most
358: // 13 below making the total 7+7+13 = 27 before the bit feed
359: // at the end of this routine.
360: //
361: ndex += ((ndex <= 4) ? 4 - ndex : 12 - ndex);
362: }
363:
364: //
365: // Write EOL into buffer
366: //
367: if (is1DMode) {
368: bits |= 0x00100000 >>> ndex;
369: ndex += 12;
370: } else {
371: bits |= (add1 ? 0x00180000 : 0x00100000) >>> ndex;
372: ndex += 13;
373: }
374:
375: while (ndex > 7) {
376: buf[len++] = (byte) (bits >>> 24);
377: bits <<= 8;
378: ndex -= 8;
379: }
380:
381: return (len - where);
382: }
383:
384: /**
385: * Add an End-of-Facsimile-Block (EOFB == 0x001001) to the compressed
386: * bitstream.
387: */
388: private int addEOFB(byte[] buf, // compressed buffer
389: int where) // byte offset into compressed buffer
390: {
391: int len = where;
392:
393: //
394: // eofb code
395: //
396: bits |= 0x00100100 >>> ndex;
397:
398: //
399: // eofb code length
400: //
401: ndex += 24;
402:
403: //
404: // flush all pending bits
405: //
406: while (ndex > 0) {
407: buf[len++] = (byte) (bits >>> 24);
408: bits <<= 8;
409: ndex -= 8;
410: }
411:
412: return (len - where);
413: }
414:
415: /**
416: * One-dimensionally encode a row of data using CCITT Huffman compression.
417: * The bit buffer should be initialized as required before invoking this
418: * method and should be flushed after the method returns. The fill order
419: * is always highest-order to lowest-order bit so the calling routine
420: * should handle bit inversion.
421: */
422: private int encode1D(byte[] data, int rowOffset, int colOffset,
423: int rowLength, byte[] compData, int compOffset) {
424: int lineAddr = rowOffset;
425: int bitIndex = colOffset;
426:
427: int last = bitIndex + rowLength;
428: int outIndex = compOffset;
429:
430: //
431: // Is first pixel black
432: //
433: int testbit = ((data[lineAddr + (bitIndex >>> 3)] & 0xff) >>> (7 - (bitIndex & 0x7))) & 0x1;
434: int currentColor = BLACK;
435: if (testbit != 0) {
436: outIndex += add1DBits(compData, outIndex, 0, WHITE);
437: } else {
438: currentColor = WHITE;
439: }
440:
441: //
442: // Run-length encode line
443: //
444: while (bitIndex < last) {
445: int bitCount = nextState(data, lineAddr, bitIndex, last)
446: - bitIndex;
447: outIndex += add1DBits(compData, outIndex, bitCount,
448: currentColor);
449: bitIndex += bitCount;
450: currentColor ^= 0x00000001;
451: }
452:
453: return outIndex - compOffset;
454: }
455:
456: /**
457: * Encode a row of data using Modified Huffman Compression also known as
458: * CCITT RLE (Run Lenth Encoding).
459: *
460: * @param data The row of data to compress.
461: * @param rowOffset Starting index in <code>data</code>.
462: * @param colOffset Bit offset within first <code>data[rowOffset]</code>.
463: * @param rowLength Number of bits in the row.
464: * @param compData The compressed data.
465: *
466: * @return The number of bytes saved in the compressed data array.
467: */
468: synchronized int encodeRLE(byte[] data, int rowOffset,
469: int colOffset, int rowLength, byte[] compData) {
470: //
471: // Initialize bit buffer machinery.
472: //
473: initBitBuf();
474:
475: //
476: // Run-length encode line.
477: //
478: int outIndex = encode1D(data, rowOffset, colOffset, rowLength,
479: compData, 0);
480:
481: //
482: // Flush pending bits
483: //
484: while (ndex > 0) {
485: compData[outIndex++] = (byte) (bits >>> 24);
486: bits <<= 8;
487: ndex -= 8;
488: }
489:
490: //
491: // Flip the bytes if inverse fill was requested.
492: //
493: if (inverseFill) {
494: byte[] flipTable = TIFFFaxDecoder.flipTable;
495: for (int i = 0; i < outIndex; i++) {
496: compData[i] = flipTable[compData[i] & 0xff];
497: }
498: }
499:
500: return outIndex;
501: }
502:
503: /**
504: * Encode a buffer of data using CCITT T.4 Compression also known as
505: * Group 3 facsimile compression.
506: *
507: * @param is1DMode Whether to perform one-dimensional encoding.
508: * @param isEOLAligned Whether EOL bit sequences should be padded.
509: * @param data The row of data to compress.
510: * @param lineStride Byte step between the same sample in different rows.
511: * @param colOffset Bit offset within first <code>data[rowOffset]</code>.
512: * @param width Number of bits in the row.
513: * @param height Number of rows in the buffer.
514: * @param compData The compressed data.
515: *
516: * @return The number of bytes saved in the compressed data array.
517: */
518: synchronized int encodeT4(boolean is1DMode, boolean isEOLAligned,
519: byte[] data, int lineStride, int colOffset, int width,
520: int height, byte[] compData) {
521: //
522: // ao, a1, a2 are bit indices in the current line
523: // b1 and b2 are bit indices in the reference line (line above)
524: // color is the current color (WHITE or BLACK)
525: //
526: byte[] refData = data;
527: int lineAddr = 0;
528: int outIndex = 0;
529:
530: initBitBuf();
531:
532: int KParameter = 2;
533: for (int numRows = 0; numRows < height; numRows++) {
534: if (is1DMode || (numRows % KParameter) == 0) { // 1D encoding
535: // Write EOL+1
536: outIndex += addEOL(is1DMode, isEOLAligned, true,
537: compData, outIndex);
538:
539: // Encode row
540: outIndex += encode1D(data, lineAddr, colOffset, width,
541: compData, outIndex);
542: } else { // 2D encoding.
543: // Write EOL+0
544: outIndex += addEOL(is1DMode, isEOLAligned, false,
545: compData, outIndex);
546:
547: // Set reference to previous line
548: int refAddr = lineAddr - lineStride;
549:
550: // Encode row
551: int a0 = colOffset;
552: int last = a0 + width;
553:
554: int testbit = ((data[lineAddr + (a0 >>> 3)] & 0xff) >>> (7 - (a0 & 0x7))) & 0x1;
555: int a1 = testbit != 0 ? a0 : nextState(data, lineAddr,
556: a0, last);
557:
558: testbit = ((refData[refAddr + (a0 >>> 3)] & 0xff) >>> (7 - (a0 & 0x7))) & 0x1;
559: int b1 = testbit != 0 ? a0 : nextState(refData,
560: refAddr, a0, last);
561:
562: // The current color is set to WHITE at line start
563: int color = WHITE;
564:
565: while (true) {
566: int b2 = nextState(refData, refAddr, b1, last);
567: if (b2 < a1) { // pass mode
568: outIndex += add2DBits(compData, outIndex, pass,
569: 0);
570: a0 = b2;
571: } else {
572: int tmp = b1 - a1 + 3;
573: if ((tmp <= 6) && (tmp >= 0)) { // vertical mode
574: outIndex += add2DBits(compData, outIndex,
575: vert, tmp);
576: a0 = a1;
577: } else { // horizontal mode
578: int a2 = nextState(data, lineAddr, a1, last);
579: outIndex += add2DBits(compData, outIndex,
580: horz, 0);
581: outIndex += add1DBits(compData, outIndex,
582: a1 - a0, color);
583: outIndex += add1DBits(compData, outIndex,
584: a2 - a1, color ^ 1);
585: a0 = a2;
586: }
587: }
588: if (a0 >= last) {
589: break;
590: }
591: color = ((data[lineAddr + (a0 >>> 3)] & 0xff) >>> (7 - (a0 & 0x7))) & 0x1;
592: a1 = nextState(data, lineAddr, a0, last);
593: b1 = nextState(refData, refAddr, a0, last);
594: testbit = ((refData[refAddr + (b1 >>> 3)] & 0xff) >>> (7 - (b1 & 0x7))) & 0x1;
595: if (testbit == color) {
596: b1 = nextState(refData, refAddr, b1, last);
597: }
598: }
599: }
600:
601: // Skip to next line.
602: lineAddr += lineStride;
603: }
604:
605: for (int i = 0; i < 6; i++) {
606: outIndex += addEOL(is1DMode, isEOLAligned, true, compData,
607: outIndex);
608: }
609:
610: //
611: // flush all pending bits
612: //
613: while (ndex > 0) {
614: compData[outIndex++] = (byte) (bits >>> 24);
615: bits <<= 8;
616: ndex -= 8;
617: }
618:
619: // Flip the bytes if inverse fill was requested.
620: if (inverseFill) {
621: for (int i = 0; i < outIndex; i++) {
622: compData[i] = TIFFFaxDecoder.flipTable[compData[i] & 0xff];
623: }
624: }
625:
626: return outIndex;
627: }
628:
629: /**
630: * Encode a buffer of data using CCITT T.6 Compression also known as
631: * Group 4 facsimile compression.
632: *
633: * @param data The row of data to compress.
634: * @param lineStride Byte step between the same sample in different rows.
635: * @param colOffset Bit offset within first <code>data[rowOffset]</code>.
636: * @param width Number of bits in the row.
637: * @param height Number of rows in the buffer.
638: * @param compData The compressed data.
639: *
640: * @return The number of bytes saved in the compressed data array.
641: */
642: public synchronized int encodeT6(byte[] data, int lineStride,
643: int colOffset, int width, int height, byte[] compData) {
644: //
645: // ao, a1, a2 are bit indices in the current line
646: // b1 and b2 are bit indices in the reference line (line above)
647: // color is the current color (WHITE or BLACK)
648: //
649: byte[] refData = null;
650: int refAddr = 0;
651: int lineAddr = 0;
652: int outIndex = 0;
653:
654: initBitBuf();
655:
656: //
657: // Iterate over all lines
658: //
659: while (height-- != 0) {
660: int a0 = colOffset;
661: int last = a0 + width;
662:
663: int testbit = ((data[lineAddr + (a0 >>> 3)] & 0xff) >>> (7 - (a0 & 0x7))) & 0x1;
664: int a1 = testbit != 0 ? a0 : nextState(data, lineAddr, a0,
665: last);
666:
667: testbit = refData == null ? 0 : ((refData[refAddr
668: + (a0 >>> 3)] & 0xff) >>> (7 - (a0 & 0x7))) & 0x1;
669: int b1 = testbit != 0 ? a0 : nextState(refData, refAddr,
670: a0, last);
671:
672: //
673: // The current color is set to WHITE at line start
674: //
675: int color = WHITE;
676:
677: while (true) {
678: int b2 = nextState(refData, refAddr, b1, last);
679: if (b2 < a1) { // pass mode
680: outIndex += add2DBits(compData, outIndex, pass, 0);
681: a0 = b2;
682: } else {
683: int tmp = b1 - a1 + 3;
684: if ((tmp <= 6) && (tmp >= 0)) { // vertical mode
685: outIndex += add2DBits(compData, outIndex, vert,
686: tmp);
687: a0 = a1;
688: } else { // horizontal mode
689: int a2 = nextState(data, lineAddr, a1, last);
690: outIndex += add2DBits(compData, outIndex, horz,
691: 0);
692: outIndex += add1DBits(compData, outIndex, a1
693: - a0, color);
694: outIndex += add1DBits(compData, outIndex, a2
695: - a1, color ^ 1);
696: a0 = a2;
697: }
698: }
699: if (a0 >= last) {
700: break;
701: }
702: color = ((data[lineAddr + (a0 >>> 3)] & 0xff) >>> (7 - (a0 & 0x7))) & 0x1;
703: a1 = nextState(data, lineAddr, a0, last);
704: b1 = nextState(refData, refAddr, a0, last);
705: testbit = refData == null ? 0
706: : ((refData[refAddr + (b1 >>> 3)] & 0xff) >>> (7 - (b1 & 0x7))) & 0x1;
707: if (testbit == color) {
708: b1 = nextState(refData, refAddr, b1, last);
709: }
710: }
711:
712: refData = data;
713: refAddr = lineAddr;
714: lineAddr += lineStride;
715:
716: } // End while(height--)
717:
718: //
719: // append eofb
720: //
721: outIndex += addEOFB(compData, outIndex);
722:
723: // Flip the bytes if inverse fill was requested.
724: if (inverseFill) {
725: for (int i = 0; i < outIndex; i++) {
726: compData[i] = TIFFFaxDecoder.flipTable[compData[i] & 0xff];
727: }
728: }
729:
730: return outIndex;
731: }
732: }
|