source: trunk/third/tiff/libtiff/tif_fax3.h @ 18174

Revision 18174, 15.4 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18173, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Id: tif_fax3.h,v 1.1.1.1 2002-12-26 02:38:36 ghudson Exp $ */
2
3/*
4 * Copyright (c) 1990-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26
27#ifndef _FAX3_
28#define _FAX3_
29/*
30 * TIFF Library.
31 *
32 * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support.
33 *
34 * Decoder support is derived, with permission, from the code
35 * in Frank Cringle's viewfax program;
36 *      Copyright (C) 1990, 1995  Frank D. Cringle.
37 */
38#include "tiff.h"
39
40/*
41 * To override the default routine used to image decoded
42 * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC.
43 * The routine must have the type signature given below;
44 * for example:
45 *
46 * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
47 *
48 * where buf is place to set the bits, runs is the array of b&w run
49 * lengths (white then black), erun is the last run in the array, and
50 * lastx is the width of the row in pixels.  Fill routines can assume
51 * the run array has room for at least lastx runs and can overwrite
52 * data in the run array as needed (e.g. to append zero runs to bring
53 * the count up to a nice multiple).
54 */
55typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32);
56
57/*
58 * The default run filler; made external for other decoders.
59 */
60#if defined(__cplusplus)
61extern "C" {
62#endif
63extern  void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32);
64#if defined(__cplusplus)
65}
66#endif
67
68
69/* finite state machine codes */
70#define S_Null          0
71#define S_Pass          1
72#define S_Horiz         2
73#define S_V0            3
74#define S_VR            4
75#define S_VL            5
76#define S_Ext           6
77#define S_TermW         7
78#define S_TermB         8
79#define S_MakeUpW       9
80#define S_MakeUpB       10
81#define S_MakeUp        11
82#define S_EOL           12
83
84typedef struct {                /* state table entry */
85        unsigned char State;    /* see above */
86        unsigned char Width;    /* width of code in bits */
87        uint32  Param;          /* unsigned 32-bit run length in bits */
88} TIFFFaxTabEnt;
89
90extern  const TIFFFaxTabEnt TIFFFaxMainTable[];
91extern  const TIFFFaxTabEnt TIFFFaxWhiteTable[];
92extern  const TIFFFaxTabEnt TIFFFaxBlackTable[];
93
94/*
95 * The following macros define the majority of the G3/G4 decoder
96 * algorithm using the state tables defined elsewhere.  To build
97 * a decoder you need some setup code and some glue code. Note
98 * that you may also need/want to change the way the NeedBits*
99 * macros get input data if, for example, you know the data to be
100 * decoded is properly aligned and oriented (doing so before running
101 * the decoder can be a big performance win).
102 *
103 * Consult the decoder in the TIFF library for an idea of what you
104 * need to define and setup to make use of these definitions.
105 *
106 * NB: to enable a debugging version of these macros define FAX3_DEBUG
107 *     before including this file.  Trace output goes to stdout.
108 */
109
110#ifndef EndOfData
111#define EndOfData()     (cp >= ep)
112#endif
113/*
114 * Need <=8 or <=16 bits of input data.  Unlike viewfax we
115 * cannot use/assume a word-aligned, properly bit swizzled
116 * input data set because data may come from an arbitrarily
117 * aligned, read-only source such as a memory-mapped file.
118 * Note also that the viewfax decoder does not check for
119 * running off the end of the input data buffer.  This is
120 * possible for G3-encoded data because it prescans the input
121 * data to count EOL markers, but can cause problems for G4
122 * data.  In any event, we don't prescan and must watch for
123 * running out of data since we can't permit the library to
124 * scan past the end of the input data buffer.
125 *
126 * Finally, note that we must handle remaindered data at the end
127 * of a strip specially.  The coder asks for a fixed number of
128 * bits when scanning for the next code.  This may be more bits
129 * than are actually present in the data stream.  If we appear
130 * to run out of data but still have some number of valid bits
131 * remaining then we makeup the requested amount with zeros and
132 * return successfully.  If the returned data is incorrect then
133 * we should be called again and get a premature EOF error;
134 * otherwise we should get the right answer.
135 */
136#ifndef NeedBits8
137#define NeedBits8(n,eoflab) do {                                        \
138    if (BitsAvail < (n)) {                                              \
139        if (EndOfData()) {                                              \
140            if (BitsAvail == 0)                 /* no valid bits */     \
141                goto eoflab;                                            \
142            BitsAvail = (n);                    /* pad with zeros */    \
143        } else {                                                        \
144            BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;              \
145            BitsAvail += 8;                                             \
146        }                                                               \
147    }                                                                   \
148} while (0)
149#endif
150#ifndef NeedBits16
151#define NeedBits16(n,eoflab) do {                                       \
152    if (BitsAvail < (n)) {                                              \
153        if (EndOfData()) {                                              \
154            if (BitsAvail == 0)                 /* no valid bits */     \
155                goto eoflab;                                            \
156            BitsAvail = (n);                    /* pad with zeros */    \
157        } else {                                                        \
158            BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;              \
159            if ((BitsAvail += 8) < (n)) {                               \
160                if (EndOfData()) {                                      \
161                    /* NB: we know BitsAvail is non-zero here */        \
162                    BitsAvail = (n);            /* pad with zeros */    \
163                } else {                                                \
164                    BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;      \
165                    BitsAvail += 8;                                     \
166                }                                                       \
167            }                                                           \
168        }                                                               \
169    }                                                                   \
170} while (0)
171#endif
172#define GetBits(n)      (BitAcc & ((1<<(n))-1))
173#define ClrBits(n) do {                                                 \
174    BitsAvail -= (n);                                                   \
175    BitAcc >>= (n);                                                     \
176} while (0)
177
178#ifdef FAX3_DEBUG
179static const char* StateNames[] = {
180    "Null   ",
181    "Pass   ",
182    "Horiz  ",
183    "V0     ",
184    "VR     ",
185    "VL     ",
186    "Ext    ",
187    "TermW  ",
188    "TermB  ",
189    "MakeUpW",
190    "MakeUpB",
191    "MakeUp ",
192    "EOL    ",
193};
194#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
195#define LOOKUP8(wid,tab,eoflab) do {                                    \
196    int t;                                                              \
197    NeedBits8(wid,eoflab);                                              \
198    TabEnt = tab + GetBits(wid);                                        \
199    printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail,               \
200           StateNames[TabEnt->State], TabEnt->Param);                   \
201    for (t = 0; t < TabEnt->Width; t++)                                 \
202        DEBUG_SHOW;                                                     \
203    putchar('\n');                                                      \
204    fflush(stdout);                                                     \
205    ClrBits(TabEnt->Width);                                             \
206} while (0)
207#define LOOKUP16(wid,tab,eoflab) do {                                   \
208    int t;                                                              \
209    NeedBits16(wid,eoflab);                                             \
210    TabEnt = tab + GetBits(wid);                                        \
211    printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail,               \
212           StateNames[TabEnt->State], TabEnt->Param);                   \
213    for (t = 0; t < TabEnt->Width; t++)                                 \
214        DEBUG_SHOW;                                                     \
215    putchar('\n');                                                      \
216    fflush(stdout);                                                     \
217    ClrBits(TabEnt->Width);                                             \
218} while (0)
219
220#define SETVAL(x) do {                                                  \
221    *pa++ = RunLength + (x);                                            \
222    printf("SETVAL: %d\t%d\n", RunLength + (x), a0);                    \
223    a0 += x;                                                            \
224    RunLength = 0;                                                      \
225} while (0)
226#else
227#define LOOKUP8(wid,tab,eoflab) do {                                    \
228    NeedBits8(wid,eoflab);                                              \
229    TabEnt = tab + GetBits(wid);                                        \
230    ClrBits(TabEnt->Width);                                             \
231} while (0)
232#define LOOKUP16(wid,tab,eoflab) do {                                   \
233    NeedBits16(wid,eoflab);                                             \
234    TabEnt = tab + GetBits(wid);                                        \
235    ClrBits(TabEnt->Width);                                             \
236} while (0)
237
238/*
239 * Append a run to the run length array for the
240 * current row and reset decoding state.
241 */
242#define SETVAL(x) do {                                                  \
243    *pa++ = RunLength + (x);                                            \
244    a0 += (x);                                                          \
245    RunLength = 0;                                                      \
246} while (0)
247#endif
248
249/*
250 * Synchronize input decoding at the start of each
251 * row by scanning for an EOL (if appropriate) and
252 * skipping any trash data that might be present
253 * after a decoding error.  Note that the decoding
254 * done elsewhere that recognizes an EOL only consumes
255 * 11 consecutive zero bits.  This means that if EOLcnt
256 * is non-zero then we still need to scan for the final flag
257 * bit that is part of the EOL code.
258 */
259#define SYNC_EOL(eoflab) do {                                           \
260    if (EOLcnt == 0) {                                                  \
261        for (;;) {                                                      \
262            NeedBits16(11,eoflab);                                      \
263            if (GetBits(11) == 0)                                       \
264                break;                                                  \
265            ClrBits(1);                                                 \
266        }                                                               \
267    }                                                                   \
268    for (;;) {                                                          \
269        NeedBits8(8,eoflab);                                            \
270        if (GetBits(8))                                                 \
271            break;                                                      \
272        ClrBits(8);                                                     \
273    }                                                                   \
274    while (GetBits(1) == 0)                                             \
275        ClrBits(1);                                                     \
276    ClrBits(1);                         /* EOL bit */                   \
277    EOLcnt = 0;                         /* reset EOL counter/flag */    \
278} while (0)
279
280/*
281 * Cleanup the array of runs after decoding a row.
282 * We adjust final runs to insure the user buffer is not
283 * overwritten and/or undecoded area is white filled.
284 */
285#define CLEANUP_RUNS() do {                                             \
286    if (RunLength)                                                      \
287        SETVAL(0);                                                      \
288    if (a0 != lastx) {                                                  \
289        badlength(a0, lastx);                                           \
290        while (a0 > lastx && pa > thisrun)                              \
291            a0 -= *--pa;                                                \
292        if (a0 < lastx) {                                               \
293            if (a0 < 0)                                                 \
294                a0 = 0;                                                 \
295            if ((pa-thisrun)&1)                                         \
296                SETVAL(0);                                              \
297            SETVAL(lastx - a0);                                         \
298        } else if (a0 > lastx) {                                        \
299            SETVAL(lastx);                                              \
300            SETVAL(0);                                                  \
301        }                                                               \
302    }                                                                   \
303} while (0)
304
305/*
306 * Decode a line of 1D-encoded data.
307 *
308 * The line expanders are written as macros so that they can be reused
309 * but still have direct access to the local variables of the "calling"
310 * function.
311 *
312 * Note that unlike the original version we have to explicitly test for
313 * a0 >= lastx after each black/white run is decoded.  This is because
314 * the original code depended on the input data being zero-padded to
315 * insure the decoder recognized an EOL before running out of data.
316 */
317#define EXPAND1D(eoflab) do {                                           \
318    for (;;) {                                                          \
319        for (;;) {                                                      \
320            LOOKUP16(12, TIFFFaxWhiteTable, eof1d);                     \
321            switch (TabEnt->State) {                                    \
322            case S_EOL:                                                 \
323                EOLcnt = 1;                                             \
324                goto done1d;                                            \
325            case S_TermW:                                               \
326                SETVAL(TabEnt->Param);                                  \
327                goto doneWhite1d;                                       \
328            case S_MakeUpW:                                             \
329            case S_MakeUp:                                              \
330                a0 += TabEnt->Param;                                    \
331                RunLength += TabEnt->Param;                             \
332                break;                                                  \
333            default:                                                    \
334                unexpected("WhiteTable", a0);                           \
335                goto done1d;                                            \
336            }                                                           \
337        }                                                               \
338    doneWhite1d:                                                        \
339        if (a0 >= lastx)                                                \
340            goto done1d;                                                \
341        for (;;) {                                                      \
342            LOOKUP16(13, TIFFFaxBlackTable, eof1d);                     \
343            switch (TabEnt->State) {                                    \
344            case S_EOL:                                                 \
345                EOLcnt = 1;                                             \
346                goto done1d;                                            \
347            case S_TermB:                                               \
348                SETVAL(TabEnt->Param);                                  \
349                goto doneBlack1d;                                       \
350            case S_MakeUpB:                                             \
351            case S_MakeUp:                                              \
352                a0 += TabEnt->Param;                                    \
353                RunLength += TabEnt->Param;                             \
354                break;                                                  \
355            default:                                                    \
356                unexpected("BlackTable", a0);                           \
357                goto done1d;                                            \
358            }                                                           \
359        }                                                               \
360    doneBlack1d:                                                        \
361        if (a0 >= lastx)                                                \
362            goto done1d;                                                \
363        if( *(pa-1) == 0 && *(pa-2) == 0 )                              \
364            pa -= 2;                                                    \
365    }                                                                   \
366eof1d:                                                                  \
367    prematureEOF(a0);                                                   \
368    CLEANUP_RUNS();                                                     \
369    goto eoflab;                                                        \
370done1d:                                                                 \
371    CLEANUP_RUNS();                                                     \
372} while (0)
373
374/*
375 * Update the value of b1 using the array
376 * of runs for the reference line.
377 */
378#define CHECK_b1 do {                                                   \
379    if (pa != thisrun) while (b1 <= a0 && b1 < lastx) {                 \
380        b1 += pb[0] + pb[1];                                            \
381        pb += 2;                                                        \
382    }                                                                   \
383} while (0)
384
385/*
386 * Expand a row of 2D-encoded data.
387 */
388#define EXPAND2D(eoflab) do {                                           \
389    while (a0 < lastx) {                                                \
390        LOOKUP8(7, TIFFFaxMainTable, eof2d);                            \
391        switch (TabEnt->State) {                                        \
392        case S_Pass:                                                    \
393            CHECK_b1;                                                   \
394            b1 += *pb++;                                                \
395            RunLength += b1 - a0;                                       \
396            a0 = b1;                                                    \
397            b1 += *pb++;                                                \
398            break;                                                      \
399        case S_Horiz:                                                   \
400            if ((pa-thisrun)&1) {                                       \
401                for (;;) {      /* black first */                       \
402                    LOOKUP16(13, TIFFFaxBlackTable, eof2d);             \
403                    switch (TabEnt->State) {                            \
404                    case S_TermB:                                       \
405                        SETVAL(TabEnt->Param);                          \
406                        goto doneWhite2da;                              \
407                    case S_MakeUpB:                                     \
408                    case S_MakeUp:                                      \
409                        a0 += TabEnt->Param;                            \
410                        RunLength += TabEnt->Param;                     \
411                        break;                                          \
412                    default:                                            \
413                        goto badBlack2d;                                \
414                    }                                                   \
415                }                                                       \
416            doneWhite2da:;                                              \
417                for (;;) {      /* then white */                        \
418                    LOOKUP16(12, TIFFFaxWhiteTable, eof2d);             \
419                    switch (TabEnt->State) {                            \
420                    case S_TermW:                                       \
421                        SETVAL(TabEnt->Param);                          \
422                        goto doneBlack2da;                              \
423                    case S_MakeUpW:                                     \
424                    case S_MakeUp:                                      \
425                        a0 += TabEnt->Param;                            \
426                        RunLength += TabEnt->Param;                     \
427                        break;                                          \
428                    default:                                            \
429                        goto badWhite2d;                                \
430                    }                                                   \
431                }                                                       \
432            doneBlack2da:;                                              \
433            } else {                                                    \
434                for (;;) {      /* white first */                       \
435                    LOOKUP16(12, TIFFFaxWhiteTable, eof2d);             \
436                    switch (TabEnt->State) {                            \
437                    case S_TermW:                                       \
438                        SETVAL(TabEnt->Param);                          \
439                        goto doneWhite2db;                              \
440                    case S_MakeUpW:                                     \
441                    case S_MakeUp:                                      \
442                        a0 += TabEnt->Param;                            \
443                        RunLength += TabEnt->Param;                     \
444                        break;                                          \
445                    default:                                            \
446                        goto badWhite2d;                                \
447                    }                                                   \
448                }                                                       \
449            doneWhite2db:;                                              \
450                for (;;) {      /* then black */                        \
451                    LOOKUP16(13, TIFFFaxBlackTable, eof2d);             \
452                    switch (TabEnt->State) {                            \
453                    case S_TermB:                                       \
454                        SETVAL(TabEnt->Param);                          \
455                        goto doneBlack2db;                              \
456                    case S_MakeUpB:                                     \
457                    case S_MakeUp:                                      \
458                        a0 += TabEnt->Param;                            \
459                        RunLength += TabEnt->Param;                     \
460                        break;                                          \
461                    default:                                            \
462                        goto badBlack2d;                                \
463                    }                                                   \
464                }                                                       \
465            doneBlack2db:;                                              \
466            }                                                           \
467            CHECK_b1;                                                   \
468            break;                                                      \
469        case S_V0:                                                      \
470            CHECK_b1;                                                   \
471            SETVAL(b1 - a0);                                            \
472            b1 += *pb++;                                                \
473            break;                                                      \
474        case S_VR:                                                      \
475            CHECK_b1;                                                   \
476            SETVAL(b1 - a0 + TabEnt->Param);                            \
477            b1 += *pb++;                                                \
478            break;                                                      \
479        case S_VL:                                                      \
480            CHECK_b1;                                                   \
481            SETVAL(b1 - a0 - TabEnt->Param);                            \
482            b1 -= *--pb;                                                \
483            break;                                                      \
484        case S_Ext:                                                     \
485            *pa++ = lastx - a0;                                         \
486            extension(a0);                                              \
487            goto eol2d;                                                 \
488        case S_EOL:                                                     \
489            *pa++ = lastx - a0;                                         \
490            NeedBits8(4,eof2d);                                         \
491            if (GetBits(4))                                             \
492                unexpected("EOL", a0);                                  \
493            ClrBits(4);                                                 \
494            EOLcnt = 1;                                                 \
495            goto eol2d;                                                 \
496        default:                                                        \
497        badMain2d:                                                      \
498            unexpected("MainTable", a0);                                \
499            goto eol2d;                                                 \
500        badBlack2d:                                                     \
501            unexpected("BlackTable", a0);                               \
502            goto eol2d;                                                 \
503        badWhite2d:                                                     \
504            unexpected("WhiteTable", a0);                               \
505            goto eol2d;                                                 \
506        eof2d:                                                          \
507            prematureEOF(a0);                                           \
508            CLEANUP_RUNS();                                             \
509            goto eoflab;                                                \
510        }                                                               \
511    }                                                                   \
512    if (RunLength) {                                                    \
513        if (RunLength + a0 < lastx) {                                   \
514            /* expect a final V0 */                                     \
515            NeedBits8(1,eof2d);                                         \
516            if (!GetBits(1))                                            \
517                goto badMain2d;                                         \
518            ClrBits(1);                                                 \
519        }                                                               \
520        SETVAL(0);                                                      \
521    }                                                                   \
522eol2d:                                                                  \
523    CLEANUP_RUNS();                                                     \
524} while (0)
525#endif /* _FAX3_ */
Note: See TracBrowser for help on using the repository browser.