001/*
002 * $Id: CCITTG4Encoder.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf.codec;
045
046import com.itextpdf.text.pdf.ByteBuffer;
047
048/**
049 * Encodes data in the CCITT G4 FAX format.
050 */
051public class CCITTG4Encoder {
052    private int rowbytes;
053    private int rowpixels;
054    private int bit = 8;
055    private int data;
056    private byte[] refline;
057    private ByteBuffer outBuf = new ByteBuffer(1024);
058    private byte[] dataBp;
059    private int offsetData;
060    private int sizeData;
061    
062    /**
063     * Creates a new encoder.
064     * @param width the line width
065     */    
066    public CCITTG4Encoder(int width) {
067        rowpixels = width;
068        rowbytes = (rowpixels + 7) / 8;
069        refline = new byte[rowbytes];
070    }
071    
072    /**
073     * Encodes a number of lines.
074     * @param data the data to be encoded
075     * @param offset the offset into the data
076     * @param size the size of the data to be encoded
077     */    
078    public void fax4Encode(byte[] data, int offset, int size) {
079        dataBp = data;
080        offsetData = offset;
081        sizeData = size;
082        while (sizeData > 0) {
083            Fax3Encode2DRow();
084            System.arraycopy(dataBp, offsetData, refline, 0, rowbytes);
085            offsetData += rowbytes;
086            sizeData -= rowbytes;
087        }
088    }
089    
090
091    /**
092     * Encodes a full image.
093     * @param data the data to encode
094     * @param width the image width
095     * @param height the image height
096     * @return the encoded image
097     */    
098    public static byte[] compress(byte[] data, int width, int height) {
099        CCITTG4Encoder g4 = new CCITTG4Encoder(width);
100        g4.fax4Encode(data, 0, g4.rowbytes * height);
101        return g4.close();
102    }
103    
104    /**
105     * Encodes a number of lines.
106     * @param data the data to be encoded
107     * @param height the number of lines to encode
108     */    
109    public void fax4Encode(byte[] data, int height) {
110        fax4Encode(data, 0, rowbytes * height);
111    }
112
113    private void putcode(int[] table) {
114        putBits(table[CODE], table[LENGTH]);
115    }
116    
117    private void putspan(int span, int[][] tab) {
118        int code, length;
119        
120        while (span >= 2624) {
121            int[] te = tab[63 + (2560>>6)];
122            code = te[CODE];
123            length = te[LENGTH];
124            putBits(code, length);
125            span -= te[RUNLEN];
126        }
127        if (span >= 64) {
128            int[] te = tab[63 + (span>>6)];
129            code = te[CODE];
130            length = te[LENGTH];
131            putBits(code, length);
132            span -= te[RUNLEN];
133        }
134        code = tab[span][CODE];
135        length = tab[span][LENGTH];
136        putBits(code, length);
137    }
138    
139    private void putBits(int bits, int length) {
140        while (length > bit) {
141            data |= bits >> (length - bit);
142            length -= bit;
143            outBuf.append((byte)data);
144            data = 0;
145            bit = 8;
146        }
147        data |= (bits & msbmask[length]) << (bit - length);
148        bit -= length;
149        if (bit == 0) {
150            outBuf.append((byte)data);
151            data = 0;
152            bit = 8;
153        }
154    }
155    
156    private void Fax3Encode2DRow() {
157        int a0 = 0;
158        int a1 = (pixel(dataBp, offsetData, 0) != 0 ? 0 : finddiff(dataBp, offsetData, 0, rowpixels, 0));
159        int b1 = (pixel(refline, 0, 0) != 0 ? 0 : finddiff(refline, 0, 0, rowpixels, 0));
160        int a2, b2;
161        
162        for (;;) {
163            b2 = finddiff2(refline, 0, b1, rowpixels, pixel(refline, 0,b1));
164            if (b2 >= a1) {
165                int d = b1 - a1;
166                if (!(-3 <= d && d <= 3)) {     /* horizontal mode */
167                    a2 = finddiff2(dataBp, offsetData, a1, rowpixels, pixel(dataBp, offsetData,a1));
168                    putcode(horizcode);
169                    if (a0+a1 == 0 || pixel(dataBp, offsetData, a0) == 0) {
170                        putspan(a1-a0, TIFFFaxWhiteCodes);
171                        putspan(a2-a1, TIFFFaxBlackCodes);
172                    } else {
173                        putspan(a1-a0, TIFFFaxBlackCodes);
174                        putspan(a2-a1, TIFFFaxWhiteCodes);
175                    }
176                    a0 = a2;
177                } else {                        /* vertical mode */
178                    putcode(vcodes[d+3]);
179                    a0 = a1;
180                }
181            } else {                            /* pass mode */
182                putcode(passcode);
183                a0 = b2;
184            }
185            if (a0 >= rowpixels)
186                break;
187            a1 = finddiff(dataBp, offsetData, a0, rowpixels, pixel(dataBp, offsetData,a0));
188            b1 = finddiff(refline, 0, a0, rowpixels, pixel(dataBp, offsetData,a0) ^ 1);
189            b1 = finddiff(refline, 0, b1, rowpixels, pixel(dataBp, offsetData,a0));
190        }
191    }
192    
193    private void Fax4PostEncode() {
194        putBits(EOL, 12);
195        putBits(EOL, 12);
196        if (bit != 8) {
197            outBuf.append((byte)data);
198            data = 0;
199            bit = 8;
200        }
201    }
202    
203    /**
204     * Closes the encoder and returns the encoded data.
205     * @return the encoded data
206     */    
207    public byte[] close() {
208        Fax4PostEncode();
209        return outBuf.toByteArray();
210    }
211    
212    private int pixel(byte[] data, int offset, int bit) {
213        if (bit >= rowpixels)
214            return 0;
215        return ((data[offset + (bit >> 3)] & 0xff) >> (7-((bit)&7))) & 1;
216    }
217    
218    private static int find1span(byte[] bp, int offset, int bs, int be) {
219        int bits = be - bs;
220        int n, span;
221        
222        int pos = offset + (bs >> 3);
223        /*
224         * Check partial byte on lhs.
225         */
226        if (bits > 0 && (n = (bs & 7)) != 0) {
227            span = oneruns[(bp[pos] << n) & 0xff];
228            if (span > 8-n)             /* table value too generous */
229                span = 8-n;
230            if (span > bits)    /* constrain span to bit range */
231                span = bits;
232            if (n+span < 8)             /* doesn't extend to edge of byte */
233                return span;
234            bits -= span;
235            pos++;
236        } else
237            span = 0;
238        /*
239         * Scan full bytes for all 1's.
240         */
241        while (bits >= 8) {
242            if (bp[pos] != -1)  /* end of run */
243                return (span + oneruns[bp[pos] & 0xff]);
244            span += 8;
245            bits -= 8;
246            pos++;
247        }
248        /*
249         * Check partial byte on rhs.
250         */
251        if (bits > 0) {
252            n = oneruns[bp[pos] & 0xff];
253            span += (n > bits ? bits : n);
254        }
255        return span;
256    }
257    
258    private static int find0span(byte[] bp, int offset, int bs, int be) {
259        int bits = be - bs;
260        int n, span;
261        
262        int pos = offset + (bs >> 3);
263        /*
264         * Check partial byte on lhs.
265         */
266        if (bits > 0 && (n = (bs & 7)) != 0) {
267            span = zeroruns[(bp[pos] << n) & 0xff];
268            if (span > 8-n)             /* table value too generous */
269                span = 8-n;
270            if (span > bits)    /* constrain span to bit range */
271                span = bits;
272            if (n+span < 8)             /* doesn't extend to edge of byte */
273                return span;
274            bits -= span;
275            pos++;
276        } else
277            span = 0;
278        /*
279         * Scan full bytes for all 1's.
280         */
281        while (bits >= 8) {
282            if (bp[pos] != 0)   /* end of run */
283                return (span + zeroruns[bp[pos] & 0xff]);
284            span += 8;
285            bits -= 8;
286            pos++;
287        }
288        /*
289         * Check partial byte on rhs.
290         */
291        if (bits > 0) {
292            n = zeroruns[bp[pos] & 0xff];
293            span += (n > bits ? bits : n);
294        }
295        return span;
296    }
297    
298    private static int finddiff(byte[] bp, int offset, int bs, int be, int color) {
299        return bs + (color != 0 ? find1span(bp, offset, bs, be) : find0span(bp, offset, bs, be));
300    }
301    
302    private static int finddiff2(byte[] bp, int offset, int bs, int be, int color) {
303        return bs < be ? finddiff(bp, offset, bs, be, color) : be;
304    }
305    
306    private static byte zeroruns[] = {
307        8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */
308        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */
309        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */
310        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */
311        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */
312        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */
313        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */
314        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */
315        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
316        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
317        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
318        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
319        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
320        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
321        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
322        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 - 0xff */
323    };
324    
325    private static byte oneruns[] = {
326        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */
327        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
328        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
329        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
330        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
331        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
332        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */
333        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
334        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */
335        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */
336        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */
337        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */
338        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */
339        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */
340        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */
341        4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8  /* 0xf0 - 0xff */
342    };
343
344    private static final int LENGTH = 0; /* bit length of g3 code */
345    private static final int CODE = 1;   /* g3 code */
346    private static final int RUNLEN = 2; /* run length in bits */
347
348    private static final int EOL = 0x001; /* EOL code value - 0000 0000 0000 1 */
349
350    /* status values returned instead of a run length */
351    private static final int G3CODE_EOL = -1;     /* NB: ACT_EOL - ACT_WRUNT */
352    private static final int G3CODE_INVALID = -2; /* NB: ACT_INVALID - ACT_WRUNT */
353    private static final int G3CODE_EOF = -3;     /* end of input data */
354    private static final int G3CODE_INCOMP = -4;  /* incomplete run code */
355
356    private int[][] TIFFFaxWhiteCodes = {
357        { 8, 0x35, 0 }, /* 0011 0101 */
358        { 6, 0x7, 1 },  /* 0001 11 */
359        { 4, 0x7, 2 },  /* 0111 */
360        { 4, 0x8, 3 },  /* 1000 */
361        { 4, 0xB, 4 },  /* 1011 */
362        { 4, 0xC, 5 },  /* 1100 */
363        { 4, 0xE, 6 },  /* 1110 */
364        { 4, 0xF, 7 },  /* 1111 */
365        { 5, 0x13, 8 }, /* 1001 1 */
366        { 5, 0x14, 9 }, /* 1010 0 */
367        { 5, 0x7, 10 }, /* 0011 1 */
368        { 5, 0x8, 11 }, /* 0100 0 */
369        { 6, 0x8, 12 }, /* 0010 00 */
370        { 6, 0x3, 13 }, /* 0000 11 */
371        { 6, 0x34, 14 },        /* 1101 00 */
372        { 6, 0x35, 15 },        /* 1101 01 */
373        { 6, 0x2A, 16 },        /* 1010 10 */
374        { 6, 0x2B, 17 },        /* 1010 11 */
375        { 7, 0x27, 18 },        /* 0100 111 */
376        { 7, 0xC, 19 }, /* 0001 100 */
377        { 7, 0x8, 20 }, /* 0001 000 */
378        { 7, 0x17, 21 },        /* 0010 111 */
379        { 7, 0x3, 22 }, /* 0000 011 */
380        { 7, 0x4, 23 }, /* 0000 100 */
381        { 7, 0x28, 24 },        /* 0101 000 */
382        { 7, 0x2B, 25 },        /* 0101 011 */
383        { 7, 0x13, 26 },        /* 0010 011 */
384        { 7, 0x24, 27 },        /* 0100 100 */
385        { 7, 0x18, 28 },        /* 0011 000 */
386        { 8, 0x2, 29 }, /* 0000 0010 */
387        { 8, 0x3, 30 }, /* 0000 0011 */
388        { 8, 0x1A, 31 },        /* 0001 1010 */
389        { 8, 0x1B, 32 },        /* 0001 1011 */
390        { 8, 0x12, 33 },        /* 0001 0010 */
391        { 8, 0x13, 34 },        /* 0001 0011 */
392        { 8, 0x14, 35 },        /* 0001 0100 */
393        { 8, 0x15, 36 },        /* 0001 0101 */
394        { 8, 0x16, 37 },        /* 0001 0110 */
395        { 8, 0x17, 38 },        /* 0001 0111 */
396        { 8, 0x28, 39 },        /* 0010 1000 */
397        { 8, 0x29, 40 },        /* 0010 1001 */
398        { 8, 0x2A, 41 },        /* 0010 1010 */
399        { 8, 0x2B, 42 },        /* 0010 1011 */
400        { 8, 0x2C, 43 },        /* 0010 1100 */
401        { 8, 0x2D, 44 },        /* 0010 1101 */
402        { 8, 0x4, 45 }, /* 0000 0100 */
403        { 8, 0x5, 46 }, /* 0000 0101 */
404        { 8, 0xA, 47 }, /* 0000 1010 */
405        { 8, 0xB, 48 }, /* 0000 1011 */
406        { 8, 0x52, 49 },        /* 0101 0010 */
407        { 8, 0x53, 50 },        /* 0101 0011 */
408        { 8, 0x54, 51 },        /* 0101 0100 */
409        { 8, 0x55, 52 },        /* 0101 0101 */
410        { 8, 0x24, 53 },        /* 0010 0100 */
411        { 8, 0x25, 54 },        /* 0010 0101 */
412        { 8, 0x58, 55 },        /* 0101 1000 */
413        { 8, 0x59, 56 },        /* 0101 1001 */
414        { 8, 0x5A, 57 },        /* 0101 1010 */
415        { 8, 0x5B, 58 },        /* 0101 1011 */
416        { 8, 0x4A, 59 },        /* 0100 1010 */
417        { 8, 0x4B, 60 },        /* 0100 1011 */
418        { 8, 0x32, 61 },        /* 0011 0010 */
419        { 8, 0x33, 62 },        /* 0011 0011 */
420        { 8, 0x34, 63 },        /* 0011 0100 */
421        { 5, 0x1B, 64 },        /* 1101 1 */
422        { 5, 0x12, 128 },       /* 1001 0 */
423        { 6, 0x17, 192 },       /* 0101 11 */
424        { 7, 0x37, 256 },       /* 0110 111 */
425        { 8, 0x36, 320 },       /* 0011 0110 */
426        { 8, 0x37, 384 },       /* 0011 0111 */
427        { 8, 0x64, 448 },       /* 0110 0100 */
428        { 8, 0x65, 512 },       /* 0110 0101 */
429        { 8, 0x68, 576 },       /* 0110 1000 */
430        { 8, 0x67, 640 },       /* 0110 0111 */
431        { 9, 0xCC, 704 },       /* 0110 0110 0 */
432        { 9, 0xCD, 768 },       /* 0110 0110 1 */
433        { 9, 0xD2, 832 },       /* 0110 1001 0 */
434        { 9, 0xD3, 896 },       /* 0110 1001 1 */
435        { 9, 0xD4, 960 },       /* 0110 1010 0 */
436        { 9, 0xD5, 1024 },      /* 0110 1010 1 */
437        { 9, 0xD6, 1088 },      /* 0110 1011 0 */
438        { 9, 0xD7, 1152 },      /* 0110 1011 1 */
439        { 9, 0xD8, 1216 },      /* 0110 1100 0 */
440        { 9, 0xD9, 1280 },      /* 0110 1100 1 */
441        { 9, 0xDA, 1344 },      /* 0110 1101 0 */
442        { 9, 0xDB, 1408 },      /* 0110 1101 1 */
443        { 9, 0x98, 1472 },      /* 0100 1100 0 */
444        { 9, 0x99, 1536 },      /* 0100 1100 1 */
445        { 9, 0x9A, 1600 },      /* 0100 1101 0 */
446        { 6, 0x18, 1664 },      /* 0110 00 */
447        { 9, 0x9B, 1728 },      /* 0100 1101 1 */
448        { 11, 0x8, 1792 },      /* 0000 0001 000 */
449        { 11, 0xC, 1856 },      /* 0000 0001 100 */
450        { 11, 0xD, 1920 },      /* 0000 0001 101 */
451        { 12, 0x12, 1984 },     /* 0000 0001 0010 */
452        { 12, 0x13, 2048 },     /* 0000 0001 0011 */
453        { 12, 0x14, 2112 },     /* 0000 0001 0100 */
454        { 12, 0x15, 2176 },     /* 0000 0001 0101 */
455        { 12, 0x16, 2240 },     /* 0000 0001 0110 */
456        { 12, 0x17, 2304 },     /* 0000 0001 0111 */
457        { 12, 0x1C, 2368 },     /* 0000 0001 1100 */
458        { 12, 0x1D, 2432 },     /* 0000 0001 1101 */
459        { 12, 0x1E, 2496 },     /* 0000 0001 1110 */
460        { 12, 0x1F, 2560 },     /* 0000 0001 1111 */
461        { 12, 0x1, G3CODE_EOL },        /* 0000 0000 0001 */
462        { 9, 0x1, G3CODE_INVALID },     /* 0000 0000 1 */
463        { 10, 0x1, G3CODE_INVALID },    /* 0000 0000 01 */
464        { 11, 0x1, G3CODE_INVALID },    /* 0000 0000 001 */
465        { 12, 0x0, G3CODE_INVALID }     /* 0000 0000 0000 */
466    };
467
468    private int[][] TIFFFaxBlackCodes = {
469        { 10, 0x37, 0 },        /* 0000 1101 11 */
470        { 3, 0x2, 1 },  /* 010 */
471        { 2, 0x3, 2 },  /* 11 */
472        { 2, 0x2, 3 },  /* 10 */
473        { 3, 0x3, 4 },  /* 011 */
474        { 4, 0x3, 5 },  /* 0011 */
475        { 4, 0x2, 6 },  /* 0010 */
476        { 5, 0x3, 7 },  /* 0001 1 */
477        { 6, 0x5, 8 },  /* 0001 01 */
478        { 6, 0x4, 9 },  /* 0001 00 */
479        { 7, 0x4, 10 }, /* 0000 100 */
480        { 7, 0x5, 11 }, /* 0000 101 */
481        { 7, 0x7, 12 }, /* 0000 111 */
482        { 8, 0x4, 13 }, /* 0000 0100 */
483        { 8, 0x7, 14 }, /* 0000 0111 */
484        { 9, 0x18, 15 },        /* 0000 1100 0 */
485        { 10, 0x17, 16 },       /* 0000 0101 11 */
486        { 10, 0x18, 17 },       /* 0000 0110 00 */
487        { 10, 0x8, 18 },        /* 0000 0010 00 */
488        { 11, 0x67, 19 },       /* 0000 1100 111 */
489        { 11, 0x68, 20 },       /* 0000 1101 000 */
490        { 11, 0x6C, 21 },       /* 0000 1101 100 */
491        { 11, 0x37, 22 },       /* 0000 0110 111 */
492        { 11, 0x28, 23 },       /* 0000 0101 000 */
493        { 11, 0x17, 24 },       /* 0000 0010 111 */
494        { 11, 0x18, 25 },       /* 0000 0011 000 */
495        { 12, 0xCA, 26 },       /* 0000 1100 1010 */
496        { 12, 0xCB, 27 },       /* 0000 1100 1011 */
497        { 12, 0xCC, 28 },       /* 0000 1100 1100 */
498        { 12, 0xCD, 29 },       /* 0000 1100 1101 */
499        { 12, 0x68, 30 },       /* 0000 0110 1000 */
500        { 12, 0x69, 31 },       /* 0000 0110 1001 */
501        { 12, 0x6A, 32 },       /* 0000 0110 1010 */
502        { 12, 0x6B, 33 },       /* 0000 0110 1011 */
503        { 12, 0xD2, 34 },       /* 0000 1101 0010 */
504        { 12, 0xD3, 35 },       /* 0000 1101 0011 */
505        { 12, 0xD4, 36 },       /* 0000 1101 0100 */
506        { 12, 0xD5, 37 },       /* 0000 1101 0101 */
507        { 12, 0xD6, 38 },       /* 0000 1101 0110 */
508        { 12, 0xD7, 39 },       /* 0000 1101 0111 */
509        { 12, 0x6C, 40 },       /* 0000 0110 1100 */
510        { 12, 0x6D, 41 },       /* 0000 0110 1101 */
511        { 12, 0xDA, 42 },       /* 0000 1101 1010 */
512        { 12, 0xDB, 43 },       /* 0000 1101 1011 */
513        { 12, 0x54, 44 },       /* 0000 0101 0100 */
514        { 12, 0x55, 45 },       /* 0000 0101 0101 */
515        { 12, 0x56, 46 },       /* 0000 0101 0110 */
516        { 12, 0x57, 47 },       /* 0000 0101 0111 */
517        { 12, 0x64, 48 },       /* 0000 0110 0100 */
518        { 12, 0x65, 49 },       /* 0000 0110 0101 */
519        { 12, 0x52, 50 },       /* 0000 0101 0010 */
520        { 12, 0x53, 51 },       /* 0000 0101 0011 */
521        { 12, 0x24, 52 },       /* 0000 0010 0100 */
522        { 12, 0x37, 53 },       /* 0000 0011 0111 */
523        { 12, 0x38, 54 },       /* 0000 0011 1000 */
524        { 12, 0x27, 55 },       /* 0000 0010 0111 */
525        { 12, 0x28, 56 },       /* 0000 0010 1000 */
526        { 12, 0x58, 57 },       /* 0000 0101 1000 */
527        { 12, 0x59, 58 },       /* 0000 0101 1001 */
528        { 12, 0x2B, 59 },       /* 0000 0010 1011 */
529        { 12, 0x2C, 60 },       /* 0000 0010 1100 */
530        { 12, 0x5A, 61 },       /* 0000 0101 1010 */
531        { 12, 0x66, 62 },       /* 0000 0110 0110 */
532        { 12, 0x67, 63 },       /* 0000 0110 0111 */
533        { 10, 0xF, 64 },        /* 0000 0011 11 */
534        { 12, 0xC8, 128 },      /* 0000 1100 1000 */
535        { 12, 0xC9, 192 },      /* 0000 1100 1001 */
536        { 12, 0x5B, 256 },      /* 0000 0101 1011 */
537        { 12, 0x33, 320 },      /* 0000 0011 0011 */
538        { 12, 0x34, 384 },      /* 0000 0011 0100 */
539        { 12, 0x35, 448 },      /* 0000 0011 0101 */
540        { 13, 0x6C, 512 },      /* 0000 0011 0110 0 */
541        { 13, 0x6D, 576 },      /* 0000 0011 0110 1 */
542        { 13, 0x4A, 640 },      /* 0000 0010 0101 0 */
543        { 13, 0x4B, 704 },      /* 0000 0010 0101 1 */
544        { 13, 0x4C, 768 },      /* 0000 0010 0110 0 */
545        { 13, 0x4D, 832 },      /* 0000 0010 0110 1 */
546        { 13, 0x72, 896 },      /* 0000 0011 1001 0 */
547        { 13, 0x73, 960 },      /* 0000 0011 1001 1 */
548        { 13, 0x74, 1024 },     /* 0000 0011 1010 0 */
549        { 13, 0x75, 1088 },     /* 0000 0011 1010 1 */
550        { 13, 0x76, 1152 },     /* 0000 0011 1011 0 */
551        { 13, 0x77, 1216 },     /* 0000 0011 1011 1 */
552        { 13, 0x52, 1280 },     /* 0000 0010 1001 0 */
553        { 13, 0x53, 1344 },     /* 0000 0010 1001 1 */
554        { 13, 0x54, 1408 },     /* 0000 0010 1010 0 */
555        { 13, 0x55, 1472 },     /* 0000 0010 1010 1 */
556        { 13, 0x5A, 1536 },     /* 0000 0010 1101 0 */
557        { 13, 0x5B, 1600 },     /* 0000 0010 1101 1 */
558        { 13, 0x64, 1664 },     /* 0000 0011 0010 0 */
559        { 13, 0x65, 1728 },     /* 0000 0011 0010 1 */
560        { 11, 0x8, 1792 },      /* 0000 0001 000 */
561        { 11, 0xC, 1856 },      /* 0000 0001 100 */
562        { 11, 0xD, 1920 },      /* 0000 0001 101 */
563        { 12, 0x12, 1984 },     /* 0000 0001 0010 */
564        { 12, 0x13, 2048 },     /* 0000 0001 0011 */
565        { 12, 0x14, 2112 },     /* 0000 0001 0100 */
566        { 12, 0x15, 2176 },     /* 0000 0001 0101 */
567        { 12, 0x16, 2240 },     /* 0000 0001 0110 */
568        { 12, 0x17, 2304 },     /* 0000 0001 0111 */
569        { 12, 0x1C, 2368 },     /* 0000 0001 1100 */
570        { 12, 0x1D, 2432 },     /* 0000 0001 1101 */
571        { 12, 0x1E, 2496 },     /* 0000 0001 1110 */
572        { 12, 0x1F, 2560 },     /* 0000 0001 1111 */
573        { 12, 0x1, G3CODE_EOL },        /* 0000 0000 0001 */
574        { 9, 0x1, G3CODE_INVALID },     /* 0000 0000 1 */
575        { 10, 0x1, G3CODE_INVALID },    /* 0000 0000 01 */
576        { 11, 0x1, G3CODE_INVALID },    /* 0000 0000 001 */
577        { 12, 0x0, G3CODE_INVALID }     /* 0000 0000 0000 */
578    };
579    
580    private int[] horizcode =
581        { 3, 0x1, 0 };          /* 001 */
582    private int[] passcode =
583        { 4, 0x1, 0 };          /* 0001 */
584    private int[][] vcodes = {
585        { 7, 0x03, 0 }, /* 0000 011 */
586        { 6, 0x03, 0 }, /* 0000 11 */
587        { 3, 0x03, 0 }, /* 011 */
588        { 1, 0x1, 0 },          /* 1 */
589        { 3, 0x2, 0 },          /* 010 */
590        { 6, 0x02, 0 }, /* 0000 10 */
591        { 7, 0x02, 0 }          /* 0000 010 */
592    };
593    private int[] msbmask =
594    { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
595}