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}