|
|
1.1 root 1: /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */
2: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */
3: /* The copyright notice does not imply actual or intended publication. */
4: /* AUTHORS: */
5: /* H. S. Baird - ATT-BL MH - first versions */
6:
7: /* CCITT.c - functions for CCITT compression/decompression of binary images.
8: The following discussion is a summary of CCITT Recommendations T.4 and T.6
9: on facsimile coding schemes and coding control functions for Group 3 and Group
10: 4 facsimile apparatus (drafted at Malaga-Torremolinos, 1984). They describe
11: algorithms for invertible (lossless) compression and decompression of bilevel
12: (black-and-white, not grey) 2D rectangular images of arbitrary height and
13: width. By convention the images are processed top-down, one horizontal scan
14: line at a time. It is not strictly necessary to know the height of an image
15: before starting compression or decompression. Width, however, must be known
16: in advance in some cases (discussed below), and must remain constant for the
17: whole image in all cases. There are three distinct but intimately related
18: standards: Group 3 1-dimensional, Group 3 2-dimensional, and Group 4.
19: VLSI hardware implementations always include all three. The Group 3 encodings
20: are used in the vast installed base of FAX machines. Group 4 is not used
21: in today's FAX machines, but seems to be the default standard in document image
22: archiving applications.
23: The CCITT Group 3 FAX standard permits either 1-D or 2-D encoding.
24: It is not easy to tell from an encoding which was used. Both 1-D and 2-D
25: assume fixed scanline length (in pixels), which must be known at encoding time.
26: Group 3 1-D (g31) code uses fixed ``modified Huffman'' codes for
27: run-lengths, with two different code tables for black and white runs. Each
28: line is assumed to begin with a (possibly 0-length) white run. Of course,
29: the colors strictly alternate. An empty (all-white) line is supposed to be
30: spelled out with a full pixel count, although some decoders won't complain
31: if just a 0-length count is used. There are provisions for fill bits at the
32: end of lines to allow slow receiving equipment to keep up. Each line ends with
33: an EOL code on which it may be possible to synchronize after transmission error.
34: Group 3 2-D (g32) encoding tries to exploit the slowly-changing nature
35: of artwork from line to line. It is a mixture of 1-D-coded lines and
36: ``2-D''-coded lines describing small local changes relative to the immediately
37: prior ``reference'' line. 1-D coding recurs every few (`k') lines, so that
38: resynchronization is frequently possible. K is usually 2 or 4, but the
39: standard permits any number, even infinity, since the coding method used on
40: a line is specified by which of two special EOLx codes is used to end the
41: prior line.
42: CCITT Group 4 (g4) is like Group 3 2-D, but optimized to take advantage
43: of a lossless communications channel or reliable storage medium (such as computer
44: memory), where resynchronization is unnecessary. Thus the first line is 2-D
45: encoded referenced to an imaginary initial blank line, k is always infinity,
46: and EOL's are not used at all. It essential that the line-length be known in
47: advance of both encoding and decoding, so that line-breaks can be triggered when
48: that length is exceeded. End of FAX buffer (end of page) is signaled by a
49: special EOFB code.
50: On images of printed text and sparse line-graphics, g4-compressed files
51: are often 15-40X smaller than bitmap (packed bits), 5X than bitfile(9.5),
52: 2X than g31, and 2X than rle | pack.
53: PERFORMANCE
54: On 10 printed A4 pages (business letters, technical reports, etc),
55: at a resolution of 400 dpi:
56: binary: 2020 Kbytes CPU secs (to compress binary)
57: pack: 200 - 380 17
58: bitfile(9.5): 150 - 360 ?
59: rle: 100 - 230 7.5
60: compress: 90 - 155 14
61: g31: 85 - 190 13
62: g32: 55 - 110 13
63: g4: 30 - 70 13
64: G4-compressed files are 15-40X smaller than binary, 5X than bitfile(9.5),
65: 3.5X than rle, 2X than g31, and 2X than rle | pack.
66: */
67:
68: #include <stdio.h>
69: #include <string.h>
70: #include <ctype.h>
71: #include "CPU.h"
72: #include "stdocr.h"
73: #include "rle.h"
74: #include "bitio.h"
75: #include "CCITT.h"
76:
77: #define DEBUG 0 /* 0 disables compilation of all debugging code;
78: 1 compiles, but must enable particular parts below */
79: #define NEW_TRAIL 1 /* enable new trailing-0 counts (has passed early tests) */
80: #define dbg_trail 0
81:
82: DST_table *ccitt_table()
83: { DST_context cx;
84: if((cx.t = (DST_table *)malloc(sizeof(DST_table)))==NULL)
85: abort("CCITT.c: build_tbl: can't alloc cx.t");
86: /* All tables have e[DST_white], e[DST_black], & e[DST_2d] entries */
87: cx.t->mny=3;
88: if((cx.t->e=(DST_entry *)malloc(cx.t->mny*sizeof(DST_entry)))==NULL)
89: abort("CCITT.c: build_tbl: can't alloc cx.t->e[%d]",cx.t->mny);
90:
91: cx.s = cx.c = DST_white;
92: cx.l = 0;
93: cx.t->e[cx.s].p[0] = '\0';
94: cx.t->e[cx.s].l = 0;
95: cx.t->e[cx.s].z = 0;
96: build_transits(cx);
97:
98: cx.s = cx.c = DST_black;
99: cx.l = 0;
100: cx.t->e[cx.s].p[0] = '\0';
101: cx.t->e[cx.s].l = 0;
102: cx.t->e[cx.s].z = 0;
103: build_transits(cx);
104:
105: cx.s = cx.c = DST_2d;
106: cx.l = 0;
107: cx.t->e[cx.s].p[0] = '\0';
108: cx.t->e[cx.s].l = 0;
109: cx.t->e[cx.s].z = 0;
110: build_transits(cx);
111:
112: #if DEBUG
113: if(F) ccitt_err_tbl(cx.t);
114: #endif
115: return(cx.t);
116: }
117:
118: DST_state new_state(t)
119: DST_table *t;
120: { t->mny++;
121: if((t->e=(DST_entry *)realloc(t->e,t->mny*sizeof(DST_entry)))==NULL)
122: abort("can't realloc t->[%d]",t->mny);
123: return(t->mny-1);
124: }
125:
126: /* The entry described by `cx' exists in the table, and its prefix `p' is
127: setup; create its transitions, and their next entries, recursively. */
128: build_transits(cx)
129: DST_context cx;
130: #define entry cx.t->e[cx.s]
131: #define transit entry.t[col]
132: { DST_color col;
133: DST_entry ne; /* next entry */
134: DST_context ncx; /* next Context */
135: char **s,**ss; /* for searching code */
136: short *c,*cs;
137: int si,matching,longer;
138: char svch,col_str[2];
139: switch(cx.c) {
140: case DST_white:
141: ss=codewht;
142: cs=bitcwht;
143: break;
144: case DST_black:
145: ss=codeblk;
146: cs=bitcblk;
147: break;
148: case DST_2d:
149: ss=code2d;
150: cs=bitc2d;
151: break;
152: };
153: for(col=0;col<=1;col++) {
154: sprintf(col_str,"%1d",col);
155: ncx = cx; ncx.l++;
156: /* build a transition */
157: strcpy(ne.p,entry.p); strcat(ne.p,col_str);
158: ne.l = ncx.l;
159: if(col==0) ne.z = entry.z+1; else ne.z = 0;
160: /* count those that match new prefix */
161: longer=matching=0;
162: for(s=ss,c=cs,si=0; (*s)!=NULL; s++,c++,si++) {
163: if(*c==ncx.l) {
164: if(strcmp(*s,ne.p)==0) {
165: matching++;
166: switch(cx.c) {
167: case DST_white:
168: case DST_black:
169: transit.a = itor(si);
170: break;
171: case DST_2d:
172: transit.a = si;
173: break;
174: };
175: };
176: }
177: else if(*c>ncx.l) {
178: svch=(*s)[ncx.l]; (*s)[ncx.l] = '\0';
179: if(strcmp(*s,ne.p)==0) {
180: longer++;
181: };
182: (*s)[ncx.l]=svch;
183: };
184: };
185: /* analyze results */
186: if(matching==0&&longer>0) {
187: /* no match yet; go deeper */
188: transit.a = DST_action_NULL;
189: ncx.s = transit.s = new_state(cx.t);
190: strcpy(cx.t->e[ncx.s].p,ne.p);
191: cx.t->e[ncx.s].l = ne.l;
192: cx.t->e[ncx.s].z = ne.z;
193: build_transits(ncx);
194: }
195: else if(matching==1&&longer==0) {
196: /* unique leaf: good */
197: /* picked up action earlier */
198: switch(cx.c) {
199: case DST_white:
200: case DST_black:
201: if(transit.a<=63) /* termination code */
202: transit.s = flip_color(cx.c);
203: else /* makeup code */
204: transit.s = cx.c;
205: break;
206: case DST_2d:
207: /* legal end of code */
208: transit.s = DST_state_NULL;
209: break;
210: };
211: }
212: else { /* illegal transition */
213: transit.a = DST_action_ERROR;
214: transit.s = DST_state_NULL;
215: };
216: };
217: }
218:
219: ccitt_err_tbl(t)
220: DST_table *t;
221: { int d;
222: ccitt_err_state(DST_white,t);
223: ccitt_err_state(DST_black,t);
224: ccitt_err_state(DST_2d,t);
225: }
226:
227: ccitt_err_state(s,t)
228: DST_state s;
229: DST_table *t;
230: { err("%03d %s %2d %2d%*s %d %03d,%-4d %d %03d,%-4d",
231: s,t->e[s].p,t->e[s].l,t->e[s].z,14-strlen(t->e[s].p)," ",
232: 0,t->e[s].t[0].s,t->e[s].t[0].a,
233: 1,t->e[s].t[1].s,t->e[s].t[1].a
234: );
235: if(t->e[s].t[0].s>1) ccitt_err_state(t->e[s].t[0].s,t);
236: if(t->e[s].t[1].s>1) ccitt_err_state(t->e[s].t[1].s,t);
237: }
238:
239: /* Translate a stream of bits in CCITT FAX Group 3 (1-D) compression format
240: into a sequence of RLE_Lines. Returns one (RLE_Line *) on each call (or NULL
241: if EOF or error). The first pixel (black or white) in each g31 line is
242: assigned run index 0. */
243: RLE_Line *g31_to_rlel(t,f,bof)
244: DST_table *t;
245: BITFILE *f;
246: boolean bof; /* beginning of file */
247: #define dbg_g31r_r (0) /* trace each run/EOL/ERR_SYN */
248: #define dbg_g31r_c (0) /* trace each Huffman code (or, fill+EOL)*/
249: #define dbg_g31r_t (0) /* trace each state-transition */
250: { static DST_context cx;
251: static RLE_Line rl;
252: static RLE_Run *r; /* prior, current runs */
253: int run,biti,sync,si,bitv;
254: boolean fill;
255: /* color of 1st run in each line */
256: #define g31_first_color DST_white
257: /* reverse Black/White in output image */
258: #define g31_negative 0
259: if(bof){if(T) { /* sync by skipping initial FILL & EOL code */
260: sync=0; while((bitv=getb(f))==0) sync++;
261: if(bitv!=1||sync<11) {
262: #if DEBUG
263: if(dbg_g31r_c) {
264: fprintf(stderr,"BOF_ERR ");
265: for(si=0;si<sync;si++) fprintf(stderr,"0");
266: if(bitv==1) fprintf(stderr,"1\n");
267: else fprintf(stderr,"?\n");
268: };
269: #endif
270: return(NULL);
271: }
272: #if DEBUG
273: else if(dbg_g31r_c){
274: fprintf(stderr,"BOF_EOL ");
275: for(si=0;si<sync;si++) fprintf(stderr,"0");
276: fprintf(stderr,"1\n");
277: };
278: #endif
279: };
280: /* start file expecting a run-code of a fixed color */
281: cx.s = cx.c = g31_first_color;
282: rl.y = -1; /* assume first line is y==0 */
283: };
284: rl.y++; rl.runs=0; r = rl.r; biti=run=0;
285: while(T) switch(getb(f)) {
286: case 0 : /* next bit is 0 */
287: switch(t->e[cx.s].t[0].a) {
288: case DST_action_ERROR:
289: /* bad code: try to resynchronize */
290: #if DEBUG
291: if(dbg_g31r_t){
292: fprintf(stderr,"%s %04d %s0?...\n",
293: (cx.c==DST_white)? "W": "B",
294: t->e[cx.s].t[0].s,
295: t->e[cx.s].p);
296: };
297: #endif
298: /* count trailing 0's so far (should be in table) */
299: #if !NEW_TRAIL
300: sync=1;
301: si=strlen(t->e[cx.s].p)-1;
302: while(si>=0&&t->e[cx.s].p[si]=='0') {sync++; si--;};
303: fill = (si<0); /* all 0's: may be fill bits */
304: #else
305: sync=t->e[cx.s].z+1;
306: fill = (sync>t->e[cx.s].l); /* all 0's: maybe fill bits */
307: #endif
308: #if DEBUG
309: if(dbg_trail) err("sync %d fill %d",sync,fill);
310: if(dbg_g31r_c)fprintf(stderr,"ERR_SYN %s0?",t->e[cx.s].p);
311: #endif
312: while(sync<11) {
313: switch(bitv=getb(f)) {
314: case 0: sync++;
315: #if DEBUG
316: if(dbg_g31r_c) fprintf(stderr,"0");
317: #endif
318: break;
319: case 1: sync=0; fill=F;
320: #if DEBUG
321: if(dbg_g31r_c) fprintf(stderr,"1");
322: #endif
323: break;
324: case EOF:
325: #if DEBUG
326: if(dbg_g31r_c) fprintf(stderr,"<EOF>\n");
327: #endif
328: return(NULL); break;
329: };
330: };
331: /* next `1' will synchronize */
332: do { switch(bitv=getb(f)) {
333: case 0:
334: #if DEBUG
335: if(dbg_g31r_c) fprintf(stderr,"0");
336: #endif
337: break;
338: case 1:
339: #if DEBUG
340: if(dbg_g31r_c) fprintf(stderr,"1");
341: #endif
342: break;
343: case EOF:
344: #if DEBUG
345: if(dbg_g31r_c) fprintf(stderr,"<EOF>\n");
346: #endif
347: return(NULL); break;
348: };
349: }
350: while(bitv!=1);
351: #if DEBUG
352: if(dbg_g31r_c) fprintf(stderr,"\n");
353: if(dbg_g31r_r) {
354: if(fill) fprintf(stderr,"FILL_EOL\n");
355: else fprintf(stderr,"ERR_SYN_EOL\n");
356: };
357: #endif
358: /* start next line expecting a run-code of a fixed color */
359: cx.s = cx.c = g31_first_color;
360: return(&rl);
361: break;
362: case DST_action_NULL:
363: #if DEBUG
364: if(dbg_g31r_t)fprintf(stderr,"%s %04d %s0\n",
365: (cx.c==DST_white)? "W": "B",
366: t->e[cx.s].t[0].s,
367: t->e[cx.s].p);
368: #endif
369: cx.s = t->e[cx.s].t[0].s;
370: break;
371: case DST_EOL:
372: #if DEBUG
373: if(dbg_g31r_c)fprintf(stderr,"EOL %s0\n",
374: t->e[cx.s].p);
375: if(dbg_g31r_r)fprintf(stderr,"EOL\n");
376: #endif
377: /* start next line expecting a run-code of a fixed color */
378: cx.s = cx.c = g31_first_color;
379: return(&rl);
380: break;
381: default:
382: #if DEBUG
383: if(dbg_g31r_c)fprintf(stderr,"%s%6d %s0\n",
384: (cx.c==DST_white)? "W": "B",
385: t->e[cx.s].t[0].a,
386: t->e[cx.s].p);
387: #endif
388: if(t->e[cx.s].t[0].a<=63) {
389: run += t->e[cx.s].t[0].a;
390: #if DEBUG
391: if(dbg_g31r_r)fprintf(stderr,"%s%6d\n",
392: (cx.c==DST_white)? "W": "B",
393: run);
394: #endif
395: biti += run;
396: if(cx.c==DST_black^g31_negative) {
397: /* end of black run */
398: r->xe = biti-1;
399: r++; rl.runs++;
400: }
401: else { /* end of white run */
402: r->xs = biti;
403: };
404: cx.c = flip_color(cx.c);
405: run = 0;
406: }
407: else run += t->e[cx.s].t[0].a;
408: cx.s = t->e[cx.s].t[0].s;
409: break;
410: };
411: break;
412: case 1: /* next bit is 1 */
413: switch(t->e[cx.s].t[1].a) {
414: case DST_action_ERROR:
415: /* bad code: try to resynchronize */
416: #if DEBUG
417: if(dbg_g31r_t){
418: fprintf(stderr,"%s %04d %s1?...\n",
419: (cx.c==DST_white)? "W": "B",
420: t->e[cx.s].t[1].s,
421: t->e[cx.s].p);
422: };
423: if(dbg_g31r_c)fprintf(stderr,"ERR_SYN %s1?",t->e[cx.s].p);
424: #endif
425: /* no trailing 0's; can't be fill bits */
426: sync=0;
427: while(sync<11) {
428: switch(bitv=getb(f)) {
429: case 0: sync++;
430: #if DEBUG
431: if(dbg_g31r_c) fprintf(stderr,"0");
432: #endif
433: break;
434: case 1: sync=0;
435: #if DEBUG
436: if(dbg_g31r_c) fprintf(stderr,"1");
437: #endif
438: break;
439: case EOF:
440: #if DEBUG
441: if(dbg_g31r_c)
442: fprintf(stderr,"<EOF>\n");
443: #endif
444: return(NULL); break;
445: };
446: };
447: /* next `1' will synchronize */
448: do { switch(bitv=getb(f)) {
449: case 0:
450: #if DEBUG
451: if(dbg_g31r_c) fprintf(stderr,"0");
452: #endif
453: break;
454: case 1:
455: #if DEBUG
456: if(dbg_g31r_c) fprintf(stderr,"1");
457: #endif
458: break;
459: case EOF:
460: #if DEBUG
461: if(dbg_g31r_c)
462: fprintf(stderr,"<EOF>\n");
463: #endif
464: return(NULL); break;
465: };
466: }
467: while(bitv!=1);
468: #if DEBUG
469: if(dbg_g31r_c) fprintf(stderr,"\n");
470: if(dbg_g31r_r) fprintf(stderr,"ERR_SYN_EOL\n");
471: #endif
472: /* start next line expecting a run-code of a fixed color */
473: cx.s = cx.c = g31_first_color;
474: return(&rl);
475: break;
476: case DST_action_NULL:
477: #if DEBUG
478: if(dbg_g31r_t)fprintf(stderr,"%s %04d %s1\n",
479: (cx.c==DST_white)? "W": "B",
480: t->e[cx.s].t[1].s,
481: t->e[cx.s].p);
482: #endif
483: cx.s = t->e[cx.s].t[1].s;
484: break;
485: case DST_EOL:
486: #if DEBUG
487: if(dbg_g31r_c)fprintf(stderr,"EOL %s1\n",
488: t->e[cx.s].p);
489: if(dbg_g31r_r)fprintf(stderr,"EOL\n");
490: #endif
491: /* start next line expecting a run-code of a fixed color */
492: cx.s = cx.c = g31_first_color;
493: return(&rl);
494: break;
495: default:
496: #if DEBUG
497: if(dbg_g31r_c)fprintf(stderr,"%s%6d %s1\n",
498: (cx.c==DST_white)? "W": "B",
499: t->e[cx.s].t[1].a,
500: t->e[cx.s].p);
501: #endif
502: if(t->e[cx.s].t[1].a<=63) {
503: run += t->e[cx.s].t[1].a;
504: #if DEBUG
505: if(dbg_g31r_r)fprintf(stderr,"%s%6d\n",
506: (cx.c==DST_white)? "W": "B",
507: run);
508: #endif
509: biti += run;
510: if(cx.c==DST_black^g31_negative) {
511: /* end of black run */
512: r->xe = biti-1;
513: r++; rl.runs++;
514: }
515: else { /* end of white run */
516: r->xs = biti;
517: };
518: cx.c = flip_color(cx.c);
519: run = 0;
520: }
521: else run += t->e[cx.s].t[1].a;
522: cx.s = t->e[cx.s].t[1].s;
523: break;
524: };
525: break;
526: case EOF:
527: return(NULL);
528: break;
529: default:
530: return(NULL);
531: break;
532: };
533: /* never come here: return() variously from cases above */
534: }
535:
536: /* Translate a sequence of RLE_Line's (describing a binary image)
537: into a file (a stream of bits) in CCITT FAX Group 3 (1-D) compression format.
538: BOF_to_g31() must be called first; then call rlel_to_g31() for each line
539: (including blank lines); finally, EOF_to_g31() must be called. Each line's
540: EOL and the RTC's first EOL are padded so they end on a byte boundary.
541: */
542: /* debugging flags: trace to stderr */
543: #define dbg_rg31_e (0) /* entry */
544: #define dbg_rg31_r (0) /* runs */
545: #define dbg_rg31_s (0) /* bitstrings */
546:
547: #if DEBUG
548: #define bits_g31(bits) { \
549: cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \
550: if(dbg_rg31_s) fprintf(stderr,"%s",(bits)); \
551: if(dbg_rg31_r) fprintf(stderr," "); \
552: }
553: #define EOL_g31 { \
554: if(dbg_rg31_r) fprintf(stderr,"EOL "); \
555: bits_g31(EOLSTRING); \
556: if(dbg_rg31_r) fprintf(stderr,"\n"); \
557: }
558: #else
559: #define bits_g31(bits) { \
560: cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \
561: }
562: #define EOL_g31 { \
563: bits_g31(EOLSTRING); \
564: }
565: #endif
566:
567: BOF_to_g31(f)
568: BITFILE *f; /* state of output bitfile */
569: { char *cs;
570: EOL_g31;
571: }
572:
573: rlel_to_g31(rl,wid,f)
574: RLE_Line *rl; /* line of runs: if NULL, then blank */
575: int wid; /* width of an output line in pixels */
576: BITFILE *f; /* state of output bitfile */
577: { int pi; /* input pixel index on line */
578: RLE_Run *rp,*pp,*sp;
579: int runl,codi;
580: char *cs,*p01;
581: #if DEBUG
582: #define Wrun_g31(rn) { \
583: runl=(rn); \
584: if(dbg_rg31_r) fprintf(stderr,"W %5d ",runl); \
585: while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
586: p01=codewht[codi=rtoi(runl)]; bits_g31(p01); \
587: if(codi>=64) {p01=codewht[runl%64]; bits_g31(p01);}; \
588: if(dbg_rg31_r) fprintf(stderr,"\n"); \
589: }
590: #else
591: #define Wrun_g31(rn) { \
592: runl=(rn); \
593: while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
594: p01=codewht[codi=rtoi(runl)]; bits_g31(p01); \
595: if(codi>=64) {p01=codewht[runl%64]; bits_g31(p01);}; \
596: }
597: #endif
598: #if DEBUG
599: #define Brun_g31(rn) { \
600: runl=(rn); \
601: if(dbg_rg31_r) fprintf(stderr,"B %5d ",runl); \
602: while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
603: p01=codeblk[codi=rtoi(runl)]; bits_g31(p01); \
604: if(codi>=64) {p01=codeblk[runl%64]; bits_g31(p01);}; \
605: if(dbg_rg31_r) fprintf(stderr,"\n"); \
606: }
607:
608: #else
609: #define Brun_g31(rn) { \
610: runl=(rn); \
611: while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
612: p01=codeblk[codi=rtoi(runl)]; bits_g31(p01); \
613: if(codi>=64) {p01=codeblk[runl%64]; bits_g31(p01);}; \
614: }
615: #endif
616: #if DEBUG
617: if(dbg_rg31_e) err("rlel_to_g31(rl[y%d,r%d])",rl->y,rl->runs);
618: #endif
619: if(rl!=NULL&&rl->runs>0) {
620: pi=0; /* bit to write next */
621: #if DEBUG
622: if(dbg_rg31_e) err("rlel_to_g31(rl[y%d,r%d])",rl->y,rl->runs);
623: #endif
624: for(sp=(rp=rl->r)+rl->runs; rp<sp; rp++) {
625: Wrun_g31(rp->xs-pi); pi=rp->xs;
626: Brun_g31(rp->xe-pi+1); pi=rp->xe+1;
627: };
628: if((--rp)->xe+1<wid) Wrun_g31(wid-rp->xe-1);
629: }
630: else {
631: #if DEBUG
632: if(dbg_rg31_e) err("rlel_to_g31(rl[y?,r0])");
633: #endif
634: Wrun_g31(wid); /* blank (all-white) scanline */
635: };
636: /* fill so that EOL ends on byte boundary */
637: padb(f,0,8,EOLLENGTH);
638: #if DEBUG
639: if(dbg_rg31_s) fprintf(stderr,"+0?");
640: #endif
641: EOL_g31;
642: }
643:
644: EOF_to_g31(f)
645: BITFILE *f;
646: { char *cs;
647: /* fill so that EOL ends on byte boundary */
648: padb(f,0,8,EOLLENGTH);
649: #if DEBUG
650: if(dbg_rg31_s) fprintf(stderr,"+0?");
651: #endif
652: /* write RTC */
653: EOL_g31;
654: EOL_g31;
655: EOL_g31;
656: EOL_g31;
657: EOL_g31;
658: EOL_g31;
659: }
660:
661: /* Macro for use within g32_to_rlel, to read one 1-D Modified Huffman coded
662: run-length of a given color, placing the result in a given variable.
663: Exceptionally, goto trap_eol, trap_eof, or trap_code_err.
664: */
665: #if DEBUG
666: #define g32_1d_run(C,V) { \
667: run = 0; \
668: do { cx.tr.s = (C); \
669: do { px = cx; \
670: switch(bitv=getb(f)) { \
671: case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \
672: case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \
673: case EOF : goto trap_eof; break; \
674: }; \
675: } \
676: while(cx.tr.a==DST_action_NULL); \
677: switch(cx.tr.a) { \
678: case DST_EOL : \
679: if(dbg_g32r_c)fprintf(stderr,"EOL %s\n",EOLSTRING); \
680: goto trap_eol; \
681: break; \
682: case DST_action_ERROR : goto trap_code_err; break; \
683: default : \
684: if(dbg_g32r_c)fprintf(stderr,"%s%6d %s%d\n", \
685: ((C)==DST_white)? "W": "B", \
686: cx.tr.a, \
687: t->e[px.tr.s].p, \
688: bitv); \
689: run += cx.tr.a; \
690: break; \
691: }; \
692: } \
693: while(cx.tr.a>63); \
694: (V) = run; \
695: }
696: #else
697: #define g32_1d_run(C,V) { \
698: run = 0; \
699: do { cx.tr.s = (C); \
700: do { px = cx; \
701: switch(bitv=getb(f)) { \
702: case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \
703: case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \
704: case EOF : goto trap_eof; break; \
705: }; \
706: } \
707: while(cx.tr.a==DST_action_NULL); \
708: switch(cx.tr.a) { \
709: case DST_EOL : \
710: goto trap_eol; \
711: break; \
712: case DST_action_ERROR : goto trap_code_err; break; \
713: default : \
714: run += cx.tr.a; \
715: break; \
716: }; \
717: } \
718: while(cx.tr.a>63); \
719: (V) = run; \
720: }
721: #endif
722:
723: /* Translate a stream of bits in CCITT FAX Group 3 (2-D) compression format
724: into a sequence of RLE_Lines. Returns one (RLE_Line *) on each call (or NULL
725: if EOF or error). The first pixel (black or white) in each g32 line is
726: assigned run index 0. */
727: RLE_Line *g32_to_rlel(t,f,bof)
728: DST_table *t;
729: BITFILE *f;
730: boolean bof; /* beginning of file */
731: #define dbg_g32r_e (0) /* entry/exit */
732: #define dbg_g32r_r (0) /* trace each run/EOL/ERR_SYN */
733: #define dbg_g32r_c (0) /* trace each Huffman code (or, fill+EOL)*/
734: #define dbg_g32r_t (0) /* trace each state-transition */
735: #define g32r_strict (1) /* 1 is CORRECT: explicitly code the last black pel */
736: { static RLE_Line rl0,rl1,*prl,*crl; /* prior, current run-lines */
737: RLE_Line *swrl;
738: int bitv; /* the last-read bit value */
739: DST_context cx,px; /* the current/prior decoding context */
740: RLE_Run *cr,*pr,*pre; /* into current/prior rle lines */
741: RLE_Run *pra0; /* rightmost in prior line with xe<=a0 (if none: prl->r) */
742: int run,sync,si,rtc_eols;
743: boolean fill;
744: /* pixel indices (0,1,...): current-line a*; prior-line b*.
745: a0 is the index of the most recently completely encoded bit */
746: int a0,a1,a2,b1,b2;
747: DST_color a0_color; /* a0's color: same as a2 & b2, opposite of a1 & b1 */
748: int a01,a12; /* lengths of runs a0-a1 & a1-a2 */
749: #define g32_first_color DST_white /* color of 1st run in each line */
750: #define g32_negative (0) /* if 1, invert Black/White on output */
751: #define swap_rl(f,b) {swrl=(f); (f)=(b); (b)=swrl;}
752: /* detect b1 & b2: sensitive to a0, a0_color, and prior runs *pr *(pr+1) */
753: #define g32r_find_Bb1Wb2 { \
754: /* find 1st black changing pel>a0 */ \
755: /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
756: while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
757: /* look beyond pra0 */ \
758: pr=pra0; while(pr<pre && (b1=pr->xs)<=a0) pr++; \
759: /* move b2 to 1st changing white pel > b1 */ \
760: if(pr<pre) b2=pr->xe+1; \
761: else b1=b2=prl->len; \
762: }
763: #define g32r_find_Wb1Bb2 { \
764: /* find 1st white changing pel>a0 */ \
765: /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
766: while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
767: /* look beyond pra0 */ \
768: pr=pra0; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
769: /* move b2 to 1st changing black pel > b1 */ \
770: if(pr<pre) { \
771: if((pr+1)<pre) b2=(pr+1)->xs; \
772: else b2=prl->len; \
773: } \
774: else b1=b2=prl->len; \
775: }
776: #define g32r_find_b1b2 {if(a0_color==DST_white) g32r_find_Bb1Wb2 else g32r_find_Wb1Bb2;}
777:
778: #if DEBUG
779: if(dbg_g32r_e) fprintf(stderr,"g32_to_rlel(t,bf,bof%d)\n",bof);
780: #endif
781: if(bof){crl= &rl0; crl->y= -1; crl->len=0; crl->runs=0;
782: prl= &rl1; prl->y= -1; prl->len=0; prl->runs=0;
783: /* sync by skipping initial FILL & EOL code */
784: sync=0; while((bitv=getb(f))==0) sync++;
785: if(bitv!=1||sync<11) {
786: #if DEBUG
787: if(dbg_g32r_c) {
788: fprintf(stderr,"BOF_ERR ");
789: for(si=0;si<sync;si++) fprintf(stderr,"0");
790: if(bitv==1) fprintf(stderr,"1\n");
791: else fprintf(stderr,"?\n");
792: };
793: #endif
794: return(NULL);
795: }
796: #if DEBUG
797: else if(dbg_g32r_c){
798: fprintf(stderr,"BOF_EOL ");
799: for(si=0;si<sync;si++) fprintf(stderr,"0");
800: fprintf(stderr,"1\n");
801: };
802: #else
803: ;
804: #endif
805: prl->y = -1; crl->y = 0;
806: }
807: else crl->y = prl->y + 1;
808:
809: pre = (pra0=pr=prl->r) + prl->runs; /* prior line */
810: crl->runs=0; cr=crl->r-1; /* current line */
811: /* start on an imaginary white pixel just to left of margin */
812: a0= -1; a0_color = DST_white;
813:
814: /* check 1-D / 2-D bit immediately after prior EOL */
815: switch(bitv=getb(f)) {
816: case 0 : /* 2-dimensionally encoded line */
817: #if DEBUG
818: if(dbg_g32r_c) fprintf(stderr,"2D_LINE 0\n");
819: #endif
820: /* start b1/b2 on prior line's first black pixel, etc;
821: if none, then place off end of line */
822: if(pr<pre) {b1=pr->xs; b2=pr->xe+1;} else b1=b2=prl->len;
823: /* parse a sequence of 2D codes... */
824: while(T/* exited only via goto trap_* and return */) {
825: cx.tr.s = DST_2d; cx.tr.a = DST_action_NULL;
826: #if DEBUG
827: if(dbg_g32r_t)fprintf(stderr,"(%d,%d)\n",cx.tr.s,cx.tr.a);
828: #endif
829: do { switch(bitv=getb(f)) {
830: case 0 :
831: case 1 :
832: cx.tr=t->e[cx.tr.s].t[bitv];
833: break;
834: case EOF: goto trap_eof; break;
835: };
836: #if DEBUG
837: if(dbg_g32r_t)fprintf(stderr,"%d->(%d,%d)\n",
838: bitv,cx.tr.s,cx.tr.a);
839: #endif
840: }
841: while(cx.tr.a==DST_action_NULL);
842: #if DEBUG
843: if(dbg_g32r_t)fprintf(stderr,"%s %04d %s0\n",
844: (cx.c==DST_white)? "W": "B",
845: cx.tr.s,
846: t->e[cx.tr.s].p);
847: #endif
848: switch(cx.tr.a) {
849: case i2D_V0:
850: #if DEBUG
851: if(dbg_g32r_c)
852: fprintf(stderr,"V0 %s\n",code2d[cx.tr.a]);
853: #endif
854: a1=b1;
855: /* encode a0 to a1-1 */
856: if(a0_color==DST_black) cr->xe=a1-1;
857: /* move a0 to a1 */
858: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
859: a0_color = flip_color(a0_color);
860: /* encode a0 */
861: if(a0_color==DST_black)
862: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
863: #if g32r_strict
864: if(a0==prl->len-1)
865: { a0++; goto trap_expecting_eol; };
866: #endif
867: g32r_find_b1b2;
868: break;
869: case i2D_VR1:
870: #if DEBUG
871: if(dbg_g32r_c)
872: fprintf(stderr,"VR1 %s\n",code2d[cx.tr.a]);
873: #endif
874: a1=b1+1;
875: /* encode a0 to a1-1 */
876: if(a0_color==DST_black) cr->xe=a1-1;
877: /* move a0 to a1 */
878: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
879: a0_color = flip_color(a0_color);
880: /* encode a0 */
881: if(a0_color==DST_black)
882: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
883: #if !g32r_strict
884: if(a0==prl->len-1)
885: { a0++; goto trap_expecting_eol; };
886: #endif
887: g32r_find_b1b2;
888: break;
889: case i2D_VR2:
890: #if DEBUG
891: if(dbg_g32r_c)
892: fprintf(stderr,"VR2 %s\n",code2d[cx.tr.a]);
893: #endif
894: a1=b1+2;
895: /* encode a0 to a1-1 */
896: if(a0_color==DST_black) cr->xe=a1-1;
897: /* move a0 to a1 */
898: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
899: a0_color = flip_color(a0_color);
900: /* encode a0 */
901: if(a0_color==DST_black)
902: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
903: #if !g32r_strict
904: if(a0==prl->len-1)
905: { a0++; goto trap_expecting_eol; };
906: #endif
907: g32r_find_b1b2;
908: break;
909: case i2D_VR3:
910: #if DEBUG
911: if(dbg_g32r_c)
912: fprintf(stderr,"VR3 %s\n",code2d[cx.tr.a]);
913: #endif
914: a1=b1+3;
915: /* encode a0 to a1-1 */
916: if(a0_color==DST_black) cr->xe=a1-1;
917: /* move a0 to a1 */
918: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
919: a0_color = flip_color(a0_color);
920: /* encode a0 */
921: if(a0_color==DST_black)
922: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
923: #if !g32r_strict
924: if(a0==prl->len-1)
925: { a0++; goto trap_expecting_eol; };
926: #endif
927: g32r_find_b1b2;
928: break;
929: case i2D_VL1:
930: #if DEBUG
931: if(dbg_g32r_c)
932: fprintf(stderr,"VL1 %s\n",code2d[cx.tr.a]);
933: #endif
934: if((a1=b1-1)<0) err("g32_to_rlel: VL1 backs up to %d",a1);
935: /* encode a0 to a1-1 */
936: if(a0_color==DST_black) cr->xe=a1-1;
937: /* move a0 to a1 */
938: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
939: a0_color = flip_color(a0_color);
940: /* encode a0 */
941: if(a0_color==DST_black)
942: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
943: #if !g32_strict
944: if(a0==prl->len-1)
945: { a0++; goto trap_expecting_eol; };
946: #endif
947: g32r_find_b1b2;
948: break;
949: case i2D_VL2:
950: #if DEBUG
951: if(dbg_g32r_c)
952: fprintf(stderr,"VL2 %s\n",code2d[cx.tr.a]);
953: #endif
954: if((a1=b1-2)<0) err("g32_to_rlel: VL2 backs up to %d",a1);
955: /* encode a0 to a1-1 */
956: if(a0_color==DST_black) cr->xe=a1-1;
957: /* move a0 to a1 */
958: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
959: a0_color = flip_color(a0_color);
960: /* encode a0 */
961: if(a0_color==DST_black)
962: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
963: #if !g32r_strict
964: if(a0==prl->len-1)
965: { a0++; goto trap_expecting_eol; };
966: #endif
967: g32r_find_b1b2;
968: break;
969: case i2D_VL3:
970: #if DEBUG
971: if(dbg_g32r_c)
972: fprintf(stderr,"VL3 %s\n",code2d[cx.tr.a]);
973: #endif
974: if((a1=b1-3)<0) err("g32_to_rlel: VL3 backs up to %d",a1);
975: /* encode a0 to a1-1 */
976: if(a0_color==DST_black) cr->xe=a1-1;
977: /* move a0 to a1 */
978: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
979: a0_color = flip_color(a0_color);
980: /* encode a0 */
981: if(a0_color==DST_black)
982: { crl->runs++; (++cr)->xs = a0; cr->xe = a0; };
983: #if !g32r_strict
984: if(a0==prl->len-1)
985: { a0++; goto trap_expecting_eol; };
986: #endif
987: g32r_find_b1b2;
988: break;
989: case i2D_PASS:
990: #if DEBUG
991: if(dbg_g32r_c)
992: fprintf(stderr,"PASS %s\n",code2d[cx.tr.a]);
993: #endif
994: /* move a0 to b2; no change of color */
995: a0=b2; if(a0>=prl->len) goto trap_expecting_eol;
996: if(a0_color==DST_black) cr->xe = a0;
997: #if !g32r_strict
998: if(a0==prl->len-1)
999: { a0++; goto trap_expecting_eol; };
1000: #endif
1001: g32r_find_b1b2;
1002: break;
1003: case i2D_HORIZ:
1004: #if DEBUG
1005: if(dbg_g32r_c)
1006: fprintf(stderr,"HORIZ %s\n",code2d[cx.tr.a]);
1007: #endif
1008: if(a0_color==DST_white) {
1009: if(a0<0) a0=0; /* first run in line starts at 0 */
1010: g32_1d_run(DST_white,a01); a1 = a0 + a01;
1011: g32_1d_run(DST_black,a12); a2 = a1 + a12;
1012: if(a12>0) /* Black run of >0 length */ {
1013: crl->runs++;
1014: (++cr)->xs = a1;
1015: cr->xe = a2-1;
1016: };
1017: a0 = a2; /* still white */
1018: if(a0>=prl->len) goto trap_expecting_eol;
1019: /* encode a0 */
1020: #if !g32r_strict
1021: if(a0==prl->len-1)
1022: { a0++; goto trap_expecting_eol; };
1023: #endif
1024: g32r_find_Bb1Wb2;
1025: }
1026: else { g32_1d_run(DST_black,a01); a1 = a0 + a01;
1027: g32_1d_run(DST_white,a12); a2 = a1 + a12;
1028: if(a01>0) /* Black run of >0 length */ {
1029: cr->xe = a1 - 1;
1030: }
1031: else { /* 0-length: very peculiar: ignore */
1032: fprintf(stderr,
1033: "g32_to_rlel: HORIZ B%d! W%d - ignore\n",
1034: a01,a12);
1035: cr--; crl->runs--;
1036: };
1037: a0 = a2; /* still black */
1038: if(a0>=prl->len) goto trap_expecting_eol;
1039: /* encode a0 */
1040: crl->runs++; (++cr)->xs = a0;
1041: #if !g32r_strict
1042: if(a0==prl->len-1) {
1043: cr->xe = a0;
1044: a0++;
1045: goto trap_expecting_eol;
1046: };
1047: #endif
1048: g32r_find_Wb1Bb2;
1049: };
1050: break;
1051: case i2D_EOL:
1052: #if DEBUG
1053: if(dbg_g32r_c)
1054: fprintf(stderr,"EOL %s\n",code2d[cx.tr.a]);
1055: #endif
1056: goto trap_eol;
1057: break;
1058: case DST_action_ERROR: goto trap_code_err; break;
1059: };
1060: };
1061: break;
1062: case 1 : /* 1-dimensionally encoded line */
1063: #if DEBUG
1064: if(dbg_g32r_c) fprintf(stderr,"1D_LINE 1\n");
1065: #endif
1066: /* read a sequence of 1-D runcodes... */
1067: while(T/* exit only via goto trap_X */) {
1068: g32_1d_run(a0_color,a01);
1069: a1 = ((a0>=0)? a0 : 0) + a01;
1070: if(a01>0) {
1071: /* encode a0 through a1-1 */
1072: if(a0_color==DST_black^g32_negative) {
1073: /* output-black run */
1074: crl->runs++;
1075: (++cr)->xs=((a0>=0)? a0 : 0);
1076: cr->xe=a1-1;
1077: };
1078: };
1079: a0=a1;
1080: a0_color=flip_color(a0_color);
1081: if(prl->len>0 && a0>=prl->len) goto trap_expecting_eol;
1082: };
1083: break;
1084: case EOF : goto trap_eof; break;
1085: };
1086:
1087: /* come here via goto's: all these traps return() */
1088:
1089: trap_expecting_eol: /* come here expecting to see EOL or FILL+EOL */
1090: sync=0; while((bitv=getb(f))==0) sync++;
1091: switch(bitv) {
1092: case 1:
1093: if(sync==11) {
1094: #if DEBUG
1095: if(dbg_g32r_c){
1096: fprintf(stderr,"EOL %s\n",EOLSTRING);
1097: };
1098: #endif
1099: goto trap_eol;
1100: }
1101: else if(sync>11) {
1102: #if DEBUG
1103: if(dbg_g32r_c){
1104: fprintf(stderr,"FILLEOL ");
1105: for(si=0;si<sync-11;si++) fprintf(stderr,"0");
1106: fprintf(stderr,"+");
1107: fprintf(stderr,"%s\n",EOLSTRING);
1108: };
1109: #endif
1110: goto trap_eol;
1111: }
1112: else {
1113: #if DEBUG
1114: if(dbg_g32r_c){
1115: fprintf(stderr,"NOT EOL ");
1116: for(si=0;si<sync;si++) fprintf(stderr,"0");
1117: fprintf(stderr,"1?");
1118: };
1119: #endif
1120: sync=0;
1121: goto trap_eol_err;
1122: };
1123: break;
1124: case EOF: goto trap_eof; break;
1125: };
1126: goto trap_eol;
1127:
1128: trap_code_err:
1129: /* unexpected coding sequence:
1130: 'px' holds last decoding context & 'bitv' latest bit value;
1131: will attempt to resynchronize on next EOL */
1132: #if DEBUG
1133: if(dbg_g32r_c)fprintf(stderr,"CODERR %s%d?",
1134: t->e[px.tr.s].p,bitv);
1135: #endif
1136: /* count trailing 0's so far (should be in table) */
1137: #if !NEW_TRAIL
1138: if(bitv==0) sync=1; else sync=0;
1139: si=strlen(t->e[px.tr.s].p)-1;
1140: while(si>=0&&t->e[px.tr.s].p[si]=='0') {sync++; si--;};
1141: fill = (si<0); /* all 0's: may be fill bits */
1142: #else
1143: if(bitv==0) sync=t->e[px.tr.s].z+1; else sync=t->e[px.tr.s].z;
1144: fill = (sync>t->e[px.tr.s].l); /* all 0's: maybe fill bits */
1145: #endif
1146: #if DEBUG
1147: if(dbg_trail)err("sync %d fill %d",sync,fill);
1148: #endif
1149: trap_eol_err:
1150: while(sync<11) {
1151: switch(bitv=getb(f)) {
1152: case 0: sync++;
1153: #if DEBUG
1154: if(dbg_g32r_c) fprintf(stderr,"0");
1155: #endif
1156: break;
1157: case 1: sync=0;
1158: #if DEBUG
1159: if(dbg_g32r_c) fprintf(stderr,"1");
1160: #endif
1161: break;
1162: case EOF: goto trap_eof; break;
1163: };
1164: };
1165: /* next `1' will synchronize */
1166: do { switch(bitv=getb(f)) {
1167: case 0:
1168: #if DEBUG
1169: if(dbg_g32r_c) fprintf(stderr,"0");
1170: #endif
1171: break;
1172: case 1:
1173: #if DEBUG
1174: if(dbg_g32r_c) fprintf(stderr,"1");
1175: #endif
1176: break;
1177: case EOF: goto trap_eof; break;
1178: };
1179: }
1180: while(bitv!=1);
1181: #if DEBUG
1182: if(dbg_g32r_c) fprintf(stderr," EOL\n");
1183: #endif
1184: goto trap_eol;
1185:
1186: trap_eol: /* come here having seen (and reported) EOL */
1187: /* learn/check line-length */
1188: if(a0>=0) crl->len=a0; else crl->len=0;
1189: if(crl->len==0) {
1190: /* no pixels coded -- may be the 1st of 6 RTC EOLs */
1191: /* check suffix 1 bit */
1192: if((bitv=getb(f))!=1) goto trap_eol_err;
1193: rtc_eols=1;
1194: #if DEBUG
1195: if(dbg_g32r_c)fprintf(stderr,"RTC_EOL +1 (%d)\n",rtc_eols);
1196: #endif
1197: do { sync=0; while((bitv=getb(f))==0) sync++;
1198: switch(bitv) {
1199: case 1:
1200: if(sync<11) {
1201: #if DEBUG
1202: if(dbg_g32r_c){
1203: fprintf(stderr,"NOT RTC ");
1204: for(si=0;si<sync;si++)
1205: fprintf(stderr,"0");
1206: fprintf(stderr,"1?\n");
1207: };
1208: #endif
1209: sync=0;
1210: goto trap_eol_err;
1211: };
1212: break;
1213: case EOF: goto trap_eof; break;
1214: };
1215: /* check suffix 1 bit */
1216: if((bitv=getb(f))!=1) goto trap_eol_err;
1217: rtc_eols++;
1218: #if DEBUG
1219: if(dbg_g32r_c) {
1220: fprintf(stderr,"RTC_EOL ");
1221: for(si=0;si<sync;si++) fprintf(stderr,"0");
1222: fprintf(stderr,"1+1 (%d)\n",rtc_eols);
1223: };
1224: #endif
1225: }
1226: while(rtc_eols<6);
1227: /* normal RTC */
1228: #if DEBUG
1229: if(dbg_g32r_c)fprintf(stderr,"RTC\n");
1230: #endif
1231: return(NULL);
1232: }
1233: else if(prl->len==0) {
1234: #if DEBUG
1235: if(dbg_g32r_c)fprintf(stderr,"LINELEN %d\n",crl->len);
1236: #endif
1237: }
1238: else if(crl->len!=prl->len) {
1239: err("g32_to_rlel: y%d: LINELEN changes c%d != p%d ? (force to %d)",
1240: crl->y,crl->len,prl->len,prl->len);
1241: crl->len = prl->len;
1242: };
1243: swap_rl(crl,prl);
1244: return(prl);
1245:
1246: trap_eof:
1247: #if DEBUG
1248: if(dbg_g32r_c) fprintf(stderr,"<EOF>\n");
1249: #endif
1250: return(NULL);
1251:
1252: }
1253:
1254: /* Translate a sequence of RLE_Line's (describing a binary image)
1255: into a file (a stream of bits) in CCITT FAX Group 3 (2-D) compression format.
1256: BOF_to_g32() must be called first; then call rlel_to_g32() for each line
1257: (including blank lines); finally, EOF_to_g32() must be called. Each line's
1258: EOL and the RTC's first EOL will be padded so they end on a byte boundary.
1259: */
1260: /* debugging flags: trace to stderr */
1261: #define dbg_rg32_e (0) /* entry */
1262: #define dbg_rg32_r (0) /* runs */
1263: #define dbg_rg32_s (0) /* bitstrings */
1264: #define rg32_strict (1) /* 1 is CORRECT: explicitly code the last black pel */
1265:
1266: #if DEBUG
1267: #define bits_g32(bits) { \
1268: cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \
1269: if(dbg_rg32_s) fprintf(stderr,"%s",(bits)); \
1270: if(dbg_rg32_r) fprintf(stderr," "); \
1271: }
1272: #else
1273: #define bits_g32(bits) { \
1274: cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \
1275: }
1276: #endif
1277: #if DEBUG
1278: #define EOL_g32 { \
1279: if(dbg_rg32_r) fprintf(stderr,"EOL "); \
1280: bits_g32(EOLSTRING); \
1281: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1282: }
1283: #else
1284: #define EOL_g32 { \
1285: bits_g32(EOLSTRING); \
1286: }
1287: #endif
1288:
1289: BOF_to_g32(f)
1290: BITFILE *f;
1291: { char *cs;
1292: /* a NOP: no header for Group 3 (2-D) */
1293: #if DEBUG
1294: if(dbg_rg32_e) fprintf(stderr,"BOF\n");
1295: #endif
1296: };
1297:
1298: rlel_to_g32(pl,cl,wid,f)
1299: RLE_Line *pl; /* prior "reference" line: if NULL, use 1-D coding on cl */
1300: RLE_Line *cl; /* current "coding" line: if NULL, is blank (all white) */
1301: int wid; /* width of an output line in pixels */
1302: BITFILE *f;
1303: { int runl,codi;
1304: char *cs,*p01;
1305: #if DEBUG
1306: #define Wrun_g32(rn) { \
1307: runl=(rn); \
1308: if(dbg_rg32_r) fprintf(stderr,"W %5d ",runl); \
1309: while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
1310: p01=codewht[codi=rtoi(runl)]; bits_g32(p01); \
1311: if(codi>=64) {p01=codewht[runl%64]; bits_g32(p01);}; \
1312: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1313: }
1314: #else
1315: #define Wrun_g32(rn) { \
1316: runl=(rn); \
1317: while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
1318: p01=codewht[codi=rtoi(runl)]; bits_g32(p01); \
1319: if(codi>=64) {p01=codewht[runl%64]; bits_g32(p01);}; \
1320: }
1321: #endif
1322: #if DEBUG
1323: #define Brun_g32(rn) { \
1324: runl=(rn); \
1325: if(dbg_rg32_r) fprintf(stderr,"B %5d ",runl); \
1326: while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
1327: p01=codeblk[codi=rtoi(runl)]; bits_g32(p01); \
1328: if(codi>=64) {p01=codeblk[runl%64]; bits_g32(p01);}; \
1329: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1330: }
1331: #else
1332: #define Brun_g32(rn) { \
1333: runl=(rn); \
1334: while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
1335: p01=codeblk[codi=rtoi(runl)]; bits_g32(p01); \
1336: if(codi>=64) {p01=codeblk[runl%64]; bits_g32(p01);}; \
1337: }
1338: #endif
1339: #if DEBUG
1340: #define V0_g32 { \
1341: if(dbg_rg32_r) fprintf(stderr,"V0 "); \
1342: bits_g32(code2d[i2D_V0]); \
1343: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1344: }
1345: #else
1346: #define V0_g32 { \
1347: bits_g32(code2d[i2D_V0]); \
1348: }
1349: #endif
1350: #if DEBUG
1351: #define VR1_g32 { \
1352: if(dbg_rg32_r) fprintf(stderr,"VR1 "); \
1353: bits_g32(code2d[i2D_VR1]); \
1354: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1355: }
1356: #else
1357: #define VR1_g32 { \
1358: bits_g32(code2d[i2D_VR1]); \
1359: }
1360: #endif
1361: #if DEBUG
1362: #define VR2_g32 { \
1363: if(dbg_rg32_r) fprintf(stderr,"VR2 "); \
1364: bits_g32(code2d[i2D_VR2]); \
1365: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1366: }
1367: #else
1368: #define VR2_g32 { \
1369: bits_g32(code2d[i2D_VR2]); \
1370: }
1371: #endif
1372: #if DEBUG
1373: #define VR3_g32 { \
1374: if(dbg_rg32_r) fprintf(stderr,"VR3 "); \
1375: bits_g32(code2d[i2D_VR3]); \
1376: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1377: }
1378: #else
1379: #define VR3_g32 { \
1380: bits_g32(code2d[i2D_VR3]); \
1381: }
1382: #endif
1383: #if DEBUG
1384: #define VL1_g32 { \
1385: if(dbg_rg32_r) fprintf(stderr,"VL1 "); \
1386: bits_g32(code2d[i2D_VL1]); \
1387: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1388: }
1389: #else
1390: #define VL1_g32 { \
1391: bits_g32(code2d[i2D_VL1]); \
1392: }
1393: #endif
1394: #if DEBUG
1395: #define VL2_g32 { \
1396: if(dbg_rg32_r) fprintf(stderr,"VL2 "); \
1397: bits_g32(code2d[i2D_VL2]); \
1398: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1399: }
1400: #else
1401: #define VL2_g32 { \
1402: bits_g32(code2d[i2D_VL2]); \
1403: }
1404: #endif
1405: #if DEBUG
1406: #define VL3_g32 { \
1407: if(dbg_rg32_r) fprintf(stderr,"VL3 "); \
1408: bits_g32(code2d[i2D_VL3]); \
1409: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1410: }
1411: #else
1412: #define VL3_g32 { \
1413: bits_g32(code2d[i2D_VL3]); \
1414: }
1415: #endif
1416: #if DEBUG
1417: #define PASS_g32 { \
1418: if(dbg_rg32_r) fprintf(stderr,"PASS "); \
1419: bits_g32(code2d[i2D_PASS]); \
1420: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1421: }
1422: #else
1423: #define PASS_g32 { \
1424: bits_g32(code2d[i2D_PASS]); \
1425: }
1426: #endif
1427: #if DEBUG
1428: #define HORIZ_g32 { \
1429: if(dbg_rg32_r) fprintf(stderr,"HORIZ "); \
1430: bits_g32(code2d[i2D_HORIZ]); \
1431: if(dbg_rg32_r) fprintf(stderr,"\n"); \
1432: }
1433: #else
1434: #define HORIZ_g32 { \
1435: bits_g32(code2d[i2D_HORIZ]); \
1436: }
1437: #endif
1438: #define detect_a1a2_BW { \
1439: /* find leftmost black changing pel > a0 */ \
1440: /* advance cra as far as possible s.t. cra->xe<=a0 */ \
1441: while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
1442: /* look beyond cra, until cr->xs>a0 */ \
1443: cr=cra; while(cr<cre && (a1=cr->xs)<=a0) cr++; \
1444: if(cr<cre) a2=cr->xe+1; \
1445: else a1=a2=wid; \
1446: }
1447: #define detect_a1a2_WB { \
1448: /* find leftmost white changing pel > a0 */ \
1449: /* advance cra as far as possible s.t. cra->xe<=a0 */ \
1450: while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
1451: /* look beyond cra, until cr->xe+1>a0 */ \
1452: cr=cra; while(cr<cre && (a1=cr->xe+1)<=a0) cr++; \
1453: if(cr<cre) { \
1454: if((cr+1)<cre) a2=(cr+1)->xs; \
1455: else a2=wid; \
1456: } \
1457: else a1=a2=wid; \
1458: }
1459: #define detect_a1a2 {if(a0_color==DST_white) detect_a1a2_BW else detect_a1a2_WB;}
1460: #define detect_b1b2_BW {\
1461: /* find leftmost black changing pel > a0 */ \
1462: /* advance pra as far as possible s.t. pra->xe<=a0 */ \
1463: while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
1464: /* look beyond pra */ \
1465: pr=pra; while(pr<pre && (b1=pr->xs)<=a0) pr++; \
1466: /* move b2 to 1st changing white pel > b1 */ \
1467: if(pr<pre) b2=pr->xe+1; \
1468: else b1=b2=wid; \
1469: }
1470: #define detect_b1b2_WB {\
1471: /* find leftmost white changing pel > a0 */ \
1472: /* advance pra as far as possible s.t. pra->xe<=a0 */ \
1473: while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
1474: /* look beyond pra */ \
1475: pr=pra; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
1476: /* move b2 to 1st changing black pel > b1 */ \
1477: if(pr<pre) { \
1478: if((pr+1)<pre) b2=(pr+1)->xs; \
1479: else b2=wid; \
1480: } \
1481: else b1=b2=wid; \
1482: }
1483: #define detect_b1b2 {if(a0_color==DST_white) detect_b1b2_BW else detect_b1b2_WB;}
1484:
1485: #if DEBUG
1486: if(dbg_rg32_e) err("rlel_to_g32(pl[%d],cl[%d],w%d)",
1487: (pl==NULL)? -1: pl->runs,
1488: (cl==NULL)? -1: cl->runs,
1489: wid);
1490: #endif
1491: /* fill so that EOL ends on byte boundary */
1492: padb(f,0,8,EOLLENGTH);
1493: #if DEBUG
1494: if(dbg_rg32_s) fprintf(stderr,"FILL +0?");
1495: #endif
1496: EOL_g32; /* begin with EOL (sic) */
1497: if(pl==NULL) /* use 1-D coding for *cl */ {
1498: int pi; /* input pixel index on line */
1499: RLE_Run *rp,*pp,*sp;
1500: putb(1,f);
1501: #if DEBUG
1502: if(dbg_rg32_r) fprintf(stderr,"1D_LINE 1\n");
1503: #endif
1504: if(cl!=NULL&&cl->runs>0) {
1505: pi=0; /* bit to write next */
1506: for(sp=(rp=cl->r)+cl->runs; rp<sp; rp++) {
1507: Wrun_g32(rp->xs-pi); pi=rp->xs;
1508: Brun_g32(rp->xe-pi+1); pi=rp->xe+1;
1509: };
1510: if((--rp)->xe+1<wid) Wrun_g32(wid-rp->xe-1);
1511: }
1512: else Wrun_g32(wid); /* blank scanline */
1513: }
1514: else /* use 2-D coding for *cl */ {
1515: RLE_Run *cr,*cre,*pr,*pre; /* into current/prior rle lines */
1516: int a0,a1,a2,b1,b2; /* indices {0,1,...} of pixels */
1517: DST_color a0_color; /* a0's color: same as a2 & b2, opp of a1 & b1 */
1518: RLE_Run *cra; /* rightmost in current st xe<=a0 (none: ==cl->r) */
1519: RLE_Run *pra; /* rightmost in prior st xe<=a0 (none: ==pl->r) */
1520: int a01,a12,a1b1; /* lengths of runs a0-a1 a1-a2 a1-b1 */
1521: putb(0,f);
1522: #if DEBUG
1523: if(dbg_rg32_r) fprintf(stderr,"2D_LINE 0\n");
1524: #endif
1525: /* start on an imaginary white pixel just to left of margin */
1526: a0= -1; a0_color = DST_white;
1527: pre = (pra=pl->r) + pl->runs; /* prior line's runs */
1528: /* start b1/b2 on prior line's first black pixel, etc;
1529: if none, then place off end of line */
1530: if(pra<pre) {b1=pra->xs; b2=pra->xe+1;} else b1=b2=wid;
1531: if(cl!=NULL&&cl->runs>0) {
1532: cre = (cra=cl->r) + cl->runs;
1533: a1=cra->xs; a2=cra->xe+1;
1534: #if rg32_strict
1535: while(a0 < wid) {
1536: #else
1537: while(a0 < wid-1) {
1538: #endif
1539: /* a0, a1, a2, b1, b2 are as in CCITT Rec T.4 */
1540: #if DEBUG
1541: if(dbg_rg32_r)
1542: fprintf(stderr,"f%d(%d,%d,%d) b%d(%d,%d)\n",
1543: cra-(cl->r),a0,a1,a2,pra-(pl->r),b1,b2);
1544: #endif
1545: if(b2<a1) /* PASS mode */ {
1546: PASS_g32;
1547: a0=b2;
1548: /* a0-color, a1, & a2 are unchanged */
1549: detect_b1b2;
1550: }
1551: else if((a1b1=(a1-b1))<=3 && a1b1>= -3) {
1552: /* VERTICAL mode */
1553: switch(a1b1) {
1554: case -3: VL3_g32; break;
1555: case -2: VL2_g32; break;
1556: case -1: VL1_g32; break;
1557: case 0: V0_g32; break;
1558: case 1: VR1_g32; break;
1559: case 2: VR2_g32; break;
1560: case 3: VR3_g32; break;
1561: };
1562: a0=a1; a0_color=flip_color(a0_color);
1563: detect_a1a2;
1564: detect_b1b2;
1565: }
1566: else { /* HORIZONTAL mode */
1567: HORIZ_g32;
1568: a01=a1-a0; if(a0== -1) a01--;
1569: a12=a2-a1;
1570: if(a0_color==DST_white) {
1571: Wrun_g32(a01);
1572: Brun_g32(a12);
1573: }
1574: else { Brun_g32(a01);
1575: Wrun_g32(a12);
1576: };
1577: a0=a2;
1578: /* a0_color is unchanged */
1579: detect_a1a2;
1580: detect_b1b2;
1581: };
1582: };
1583: }
1584: else /* current line is blank */ {
1585: a1=a2=wid;
1586: #if rg32_strict
1587: while(a0 < wid) {
1588: #else
1589: while(a0 < wid-1) {
1590: #endif
1591: /* a0, a1, a2, b1, b2 are as in CCITT Rec. T.4 */
1592: #if DEBUG
1593: if(dbg_rg32_r)
1594: fprintf(stderr,"f(%d,%d,%d) b%d(%d,%d)\n",
1595: a0,a1,a2,pra-(pl->r),b1,b2);
1596: #endif
1597: if(b2<a1) /* PASS mode */ {
1598: PASS_g32;
1599: a0=b2;
1600: /* a0-color, a1, & a2 are unchanged */
1601: detect_b1b2;
1602: }
1603: else if((a1b1=a1-b1)<=3 && a1b1>= -3) {
1604: /* VERTICAL mode */
1605: switch(a1b1) {
1606: case -3: VL3_g32; break;
1607: case -2: VL2_g32; break;
1608: case -1: VL1_g32; break;
1609: case 0: V0_g32; break;
1610: case 1: VR1_g32; break;
1611: case 2: VR2_g32; break;
1612: case 3: VR3_g32; break;
1613: };
1614: a0=a1; a0_color=flip_color(a0_color);
1615: /* a1, & a2 are unchanged */
1616: detect_b1b2;
1617: }
1618: else { /* HORIZONTAL mode */
1619: HORIZ_g32;
1620: a01=a1-a0; if(a0== -1) a01--;
1621: a12=a2-a1;
1622: if(a0_color==DST_white) {
1623: Wrun_g32(a01);
1624: Brun_g32(a12);
1625: }
1626: else { Brun_g32(a01);
1627: Wrun_g32(a12);
1628: };
1629: a0=a2;
1630: /* a0_color, a1, & a2 are unchanged */
1631: detect_b1b2;
1632: };
1633: };
1634: };
1635: };
1636: }
1637:
1638: EOF_to_g32(f)
1639: BITFILE *f;
1640: { char *cs;
1641: padb(f,0,8,EOLLENGTH); /* fill so that EOL ends on byte boundary */
1642: #if DEBUG
1643: if(dbg_rg32_s) fprintf(stderr,"FILL +0?");
1644: #endif
1645: /* write RTC */
1646: EOL_g32;
1647: EOL_g32;
1648: EOL_g32;
1649: EOL_g32;
1650: EOL_g32;
1651: EOL_g32;
1652: #if DEBUG
1653: if(dbg_rg32_e) fprintf(stderr,"EOF\n");
1654: #endif
1655: }
1656:
1657: /* Macro for use within g4_to_rlel, to read one 1-D Modified Huffman coded
1658: run-length of color C, placing the result in variable V.
1659: Exceptionally, goto trap_eol, trap_eof, or trap_code_err.
1660: */
1661: #if DEBUG
1662: #define g4_1d_run(C,V) { \
1663: run = 0; \
1664: do { cx.tr.s = (C); \
1665: do { px = cx; \
1666: switch(bitv=getb(f)) { \
1667: case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \
1668: case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \
1669: case EOF : goto trap_eof; break; \
1670: }; \
1671: } \
1672: while(cx.tr.a==DST_action_NULL); \
1673: switch(cx.tr.a) { \
1674: case DST_EOL : \
1675: if(dbg_g4r_c)fprintf(stderr,"EOL %s\n",EOLSTRING); \
1676: goto trap_eol; \
1677: break; \
1678: case DST_action_ERROR : goto trap_code_err; break; \
1679: default : \
1680: if(dbg_g4r_c)fprintf(stderr,"%s%6d %s%d\n", \
1681: ((C)==DST_white)? "W": "B", \
1682: cx.tr.a, \
1683: t->e[px.tr.s].p, \
1684: bitv); \
1685: run += cx.tr.a; \
1686: break; \
1687: }; \
1688: } \
1689: while(cx.tr.a>63); \
1690: (V) = run; \
1691: }
1692: #else
1693: #define g4_1d_run(C,V) { \
1694: run = 0; \
1695: do { cx.tr.s = (C); \
1696: do { px = cx; \
1697: switch(bitv=getb(f)) { \
1698: case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \
1699: case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \
1700: case EOF : goto trap_eof; break; \
1701: }; \
1702: } \
1703: while(cx.tr.a==DST_action_NULL); \
1704: switch(cx.tr.a) { \
1705: case DST_EOL : \
1706: goto trap_eol; \
1707: break; \
1708: case DST_action_ERROR : goto trap_code_err; break; \
1709: default : \
1710: run += cx.tr.a; \
1711: break; \
1712: }; \
1713: } \
1714: while(cx.tr.a>63); \
1715: (V) = run; \
1716: }
1717: #endif
1718:
1719: /* Translate a stream of bits in CCITT FAX Group 4 compression format, of known
1720: fixed line-length, into a sequence of RLE_Lines. Returns one (RLE_Line *)
1721: on each call (or NULL if EOF or error). The first pixel (black or white)
1722: in each g4 line is assigned run index 0.
1723: WARNING: the RLE_Line returned must NOT be modified by the caller, since
1724: it is used to decode the next line. */
1725: RLE_Line *g4_to_rlel(t,f,bof,len)
1726: DST_table *t;
1727: BITFILE *f;
1728: boolean bof; /* beginning of file */
1729: int len; /* line-length in pixels (used only on bof) */
1730: #define dbg_g4r_e (0) /* trace entry-to / exit-from function */
1731: #define dbg_g4r_r (0) /* trace each run/EOL/ERR_SYN */
1732: #define dbg_g4r_c (0) /* trace each Huffman code (or, fill+EOL)*/
1733: #define dbg_g4r_t (0) /* trace each state-transition */
1734: #define g4r_strict (1) /* 1 is CORRECT: explicitly code the last black pel */
1735: { static RLE_Line rl0,rl1,*prl,*crl; /* prior, current run-lines */
1736: RLE_Line *swrl;
1737: int bitv; /* the last-read bit value */
1738: DST_context cx,px; /* the current/prior decoding context */
1739: RLE_Run *cr,*pr,*pre; /* into current/prior rle lines */
1740: RLE_Run *pra0; /* rightmost in prior line with xe<=a0
1741: (if none: prl->r) */
1742: int run,sync,si,rtc_eols;
1743: /* pixel indices (0,1,...): current-line a*; prior-line b*.
1744: a0 is the index of the most recently completely encoded bit */
1745: int a0,a1,a2,b1,b2;
1746: DST_color a0_color; /* a0's color: same as a2 & b2, opposite of a1 & b1 */
1747: int a01,a12; /* lengths of runs a0-a1 & a1-a2 */
1748: #define g4_first_color (DST_white) /* color of 1st run in each line */
1749: #define g4_negative (0) /* if 1, invert Black/White on output */
1750: #define swap_rl(f,b) {swrl=(f); (f)=(b); (b)=swrl;}
1751: /* detect b1 & b2: sensitive to a0, a0_color, and prior runs *pr *(pr+1) */
1752: #define g4r_find_Bb1Wb2 { \
1753: /* find 1st black changing pel>a0 */ \
1754: /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
1755: while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
1756: /* look beyond pra0 */ \
1757: pr=pra0; while(pr<pre && (b1=pr->xs)<=a0) pr++; \
1758: /* move b2 to 1st changing white pel > b1 */ \
1759: if(pr<pre) b2=pr->xe+1; \
1760: else b1=b2=prl->len; \
1761: }
1762: #define g4r_find_Wb1Bb2 { \
1763: /* find 1st white changing pel>a0 */ \
1764: /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
1765: while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
1766: /* look beyond pra0 */ \
1767: pr=pra0; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
1768: /* move b2 to 1st changing black pel > b1 */ \
1769: if(pr<pre) { \
1770: if((pr+1)<pre) b2=(pr+1)->xs; \
1771: else b2=prl->len; \
1772: } \
1773: else b1=b2=prl->len; \
1774: }
1775: #define g4r_find_b1b2 { \
1776: if(a0_color==DST_white) g4r_find_Bb1Wb2 else g4r_find_Wb1Bb2; \
1777: if(b1<=a0) err("g4_to_rlel: y%d: b1 %d <= a0 %d ?",crl->y,a0,b1); \
1778: }
1779:
1780: if(bof){/* initial reference line is all white, of known length */
1781: prl= &rl0; prl->y= -1; prl->len=len; prl->runs=0;
1782: /* initial coding line has y-coordinate 0 */
1783: crl= &rl1; crl->y=0; crl->len=0; crl->runs=0;
1784: }
1785: else crl->y = prl->y + 1;
1786: #if DEBUG
1787: if(dbg_g4r_e)
1788: fprintf(stderr,
1789: "g4_to_rlel(t,f,bof%d,len%d) y%d,l%d\n",
1790: bof,len,prl->y,prl->len);
1791: #endif
1792:
1793: pre = (pra0=pr=prl->r) + prl->runs; /* prior line */
1794: crl->runs=0; cr=crl->r-1; /* current line */
1795: /* start on an imaginary white pixel just to left of margin */
1796: a0= -1; a0_color = DST_white;
1797: #if DEBUG
1798: a1=a2=b1=b2=0; /* immaterial; looks better when debugging */
1799: #endif
1800:
1801: /* start b1/b2 on prior line's first black pixel, etc;
1802: if none, then place off end of line */
1803: if(pr<pre) {b1=pr->xs; b2=pr->xe+1;} else b1=b2=prl->len;
1804: /* parse a sequence of 2D codes... */
1805: while(T/* exit only via 'goto trap_X' */) {
1806: /* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */
1807: #if DEBUG
1808: if(dbg_g4r_r)
1809: fprintf(stderr,"a(%d,%d,%d) b(%d,%d)\n",a0,a1,a2,b1,b2);
1810: #endif
1811: cx.tr.s = DST_2d; cx.tr.a = DST_action_NULL;
1812: #if DEBUG
1813: if(dbg_g4r_t)fprintf(stderr,"(%d,%d)\n",cx.tr.s,cx.tr.a);
1814: #endif
1815: do { switch(bitv=getb(f)) {
1816: case 0 :
1817: case 1 :
1818: cx.tr=t->e[cx.tr.s].t[bitv];
1819: break;
1820: case EOF: goto trap_eof; break;
1821: };
1822: #if DEBUG
1823: if(dbg_g4r_t)fprintf(stderr,"%d->(%d,%d)\n",
1824: bitv,cx.tr.s,cx.tr.a);
1825: #endif
1826: }
1827: while(cx.tr.a==DST_action_NULL);
1828: #if DEBUG
1829: if(dbg_g4r_t)fprintf(stderr,"%s %04d %s0\n",
1830: (cx.c==DST_white)? "W": "B",
1831: cx.tr.s,
1832: t->e[cx.tr.s].p);
1833: #endif
1834: switch(cx.tr.a) {
1835: case i2D_V0:
1836: #if DEBUG
1837: if(dbg_g4r_c)
1838: fprintf(stderr,"V0 %s\n",code2d[cx.tr.a]);
1839: #endif
1840: a1=b1;
1841: /* interpret (a0,a1-1] */
1842: if(a0_color==DST_black) cr->xe=a1-1;
1843: /* move a0 to a1 */
1844: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1845: a0_color = flip_color(a0_color);
1846: /* interpret a0 */
1847: if(a0_color==DST_black) {
1848: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1849: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
1850: crl->y,crl->runs,cr->xs,cr->xe);
1851: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
1852: };
1853: #if !g4r_strict
1854: if(a0==prl->len-1)
1855: { a0++; goto trap_expecting_eol; };
1856: #endif
1857: g4r_find_b1b2;
1858: break;
1859: case i2D_VR1:
1860: #if DEBUG
1861: if(dbg_g4r_c)
1862: fprintf(stderr,"VR1 %s\n",code2d[cx.tr.a]);
1863: #endif
1864: a1=b1+1;
1865: /* encode a0 to a1-1 */
1866: if(a0_color==DST_black) cr->xe=a1-1;
1867: /* move a0 to a1 */
1868: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1869: a0_color = flip_color(a0_color);
1870: /* encode a0 */
1871: if(a0_color==DST_black) {
1872: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1873: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
1874: crl->y,crl->runs,cr->xs,cr->xe);
1875: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
1876: };
1877: #if !g4r_strict
1878: if(a0==prl->len-1)
1879: { a0++; goto trap_expecting_eol; };
1880: #endif
1881: g4r_find_b1b2;
1882: break;
1883: case i2D_VR2:
1884: #if DEBUG
1885: if(dbg_g4r_c)
1886: fprintf(stderr,"VR2 %s\n",code2d[cx.tr.a]);
1887: #endif
1888: a1=b1+2;
1889: /* encode a0 to a1-1 */
1890: if(a0_color==DST_black) cr->xe=a1-1;
1891: /* move a0 to a1 */
1892: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1893: a0_color = flip_color(a0_color);
1894: /* encode a0 */
1895: if(a0_color==DST_black) {
1896: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1897: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
1898: crl->y,crl->runs,cr->xs,cr->xe);
1899: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
1900: };
1901: #if !g4r_strict
1902: if(a0==prl->len-1)
1903: { a0++; goto trap_expecting_eol; };
1904: #endif
1905: g4r_find_b1b2;
1906: break;
1907: case i2D_VR3:
1908: #if DEBUG
1909: if(dbg_g4r_c)
1910: fprintf(stderr,"VR3 %s\n",code2d[cx.tr.a]);
1911: #endif
1912: a1=b1+3;
1913: /* encode a0 to a1-1 */
1914: if(a0_color==DST_black) cr->xe=a1-1;
1915: /* move a0 to a1 */
1916: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1917: a0_color = flip_color(a0_color);
1918: /* encode a0 */
1919: if(a0_color==DST_black) {
1920: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1921: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
1922: crl->y,crl->runs,cr->xs,cr->xe);
1923: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
1924: };
1925: #if !g4r_strict
1926: if(a0==prl->len-1)
1927: { a0++; goto trap_expecting_eol; };
1928: #endif
1929: g4r_find_b1b2;
1930: break;
1931: case i2D_VL1:
1932: #if DEBUG
1933: if(dbg_g4r_c)
1934: fprintf(stderr,"VL1 %s\n",code2d[cx.tr.a]);
1935: #endif
1936: if((a1=b1-1)<=a0)
1937: err("g4_to_rlel: y%d: VL1 a1 %d <= a0 %d ?",
1938: crl->y,a1,a0);
1939: /* encode a0 to a1-1 */
1940: if(a0_color==DST_black) cr->xe=a1-1;
1941: /* move a0 to a1 */
1942: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1943: a0_color = flip_color(a0_color);
1944: /* encode a0 */
1945: if(a0_color==DST_black) {
1946: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1947: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
1948: crl->y,crl->runs,cr->xs,cr->xe);
1949: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
1950: };
1951: #if !g4r_strict
1952: if(a0==prl->len-1)
1953: { a0++; goto trap_expecting_eol; };
1954: #endif
1955: g4r_find_b1b2;
1956: break;
1957: case i2D_VL2:
1958: #if DEBUG
1959: if(dbg_g4r_c)
1960: fprintf(stderr,"VL2 %s\n",code2d[cx.tr.a]);
1961: #endif
1962: if((a1=b1-2)<=a0)
1963: err("g4_to_rlel: y%d: VL2 a1 %d <= a0 %d ?",
1964: crl->y,a1,a0);
1965: /* encode a0 to a1-1 */
1966: if(a0_color==DST_black) cr->xe=a1-1;
1967: /* move a0 to a1 */
1968: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1969: a0_color = flip_color(a0_color);
1970: /* encode a0 */
1971: if(a0_color==DST_black) {
1972: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1973: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
1974: crl->y,crl->runs,cr->xs,cr->xe);
1975: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
1976: };
1977: #if !g4r_strict
1978: if(a0==prl->len-1)
1979: { a0++; goto trap_expecting_eol; };
1980: #endif
1981: g4r_find_b1b2;
1982: break;
1983: case i2D_VL3:
1984: #if DEBUG
1985: if(dbg_g4r_c)
1986: fprintf(stderr,"VL3 %s\n",code2d[cx.tr.a]);
1987: #endif
1988: if((a1=b1-3)<=a0)
1989: err("g4_to_rlel: y%d: VL3 a1 %d <= a0 %d ?",
1990: crl->y,a1,a0);
1991: /* encode a0 to a1-1 */
1992: if(a0_color==DST_black) cr->xe=a1-1;
1993: /* move a0 to a1 */
1994: a0=a1; if(a0>=prl->len) goto trap_expecting_eol;
1995: a0_color = flip_color(a0_color);
1996: /* encode a0 */
1997: if(a0_color==DST_black) {
1998: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
1999: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
2000: crl->y,crl->runs,cr->xs,cr->xe);
2001: crl->runs++; (++cr)->xs = a0; cr->xe = a0;
2002: };
2003: #if !g4r_strict
2004: if(a0==prl->len-1)
2005: { a0++; goto trap_expecting_eol; };
2006: #endif
2007: g4r_find_b1b2;
2008: break;
2009: case i2D_PASS:
2010: #if DEBUG
2011: if(dbg_g4r_c)
2012: fprintf(stderr,"PASS %s\n",code2d[cx.tr.a]);
2013: #endif
2014: /* move a0 to b2; no change of color */
2015: a0=b2; if(a0>=prl->len) goto trap_expecting_eol;
2016: if(a0_color==DST_black) cr->xe = a0;
2017: #if !g4r_strict
2018: if(a0==prl->len-1)
2019: { a0++; goto trap_expecting_eol; };
2020: #endif
2021: g4r_find_b1b2;
2022: break;
2023: case i2D_HORIZ:
2024: #if DEBUG
2025: if(dbg_g4r_c)
2026: fprintf(stderr,"HORIZ %s\n",code2d[cx.tr.a]);
2027: #endif
2028: if(a0_color==DST_white) {
2029: if(a0<0) a0=0; /* first run in line starts at 0 */
2030: g4_1d_run(DST_white,a01); a1 = a0 + a01;
2031: g4_1d_run(DST_black,a12); a2 = a1 + a12;
2032: if(a12>0) /* Black run of >0 length */ {
2033: if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
2034: err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
2035: crl->y,crl->runs,cr->xs,cr->xe);
2036: crl->runs++; (++cr)->xs = a1; cr->xe = a2-1;
2037: };
2038: a0 = a2; /* still white */
2039: if(a0>=prl->len) goto trap_expecting_eol;
2040: /* encode a0 */
2041: #if !g4r_strict
2042: if(a0==prl->len-1)
2043: { a0++; goto trap_expecting_eol; };
2044: #endif
2045: g4r_find_Bb1Wb2;
2046: }
2047: else { g4_1d_run(DST_black,a01); a1 = a0 + a01;
2048: g4_1d_run(DST_white,a12); a2 = a1 + a12;
2049: if(a01>0) /* Black run of >0 length */ {
2050: cr->xe = a1 - 1;
2051: }
2052: else { /* 0-length: very peculiar: ignore */
2053: fprintf(stderr,
2054: "g4_to_rlel: HORIZ B%d! W%d - ignore\n",
2055: a01,a12);
2056: cr--; crl->runs--;
2057: };
2058: a0 = a2; /* still black */
2059: if(a0>=prl->len) goto trap_expecting_eol;
2060: /* encode a0 */
2061: crl->runs++; (++cr)->xs = a0;
2062: #if !g4r_strict
2063: if(a0==prl->len-1) {
2064: cr->xe = a0;
2065: a0++;
2066: goto trap_expecting_eol;
2067: };
2068: #endif
2069: g4r_find_Wb1Bb2;
2070: };
2071: break;
2072: case i2D_EOL:
2073: #if DEBUG
2074: if(dbg_g4r_c)
2075: fprintf(stderr,"EOL %s\n",code2d[cx.tr.a]);
2076: #endif
2077: goto trap_eol;
2078: break;
2079: case DST_action_ERROR: goto trap_code_err; break;
2080: };
2081: };
2082:
2083: /* come here via goto's: all these traps return() */
2084:
2085: trap_expecting_eol: /* come here having detected (computed) end-of-line */
2086: /* learn/check/correct line-length */
2087: crl->len = (a0>0)? a0 : 0;
2088: if(crl->len!=prl->len) {
2089: err("g4_to_rlel: y%d: LINELEN changes c%d != p%d ? (force to %d)",
2090: crl->y,crl->len,prl->len,prl->len);
2091: crl->len = prl->len;
2092: };
2093: swap_rl(crl,prl);
2094: #if DEBUG
2095: if(dbg_g4r_e)
2096: fprintf(stderr,
2097: "exit g4_to_rlel: expg_eol y%d,l%d\n",
2098: prl->y,prl->len);
2099: #endif
2100: return(prl);
2101:
2102: trap_eol: /* come here having seen an EOL code (rare in Group 4) */
2103: /* It must be the first of two EOL codes making up the EOB signal */
2104: /* look for 2nd EOL */
2105: sync=0; while((bitv=getb(f))==0) sync++;
2106: switch(bitv) {
2107: case 1:
2108: if(sync==11) {
2109: #if DEBUG
2110: if(dbg_g4r_c) {
2111: fprintf(stderr,"EOB_EOL %s\n",EOLSTRING);
2112: fprintf(stderr,"EOB\n");
2113: };
2114: #endif
2115: }
2116: else {
2117: #if DEBUG
2118: if(dbg_g4r_c){
2119: fprintf(stderr,"NOT EOB ");
2120: for(si=0;si<sync;si++)
2121: fprintf(stderr,"0");
2122: fprintf(stderr,"1?\n");
2123: fprintf(stderr,"ABORT\n");
2124: };
2125: #endif
2126: };
2127: break;
2128: case EOF: goto trap_eof; break;
2129: };
2130: #if DEBUG
2131: if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: eol\n");
2132: #endif
2133: return(NULL);
2134:
2135: trap_code_err:
2136: /* unexpected coding sequence:
2137: 'px' holds last decoding context & 'bitv' latest bit value;
2138: will attempt to resynchronize on next EOL */
2139: #if DEBUG
2140: if(dbg_g4r_c)fprintf(stderr,"CODERR %s%d? (px.tr.s=%d)\n",
2141: t->e[px.tr.s].p,bitv,px.tr.s);
2142: #endif
2143: err("g4_to_rlel: code error");
2144: #if DEBUG
2145: if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: code_err\n");
2146: #endif
2147: return(NULL);
2148:
2149: trap_eof:
2150: #if DEBUG
2151: if(dbg_g4r_c) fprintf(stderr,"<EOF>\n");
2152: if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: eof\n");
2153: #endif
2154: return(NULL);
2155:
2156: }
2157:
2158: /* Translate a sequence of RLE_Line's (describing a binary image)
2159: into a file (a stream of bits) in CCITT FAX Group 4 compression format.
2160: BOF_to_g4() must be called first; then call rlel_to_g4() for each line
2161: (including blank lines); finally, EOF_to_g4() must be called. The EOFB
2162: is padded (suffixed) with 0's to a byte boundary if necessary; no other
2163: filling or padding is performed.
2164: */
2165: /* debugging flags: trace to stderr */
2166: #define dbg_rg4_e (0) /* entry */
2167: #define dbg_rg4_r (0) /* runs */
2168: #define dbg_rg4_c (0) /* codes (bitstrings) */
2169: #define rg4_strict (1) /* 1 is CORRECT: explicitly code the last black pel */
2170:
2171: #if DEBUG
2172: #define bits_g4(bits) { \
2173: cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \
2174: if(dbg_rg4_c) fprintf(stderr,"%s",(bits)); \
2175: if(dbg_rg4_r) fprintf(stderr," "); \
2176: }
2177: #else
2178: #define bits_g4(bits) { \
2179: cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \
2180: }
2181: #endif
2182: #if DEBUG
2183: #define EOFB_g4 { \
2184: if(dbg_rg4_r) fprintf(stderr,"EOFB "); \
2185: bits_g4(EOFB); \
2186: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2187: }
2188: #else
2189: #define EOFB_g4 { \
2190: bits_g4(EOFB); \
2191: }
2192: #endif
2193:
2194: BOF_to_g4(f)
2195: BITFILE *f;
2196: { char *cs;
2197: /* a NOP: no header for Group 4 */
2198: #if DEBUG
2199: if(dbg_rg4_e) fprintf(stderr,"BOF\n");
2200: #endif
2201: };
2202:
2203: rlel_to_g4(pl,cl,wid,f)
2204: RLE_Line *pl; /* prior "reference" line */
2205: RLE_Line *cl; /* current "coding" line: if NULL, is blank (all white) */
2206: int wid; /* width of an output line in pixels */
2207: BITFILE *f;
2208: { int runl,codi;
2209: char *cs,*p01;
2210: #if DEBUG
2211: #define Wrun_g4(rn) { \
2212: runl=(rn); \
2213: if(dbg_rg4_r) fprintf(stderr,"W %5d ",runl); \
2214: while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
2215: p01=codewht[codi=rtoi(runl)]; bits_g4(p01); \
2216: if(codi>=64) {p01=codewht[runl%64]; bits_g4(p01);}; \
2217: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2218: }
2219: #else
2220: #define Wrun_g4(rn) { \
2221: runl=(rn); \
2222: while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
2223: p01=codewht[codi=rtoi(runl)]; bits_g4(p01); \
2224: if(codi>=64) {p01=codewht[runl%64]; bits_g4(p01);}; \
2225: }
2226: #endif
2227: #if DEBUG
2228: #define Brun_g4(rn) { \
2229: runl=(rn); \
2230: if(dbg_rg4_r) fprintf(stderr,"B %5d ",runl); \
2231: while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
2232: p01=codeblk[codi=rtoi(runl)]; bits_g4(p01); \
2233: if(codi>=64) {p01=codeblk[runl%64]; bits_g4(p01);}; \
2234: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2235: }
2236: #else
2237: #define Brun_g4(rn) { \
2238: runl=(rn); \
2239: while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
2240: p01=codeblk[codi=rtoi(runl)]; bits_g4(p01); \
2241: if(codi>=64) {p01=codeblk[runl%64]; bits_g4(p01);}; \
2242: }
2243: #endif
2244: #if DEBUG
2245: #define V0_g4 { \
2246: if(dbg_rg4_r) fprintf(stderr,"V0 "); \
2247: bits_g4(code2d[i2D_V0]); \
2248: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2249: }
2250: #else
2251: #define V0_g4 { \
2252: bits_g4(code2d[i2D_V0]); \
2253: }
2254: #endif
2255: #if DEBUG
2256: #define VR1_g4 { \
2257: if(dbg_rg4_r) fprintf(stderr,"VR1 "); \
2258: bits_g4(code2d[i2D_VR1]); \
2259: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2260: }
2261: #else
2262: #define VR1_g4 { \
2263: bits_g4(code2d[i2D_VR1]); \
2264: }
2265: #endif
2266: #if DEBUG
2267: #define VR2_g4 { \
2268: if(dbg_rg4_r) fprintf(stderr,"VR2 "); \
2269: bits_g4(code2d[i2D_VR2]); \
2270: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2271: }
2272: #else
2273: #define VR2_g4 { \
2274: bits_g4(code2d[i2D_VR2]); \
2275: }
2276: #endif
2277: #if DEBUG
2278: #define VR3_g4 { \
2279: if(dbg_rg4_r) fprintf(stderr,"VR3 "); \
2280: bits_g4(code2d[i2D_VR3]); \
2281: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2282: }
2283: #else
2284: #define VR3_g4 { \
2285: bits_g4(code2d[i2D_VR3]); \
2286: }
2287: #endif
2288: #if DEBUG
2289: #define VL1_g4 { \
2290: if(dbg_rg4_r) fprintf(stderr,"VL1 "); \
2291: bits_g4(code2d[i2D_VL1]); \
2292: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2293: }
2294: #else
2295: #define VL1_g4 { \
2296: bits_g4(code2d[i2D_VL1]); \
2297: }
2298: #endif
2299: #if DEBUG
2300: #define VL2_g4 { \
2301: if(dbg_rg4_r) fprintf(stderr,"VL2 "); \
2302: bits_g4(code2d[i2D_VL2]); \
2303: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2304: }
2305: #else
2306: #define VL2_g4 { \
2307: bits_g4(code2d[i2D_VL2]); \
2308: }
2309: #endif
2310: #if DEBUG
2311: #define VL3_g4 { \
2312: if(dbg_rg4_r) fprintf(stderr,"VL3 "); \
2313: bits_g4(code2d[i2D_VL3]); \
2314: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2315: }
2316: #else
2317: #define VL3_g4 { \
2318: bits_g4(code2d[i2D_VL3]); \
2319: }
2320: #endif
2321: #if DEBUG
2322: #define PASS_g4 { \
2323: if(dbg_rg4_r) fprintf(stderr,"PASS "); \
2324: bits_g4(code2d[i2D_PASS]); \
2325: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2326: }
2327: #else
2328: #define PASS_g4 { \
2329: bits_g4(code2d[i2D_PASS]); \
2330: }
2331: #endif
2332: #if DEBUG
2333: #define HORIZ_g4 { \
2334: if(dbg_rg4_r) fprintf(stderr,"HORIZ "); \
2335: bits_g4(code2d[i2D_HORIZ]); \
2336: if(dbg_rg4_r) fprintf(stderr,"\n"); \
2337: }
2338: #else
2339: #define HORIZ_g4 { \
2340: bits_g4(code2d[i2D_HORIZ]); \
2341: }
2342: #endif
2343: #define detect_a1a2_BW { \
2344: /* find leftmost black changing pel > a0 */ \
2345: /* advance cra as far as possible s.t. cra->xe<=a0 */ \
2346: while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
2347: /* look beyond cra, until cr->xs>a0 */ \
2348: cr=cra; while(cr<cre && (a1=cr->xs)<=a0) cr++; \
2349: if(cr<cre) a2=cr->xe+1; \
2350: else a1=a2=wid; \
2351: }
2352: #define detect_a1a2_WB { \
2353: /* find leftmost white changing pel > a0 */ \
2354: /* advance cra as far as possible s.t. cra->xe<=a0 */ \
2355: while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
2356: /* look beyond cra, until cr->xe+1>a0 */ \
2357: cr=cra; while(cr<cre && (a1=cr->xe+1)<=a0) cr++; \
2358: if(cr<cre) { \
2359: if((cr+1)<cre) a2=(cr+1)->xs; \
2360: else a2=wid; \
2361: } \
2362: else a1=a2=wid; \
2363: }
2364: #define detect_a1a2 {if(a0_color==DST_white) detect_a1a2_BW else detect_a1a2_WB;}
2365: #define detect_b1b2_BW {\
2366: /* find leftmost black changing pel > a0 */ \
2367: /* advance pra as far as possible s.t. pra->xe<=a0 */ \
2368: while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
2369: /* look beyond pra */ \
2370: pr=pra; while(pr<pre && (b1=pr->xs)<=a0) pr++; \
2371: /* move b2 to 1st changing white pel > b1 */ \
2372: if(pr<pre) b2=pr->xe+1; \
2373: else b1=b2=wid; \
2374: }
2375: #define detect_b1b2_WB {\
2376: /* find leftmost white changing pel > a0 */ \
2377: /* advance pra as far as possible s.t. pra->xe<=a0 */ \
2378: while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
2379: /* look beyond pra */ \
2380: pr=pra; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
2381: /* move b2 to 1st changing black pel > b1 */ \
2382: if(pr<pre) { \
2383: if((pr+1)<pre) b2=(pr+1)->xs; \
2384: else b2=wid; \
2385: } \
2386: else b1=b2=wid; \
2387: }
2388: #define detect_b1b2 {if(a0_color==DST_white) detect_b1b2_BW else detect_b1b2_WB;}
2389:
2390: RLE_Run *cr,*cre,*pr,*pre; /* into current/prior rle lines */
2391: int a0,a1,a2,b1,b2; /* indices {0,1,...} of pixels */
2392: DST_color a0_color; /* a0's color: same as a2 & b2, opp of a1 & b1 */
2393: RLE_Run *cra; /* rightmost in current st xe<=a0 (none: ==cl->r) */
2394: RLE_Run *pra; /* rightmost in prior st xe<=a0 (none: ==pl->r) */
2395: int a01,a12,a1b1; /* lengths of runs a0-a1 a1-a2 a1-b1 */
2396: #if DEBUG
2397: if(dbg_rg4_e) err("rlel_to_g4(pl[%d],cl[%d],w%d)",
2398: (pl==NULL)? -1: pl->runs,
2399: (cl==NULL)? -1: cl->runs,
2400: wid);
2401: #endif
2402: /* start on an imaginary white pixel just to left of margin */
2403: a0= -1; a0_color = DST_white;
2404: pre = (pra=pl->r) + pl->runs; /* prior line's runs */
2405: /* start b1/b2 on prior line's first black pixel, etc;
2406: if none, then place off end of line */
2407: if(pra<pre) {b1=pra->xs; b2=pra->xe+1;} else b1=b2=wid;
2408: if(cl!=NULL&&cl->runs>0) {
2409: cre = (cra=cl->r) + cl->runs;
2410: a1=cra->xs; a2=cra->xe+1;
2411: #if rg4_strict
2412: while( a0 < wid ) {
2413: #else
2414: while( a0 < wid-1 ) {
2415: #endif
2416: /* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */
2417: #if DEBUG
2418: if(dbg_rg4_r)
2419: fprintf(stderr,"f%d(%d,%d,%d) b%d(%d,%d)\n",
2420: cra-(cl->r),a0,a1,a2,pra-(pl->r),b1,b2);
2421: #endif
2422: if(b2<a1) /* PASS mode */ {
2423: PASS_g4;
2424: a0=b2;
2425: /* a0-color, a1, & a2 are unchanged */
2426: detect_b1b2;
2427: }
2428: else if((a1b1=(a1-b1))<=3 && a1b1>= -3) {
2429: /* VERTICAL mode */
2430: switch(a1b1) {
2431: case -3: VL3_g4; break;
2432: case -2: VL2_g4; break;
2433: case -1: VL1_g4; break;
2434: case 0: V0_g4; break;
2435: case 1: VR1_g4; break;
2436: case 2: VR2_g4; break;
2437: case 3: VR3_g4; break;
2438: };
2439: a0=a1; a0_color=flip_color(a0_color);
2440: detect_a1a2;
2441: detect_b1b2;
2442: }
2443: else { /* HORIZONTAL mode */
2444: HORIZ_g4;
2445: a01=a1-a0; if(a0== -1) a01--;
2446: a12=a2-a1;
2447: if(a0_color==DST_white) {
2448: Wrun_g4(a01);
2449: Brun_g4(a12);
2450: }
2451: else { Brun_g4(a01);
2452: Wrun_g4(a12);
2453: };
2454: a0=a2;
2455: /* a0_color is unchanged */
2456: detect_a1a2;
2457: detect_b1b2;
2458: };
2459: };
2460: }
2461: else /* current line is blank */ {
2462: a1=a2=wid;
2463: #if rg4_strict
2464: while( a0 < wid ) {
2465: #else
2466: while( a0 < wid-1 ) {
2467: #endif
2468: /* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */
2469: #if DEBUG
2470: if(dbg_rg4_r)
2471: fprintf(stderr,"f(%d,%d,%d) b%d(%d,%d)\n",
2472: a0,a1,a2,pra-(pl->r),b1,b2);
2473: #endif
2474: if(b2<a1) /* PASS mode */ {
2475: PASS_g4;
2476: a0=b2;
2477: /* a0-color, a1, & a2 are unchanged */
2478: detect_b1b2;
2479: }
2480: else if((a1b1=a1-b1)<=3 && a1b1>= -3) {
2481: /* VERTICAL mode */
2482: switch(a1b1) {
2483: case -3: VL3_g4; break;
2484: case -2: VL2_g4; break;
2485: case -1: VL1_g4; break;
2486: case 0: V0_g4; break;
2487: case 1: VR1_g4; break;
2488: case 2: VR2_g4; break;
2489: case 3: VR3_g4; break;
2490: };
2491: a0=a1; a0_color=flip_color(a0_color);
2492: /* a1, & a2 are unchanged */
2493: detect_b1b2;
2494: }
2495: else { /* HORIZONTAL mode */
2496: HORIZ_g4;
2497: a01=a1-a0; if(a0== -1) a01--;
2498: a12=a2-a1;
2499: if(a0_color==DST_white) {
2500: Wrun_g4(a01);
2501: Brun_g4(a12);
2502: }
2503: else { Brun_g4(a01);
2504: Wrun_g4(a12);
2505: };
2506: a0=a2;
2507: /* a0_color, a1, & a2 are unchanged */
2508: detect_b1b2;
2509: };
2510: };
2511: };
2512: }
2513:
2514: EOF_to_g4(f)
2515: BITFILE *f;
2516: { char *cs;
2517: /* write EOFB */
2518: EOFB_g4;
2519: #if DEBUG
2520: if(dbg_rg4_e) fprintf(stderr,"EOF\n");
2521: #endif
2522: }
2523:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.