File indexing completed on 2024-05-12 16:06:42
0001 /* 0002 Expand one page of fax data 0003 This file is part of viewfax - g3/g4 fax processing software. 0004 SPDX-FileCopyrightText: 1990, 1995 Frank D. Cringle. 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "faxexpand.h" 0009 0010 #include <stdio.h> 0011 #include <stdlib.h> 0012 0013 #include <QDebug> 0014 0015 #include "fax_debug.h" 0016 // Uncomment this for verbose debug output 0017 //#define DEBUG_FAX 0018 #define verbose false 0019 0020 pagenode::pagenode() 0021 { 0022 } 0023 0024 /* Note that NeedBits() only works for n <= 16 */ 0025 #define NeedBits(n) \ 0026 do { \ 0027 if (BitsAvail < (n)) { \ 0028 BitAcc |= *sp++ << BitsAvail; \ 0029 BitsAvail += 16; \ 0030 } \ 0031 } while (0) 0032 #define GetBits(n) (BitAcc & ((1 << (n)) - 1)) 0033 #define ClrBits(n) \ 0034 do { \ 0035 BitAcc >>= (n); \ 0036 BitsAvail -= (n); \ 0037 } while (0) 0038 0039 #ifdef DEBUG_FAX 0040 #define DEBUG_SHOW putchar(BitAcc &(1 << t) ? '1' : '0') 0041 #define LOOKUP(wid, tab) \ 0042 do { \ 0043 int t; \ 0044 NeedBits(wid); \ 0045 TabEnt = tab + GetBits(wid); \ 0046 printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, StateNames[TabEnt->State], TabEnt->Param); \ 0047 for (t = 0; t < TabEnt->Width; t++) \ 0048 DEBUG_SHOW; \ 0049 putchar('\n'); \ 0050 fflush(stdout); \ 0051 ClrBits(TabEnt->Width); \ 0052 } while (0) 0053 0054 #define SETVAL(x) \ 0055 do { \ 0056 *pa++ = RunLength + (x); \ 0057 printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \ 0058 a0 += x; \ 0059 RunLength = 0; \ 0060 } while (0) 0061 0062 const char *StateNames[] = { 0063 "Null ", 0064 "Pass ", 0065 "Horiz ", 0066 "V0 ", 0067 "VR ", 0068 "VL ", 0069 "Ext ", 0070 "TermW ", 0071 "TermB ", 0072 "MakeUpW", 0073 "MakeUpB", 0074 "MakeUp ", 0075 "EOL ", 0076 }; 0077 0078 #else 0079 #define LOOKUP(wid, tab) \ 0080 do { \ 0081 NeedBits(wid); \ 0082 TabEnt = tab + GetBits(wid); \ 0083 ClrBits(TabEnt->Width); \ 0084 } while (0) 0085 0086 #define SETVAL(x) \ 0087 do { \ 0088 *pa++ = RunLength + (x); \ 0089 a0 += x; \ 0090 RunLength = 0; \ 0091 } while (0) 0092 #endif 0093 0094 #define dumpruns(runs) \ 0095 do { \ 0096 printf("-------------------- %d\n", LineNum); \ 0097 for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++) \ 0098 printf("%4d %d\n", a0, *pa); \ 0099 } while (0) 0100 0101 #define EndOfData(pn) (sp >= pn->data + pn->length / sizeof(*pn->data)) 0102 0103 /* This macro handles coding errors in G3 data. 0104 We redefine it below for the G4 case */ 0105 #define SKIP_EOL \ 0106 do { \ 0107 while (!EndOfData(pn)) { \ 0108 NeedBits(11); \ 0109 if (GetBits(11) == 0) \ 0110 break; \ 0111 ClrBits(1); \ 0112 } \ 0113 ClrBits(11); \ 0114 goto EOL; \ 0115 } while (0) 0116 #define eol2lab \ 0117 EOL2: 0118 0119 /* the line expanders are written as macros so that they can be reused 0120 (twice each) but still have direct access to the local variables of 0121 the "calling" function */ 0122 #define expand1d() \ 0123 do { \ 0124 while (a0 < lastx) { \ 0125 int done = 0; \ 0126 while (!done) { /* white first */ \ 0127 LOOKUP(12, WhiteTable); \ 0128 switch (TabEnt->State) { \ 0129 case S_EOL: \ 0130 EOLcnt = 1; \ 0131 goto EOL; \ 0132 case S_TermW: \ 0133 SETVAL(TabEnt->Param); \ 0134 done = 1; \ 0135 break; \ 0136 case S_MakeUpW: \ 0137 case S_MakeUp: \ 0138 a0 += TabEnt->Param; \ 0139 RunLength += TabEnt->Param; \ 0140 break; \ 0141 case S_Ext: \ 0142 unexpected("Extension code", LineNum); \ 0143 SKIP_EOL; \ 0144 break; \ 0145 default: \ 0146 unexpected("WhiteTable", LineNum); \ 0147 SKIP_EOL; \ 0148 break; \ 0149 } \ 0150 } \ 0151 done = a0 >= lastx; \ 0152 while (!done) { /* then black */ \ 0153 LOOKUP(13, BlackTable); \ 0154 switch (TabEnt->State) { \ 0155 case S_EOL: \ 0156 EOLcnt = 1; \ 0157 goto EOL; \ 0158 case S_TermB: \ 0159 SETVAL(TabEnt->Param); \ 0160 done = 1; \ 0161 break; \ 0162 case S_MakeUpB: \ 0163 case S_MakeUp: \ 0164 a0 += TabEnt->Param; \ 0165 RunLength += TabEnt->Param; \ 0166 break; \ 0167 case S_Ext: \ 0168 unexpected("Extension code", LineNum); \ 0169 SKIP_EOL; \ 0170 break; \ 0171 default: \ 0172 unexpected("BlackTable", LineNum); \ 0173 SKIP_EOL; \ 0174 break; \ 0175 } \ 0176 } \ 0177 } \ 0178 EOL:; \ 0179 } while (0) 0180 0181 #define CHECK_b1 \ 0182 do { \ 0183 if (pa != thisrun) \ 0184 while (b1 <= a0 && b1 < lastx) { \ 0185 b1 += pb[0] + pb[1]; \ 0186 pb += 2; \ 0187 } \ 0188 } while (0) 0189 0190 #define expand2d(eolab) \ 0191 do { \ 0192 while (a0 < lastx) { \ 0193 LOOKUP(7, MainTable); \ 0194 switch (TabEnt->State) { \ 0195 case S_Pass: \ 0196 CHECK_b1; \ 0197 b1 += *pb++; \ 0198 RunLength += b1 - a0; \ 0199 a0 = b1; \ 0200 b1 += *pb++; \ 0201 break; \ 0202 case S_Horiz: \ 0203 if ((pa - run0) & 1) { \ 0204 int done = 0; \ 0205 while (!done) { /* black first */ \ 0206 LOOKUP(13, BlackTable); \ 0207 switch (TabEnt->State) { \ 0208 case S_TermB: \ 0209 SETVAL(TabEnt->Param); \ 0210 done = 1; \ 0211 break; \ 0212 case S_MakeUpB: \ 0213 case S_MakeUp: \ 0214 a0 += TabEnt->Param; \ 0215 RunLength += TabEnt->Param; \ 0216 break; \ 0217 default: \ 0218 unexpected("BlackTable", LineNum); \ 0219 SKIP_EOL; \ 0220 break; \ 0221 } \ 0222 } \ 0223 done = 0; \ 0224 while (!done) { /* then white */ \ 0225 LOOKUP(12, WhiteTable); \ 0226 switch (TabEnt->State) { \ 0227 case S_TermW: \ 0228 SETVAL(TabEnt->Param); \ 0229 done = 1; \ 0230 break; \ 0231 case S_MakeUpW: \ 0232 case S_MakeUp: \ 0233 a0 += TabEnt->Param; \ 0234 RunLength += TabEnt->Param; \ 0235 break; \ 0236 default: \ 0237 unexpected("WhiteTable", LineNum); \ 0238 SKIP_EOL; \ 0239 break; \ 0240 } \ 0241 } \ 0242 } else { \ 0243 int done = 0; \ 0244 while (!done) { /* white first */ \ 0245 LOOKUP(12, WhiteTable); \ 0246 switch (TabEnt->State) { \ 0247 case S_TermW: \ 0248 SETVAL(TabEnt->Param); \ 0249 done = 1; \ 0250 break; \ 0251 case S_MakeUpW: \ 0252 case S_MakeUp: \ 0253 a0 += TabEnt->Param; \ 0254 RunLength += TabEnt->Param; \ 0255 break; \ 0256 default: \ 0257 unexpected("WhiteTable", LineNum); \ 0258 SKIP_EOL; \ 0259 break; \ 0260 } \ 0261 } \ 0262 done = 0; \ 0263 while (!done) { /* then black */ \ 0264 LOOKUP(13, BlackTable); \ 0265 switch (TabEnt->State) { \ 0266 case S_TermB: \ 0267 SETVAL(TabEnt->Param); \ 0268 done = 1; \ 0269 break; \ 0270 case S_MakeUpB: \ 0271 case S_MakeUp: \ 0272 a0 += TabEnt->Param; \ 0273 RunLength += TabEnt->Param; \ 0274 break; \ 0275 default: \ 0276 unexpected("BlackTable", LineNum); \ 0277 SKIP_EOL; \ 0278 break; \ 0279 } \ 0280 } \ 0281 } \ 0282 CHECK_b1; \ 0283 break; \ 0284 case S_V0: \ 0285 CHECK_b1; \ 0286 SETVAL(b1 - a0); \ 0287 b1 += *pb++; \ 0288 break; \ 0289 case S_VR: \ 0290 CHECK_b1; \ 0291 SETVAL(b1 - a0 + TabEnt->Param); \ 0292 b1 += *pb++; \ 0293 break; \ 0294 case S_VL: \ 0295 CHECK_b1; \ 0296 SETVAL(b1 - a0 - TabEnt->Param); \ 0297 b1 -= *--pb; \ 0298 break; \ 0299 case S_Ext: \ 0300 *pa++ = lastx - a0; \ 0301 if (verbose) \ 0302 qCDebug(FAX_LOG) << "Line " << LineNum << ": extension code\n"; \ 0303 SKIP_EOL; \ 0304 break; \ 0305 case S_EOL: \ 0306 *pa++ = lastx - a0; \ 0307 NeedBits(4); \ 0308 if (GetBits(4) && verbose) /* already seen 7 zeros */ \ 0309 qCDebug(FAX_LOG) << "Line " << LineNum << ": Bad EOL\n"; \ 0310 ClrBits(4); \ 0311 EOLcnt = 1; \ 0312 goto eolab; \ 0313 break; \ 0314 default: \ 0315 unexpected("MainTable", LineNum); \ 0316 SKIP_EOL; \ 0317 break; \ 0318 } \ 0319 } \ 0320 if (RunLength) { \ 0321 if (RunLength + a0 < lastx) { \ 0322 /* expect a final V0 */ \ 0323 NeedBits(1); \ 0324 if (!GetBits(1)) { \ 0325 unexpected("MainTable", LineNum); \ 0326 SKIP_EOL; \ 0327 } \ 0328 ClrBits(1); \ 0329 } \ 0330 SETVAL(0); \ 0331 } \ 0332 eol2lab; \ 0333 } while (0) 0334 0335 static void unexpected(const char *what, int LineNum) 0336 { 0337 if (verbose) { 0338 qCCritical(FAX_LOG) << "Line " << LineNum << ": Unexpected state in " << what; 0339 } 0340 } 0341 0342 /* Expand tiff modified huffman data (g3-1d without EOLs) */ 0343 void MHexpand(pagenode *pn, drawfunc df) 0344 { 0345 int a0; /* reference element */ 0346 int lastx; /* copy line width to register */ 0347 t32bits BitAcc; /* bit accumulator */ 0348 int BitsAvail; /* # valid bits in BitAcc */ 0349 int RunLength; /* Length of current run */ 0350 t16bits *sp; /* pointer into compressed data */ 0351 pixnum *pa; /* pointer into new line */ 0352 int EOLcnt; /* number of consecutive EOLs */ 0353 int LineNum; /* line number */ 0354 pixnum *runs; /* list of run lengths */ 0355 struct tabent *TabEnt; 0356 0357 sp = pn->data; 0358 BitAcc = 0; 0359 BitsAvail = 0; 0360 lastx = pn->size.width(); 0361 runs = (pixnum *)malloc(lastx * sizeof(pixnum)); 0362 for (LineNum = 0; LineNum < pn->rowsperstrip;) { 0363 #ifdef DEBUG_FAX 0364 printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); 0365 printf("-------------------- %d\n", LineNum); 0366 fflush(stdout); 0367 #endif 0368 RunLength = 0; 0369 pa = runs; 0370 a0 = 0; 0371 EOLcnt = 0; 0372 if (BitsAvail & 7) { /* skip to byte boundary */ 0373 ClrBits(BitsAvail & 7); 0374 } 0375 expand1d(); 0376 if (RunLength) { 0377 SETVAL(0); 0378 } 0379 if (a0 != lastx) { 0380 if (verbose) { 0381 qCWarning(FAX_LOG) << "Line " << LineNum << ": length is " << a0 << " (expected " << lastx << ")\n"; 0382 } 0383 while (a0 > lastx) { 0384 a0 -= *--pa; 0385 } 0386 if (a0 < lastx) { 0387 if ((pa - runs) & 1) { 0388 SETVAL(0); 0389 } 0390 SETVAL(lastx - a0); 0391 } 0392 } 0393 (*df)(runs, LineNum++, pn); 0394 } 0395 free(runs); 0396 (void)EOLcnt; // make gcc happy 0397 } 0398 0399 /* Expand group-3 1-dimensional data */ 0400 void g31expand(pagenode *pn, drawfunc df) 0401 { 0402 int a0; /* reference element */ 0403 int lastx; /* copy line width to register */ 0404 t32bits BitAcc; /* bit accumulator */ 0405 int BitsAvail; /* # valid bits in BitAcc */ 0406 int RunLength; /* Length of current run */ 0407 t16bits *sp; /* pointer into compressed data */ 0408 pixnum *pa; /* pointer into new line */ 0409 int EOLcnt; /* number of consecutive EOLs */ 0410 int LineNum; /* line number */ 0411 pixnum *runs; /* list of run lengths */ 0412 struct tabent *TabEnt; 0413 0414 sp = pn->data; 0415 BitAcc = 0; 0416 BitsAvail = 0; 0417 lastx = pn->size.width(); 0418 runs = (pixnum *)malloc(lastx * sizeof(pixnum)); 0419 EOLcnt = 0; 0420 for (LineNum = 0; LineNum < pn->rowsperstrip;) { 0421 #ifdef DEBUG_FAX 0422 fprintf(stderr, "\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); 0423 fprintf(stderr, "-------------------- %d\n", LineNum); 0424 fflush(stderr); 0425 #endif 0426 if (EOLcnt == 0) { 0427 while (!EndOfData(pn)) { 0428 /* skip over garbage after a coding error */ 0429 NeedBits(11); 0430 if (GetBits(11) == 0) { 0431 break; 0432 } 0433 ClrBits(1); 0434 } 0435 } 0436 for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) { 0437 /* we have seen 11 zeros, which implies EOL, 0438 skip possible fill bits too */ 0439 while (true) { 0440 NeedBits(8); 0441 if (GetBits(8)) { 0442 break; 0443 } 0444 ClrBits(8); 0445 } 0446 while (GetBits(1) == 0) { 0447 ClrBits(1); 0448 } 0449 ClrBits(1); /* the eol flag */ 0450 NeedBits(11); 0451 if (GetBits(11)) { 0452 break; 0453 } 0454 ClrBits(11); 0455 } 0456 if (EOLcnt > 1 && EOLcnt != 6 && verbose) { 0457 qCCritical(FAX_LOG) << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n"; 0458 } 0459 if (EOLcnt >= 6 || EndOfData(pn)) { 0460 free(runs); 0461 return; 0462 } 0463 RunLength = 0; 0464 pa = runs; 0465 a0 = 0; 0466 EOLcnt = 0; 0467 expand1d(); 0468 if (RunLength) { 0469 SETVAL(0); 0470 } 0471 if (a0 != lastx) { 0472 if (verbose) { 0473 qCWarning(FAX_LOG) << "Line " << LineNum << ": length is " << a0 << " (expected " << lastx << ")\n"; 0474 } 0475 while (a0 > lastx) { 0476 a0 -= *--pa; 0477 } 0478 if (a0 < lastx) { 0479 if ((pa - runs) & 1) { 0480 SETVAL(0); 0481 } 0482 SETVAL(lastx - a0); 0483 } 0484 } 0485 (*df)(runs, LineNum++, pn); 0486 } 0487 free(runs); 0488 } 0489 0490 /* Expand group-3 2-dimensional data */ 0491 void g32expand(pagenode *pn, drawfunc df) 0492 { 0493 int RunLength; /* Length of current run */ 0494 int a0; /* reference element */ 0495 int b1; /* next change on previous line */ 0496 int lastx = pn->size.width(); /* copy line width to register */ 0497 pixnum *run0, *run1; /* run length arrays */ 0498 pixnum *thisrun, *pa, *pb; /* pointers into runs */ 0499 t16bits *sp; /* pointer into compressed data */ 0500 t32bits BitAcc; /* bit accumulator */ 0501 int BitsAvail; /* # valid bits in BitAcc */ 0502 int EOLcnt; /* number of consecutive EOLs */ 0503 int refline = 0; /* 1D encoded reference line */ 0504 int LineNum; /* line number */ 0505 struct tabent *TabEnt; 0506 0507 sp = pn->data; 0508 BitAcc = 0; 0509 BitsAvail = 0; 0510 /* allocate space for 2 runlength arrays */ 0511 run0 = (pixnum *)malloc(2 * ((lastx + 5) & ~1) * sizeof(pixnum)); 0512 run1 = run0 + ((lastx + 5) & ~1); 0513 run1[0] = lastx; 0514 run1[1] = 0; 0515 EOLcnt = 0; 0516 for (LineNum = 0; LineNum < pn->rowsperstrip;) { 0517 #ifdef DEBUG_FAX 0518 printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); 0519 printf("-------------------- %d\n", LineNum); 0520 fflush(stdout); 0521 #endif 0522 if (EOLcnt == 0) { 0523 while (!EndOfData(pn)) { 0524 /* skip over garbage after a coding error */ 0525 NeedBits(11); 0526 if (GetBits(11) == 0) { 0527 break; 0528 } 0529 ClrBits(1); 0530 } 0531 } 0532 for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) { 0533 /* we have seen 11 zeros, which implies EOL, 0534 skip possible fill bits too */ 0535 while (true) { 0536 NeedBits(8); 0537 if (GetBits(8)) { 0538 break; 0539 } 0540 ClrBits(8); 0541 } 0542 while (GetBits(1) == 0) { 0543 ClrBits(1); 0544 } 0545 ClrBits(1); /* the eol flag */ 0546 NeedBits(12); 0547 refline = GetBits(1); /* 1D / 2D flag */ 0548 ClrBits(1); 0549 if (GetBits(11)) { 0550 break; 0551 } 0552 ClrBits(11); 0553 } 0554 if (EOLcnt > 1 && EOLcnt != 6 && verbose) { 0555 qCCritical(FAX_LOG) << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n"; 0556 } 0557 if (EOLcnt >= 6 || EndOfData(pn)) { 0558 free(run0); 0559 return; 0560 } 0561 if (LineNum == 0 && refline == 0 && verbose) { 0562 qCDebug(FAX_LOG) << "First line is 2-D encoded\n"; 0563 } 0564 RunLength = 0; 0565 if (LineNum & 1) { 0566 pa = run1; 0567 pb = run0; 0568 } else { 0569 pa = run0; 0570 pb = run1; 0571 } 0572 thisrun = pa; 0573 EOLcnt = 0; 0574 a0 = 0; 0575 b1 = *pb++; 0576 0577 if (refline) { 0578 expand1d(); 0579 } else { 0580 expand2d(EOL2); 0581 } 0582 if (RunLength) { 0583 SETVAL(0); 0584 } 0585 if (a0 != lastx) { 0586 if (verbose) { 0587 qCWarning(FAX_LOG) << "Line " << LineNum << ": length is " << a0 << " (expected " << lastx << ")\n"; 0588 } 0589 while (a0 > lastx) { 0590 a0 -= *--pa; 0591 } 0592 if (a0 < lastx) { 0593 if ((pa - run0) & 1) { 0594 SETVAL(0); 0595 } 0596 SETVAL(lastx - a0); 0597 } 0598 } 0599 SETVAL(0); /* imaginary change at end of line for reference */ 0600 (*df)(thisrun, LineNum++, pn); 0601 } 0602 free(run0); 0603 } 0604 0605 /* Redefine the "skip to eol" macro. We cannot recover from coding 0606 errors in G4 data */ 0607 #undef SKIP_EOL 0608 #undef eol2lab 0609 #define SKIP_EOL \ 0610 do { \ 0611 if (verbose) \ 0612 qCCritical(FAX_LOG) << "Line " << LineNum << ": G4 coding error\n"; \ 0613 free(run0); \ 0614 return; \ 0615 } while (0) 0616 #define eol2lab 0617 0618 /* Expand group-4 data */ 0619 void g4expand(pagenode *pn, drawfunc df) 0620 { 0621 int RunLength; /* Length of current run */ 0622 int a0; /* reference element */ 0623 int b1; /* next change on previous line */ 0624 int lastx = pn->size.width(); /* copy line width to register */ 0625 pixnum *run0, *run1; /* run length arrays */ 0626 pixnum *thisrun, *pa, *pb; /* pointers into runs */ 0627 t16bits *sp; /* pointer into compressed data */ 0628 t32bits BitAcc; /* bit accumulator */ 0629 int BitsAvail; /* # valid bits in BitAcc */ 0630 int LineNum; /* line number */ 0631 int EOLcnt; 0632 struct tabent *TabEnt; 0633 0634 sp = pn->data; 0635 BitAcc = 0; 0636 BitsAvail = 0; 0637 /* allocate space for 2 runlength arrays */ 0638 run0 = (pixnum *)malloc(2 * ((lastx + 5) & ~1) * sizeof(pixnum)); 0639 run1 = run0 + ((lastx + 5) & ~1); 0640 run1[0] = lastx; /* initial reference line */ 0641 run1[1] = 0; 0642 0643 for (LineNum = 0; LineNum < pn->rowsperstrip;) { 0644 #ifdef DEBUG_FAX 0645 printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); 0646 printf("-------------------- %d\n", LineNum); 0647 fflush(stdout); 0648 #endif 0649 RunLength = 0; 0650 if (LineNum & 1) { 0651 pa = run1; 0652 pb = run0; 0653 } else { 0654 pa = run0; 0655 pb = run1; 0656 } 0657 thisrun = pa; 0658 a0 = 0; 0659 b1 = *pb++; 0660 expand2d(EOFB); 0661 if (a0 < lastx) { 0662 if ((pa - run0) & 1) { 0663 SETVAL(0); 0664 } 0665 SETVAL(lastx - a0); 0666 } 0667 SETVAL(0); /* imaginary change at end of line for reference */ 0668 (*df)(thisrun, LineNum++, pn); 0669 continue; 0670 EOFB: 0671 NeedBits(13); 0672 if (GetBits(13) != 0x1001 && verbose) { 0673 qCCritical(FAX_LOG) << "Bad RTC\n"; 0674 } 0675 break; 0676 } 0677 free(run0); 0678 (void)EOLcnt; // make gcc happy 0679 } 0680 0681 static const unsigned char zerotab[256] = {0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05, 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04, 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, 0682 0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0683 0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0684 0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0685 0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0686 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0687 0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0688 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00}; 0689 0690 #define check(v) \ 0691 do { \ 0692 prezeros = zerotab[v]; \ 0693 postzeros = prezeros & 15; \ 0694 prezeros >>= 4; \ 0695 if (prezeros == 8) { \ 0696 zeros += 8; \ 0697 break; \ 0698 } \ 0699 if (zeros + prezeros < 11) { \ 0700 empty = 0; \ 0701 zeros = postzeros; \ 0702 break; \ 0703 } \ 0704 zeros = postzeros; \ 0705 if (empty) \ 0706 EOLcnt++; \ 0707 lines++; \ 0708 empty = 1; \ 0709 } while (false) 0710 0711 /* count fax lines */ 0712 int G3count(pagenode *pn, int twoD) 0713 { 0714 t16bits *p = pn->data; 0715 t16bits *end = p + pn->length / sizeof(*p); 0716 int lines = 0; /* lines seen so far */ 0717 int zeros = 0; /* number of consecutive zero bits seen */ 0718 int EOLcnt = 0; /* number of consecutive EOLs seen */ 0719 int empty = 1; /* empty line */ 0720 int prezeros, postzeros; 0721 0722 while (p < end && EOLcnt < 6) { 0723 t16bits bits = *p++; 0724 check(bits & 255); 0725 if (twoD && (prezeros + postzeros == 7)) { 0726 if (postzeros || ((bits & 0x100) == 0)) { 0727 zeros--; 0728 } 0729 } 0730 check(bits >> 8); 0731 if (twoD && (prezeros + postzeros == 7)) { 0732 if (postzeros || ((p < end) && ((*p & 1) == 0))) { 0733 zeros--; 0734 } 0735 } 0736 } 0737 return lines - EOLcnt; /* don't count trailing EOLs */ 0738 }