|
|
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.