1 #include <u.h> 2 #include <libc.h> 3 4 enum 5 { 6 ERR, 7 EOL, 8 MAKE, 9 TERM, 10 }; 11 12 enum 13 { 14 White, 15 Black, 16 }; 17 18 typedef struct Tab 19 { 20 ushort run; 21 ushort bits; 22 int code; 23 } Tab; 24 25 Tab wtab[8192]; 26 Tab btab[8192]; 27 uchar bitrev[256]; 28 uchar bitnonrev[256]; 29 30 int readrow(uchar *rev, int*); 31 void initwbtab(void); 32 void sync(uchar*); 33 int readfile(int, char*, char*); 34 35 int nbytes; 36 uchar *bytes; 37 uchar *pixels; 38 uchar *buf; 39 int y; 40 uint bitoffset; 41 uint word24; 42 43 enum 44 { 45 Bytes = 1024*1024, 46 Lines = 1410, /* 1100 for A4, 1410 for B4 */ 47 Dots = 1728, 48 }; 49 50 void 51 error(char *fmt, ...) 52 { 53 char buf[256]; 54 va_list arg; 55 56 if(fmt){ 57 va_start(arg, fmt); 58 vseprint(buf, buf+sizeof buf, fmt, arg); 59 va_end(arg); 60 fprint(2, "g3: %s\n", buf); 61 } 62 exits(fmt); 63 } 64 65 void 66 usage(void) 67 { 68 fprint(2, "usage: g3p9bit [-gy] file\n"); 69 exits("usage"); 70 } 71 72 void 73 main(int argc, char **argv) 74 { 75 int y, fd, n, m; 76 char *t; 77 char *file, err[ERRMAX], tbuf[5*12+1]; 78 int gray=0; 79 int yscale=1; 80 81 ARGBEGIN{ 82 case 'g': 83 /* do simulated 2bit gray to compress x */ 84 gray++; 85 break; 86 case 'y': 87 /* double each scan line to double the y resolution */ 88 yscale=2; 89 break; 90 default: 91 usage(); 92 }ARGEND 93 94 if(argc > 1) 95 usage(); 96 97 initwbtab(); 98 buf = malloc(1024*1024); 99 t = malloc((Dots/8)*Lines); 100 if(buf==nil || t==nil) 101 error("malloc failed: %r\n"); 102 pixels = (uchar*)t; 103 104 file = "<stdin>"; 105 fd = 0; 106 if(argc > 0){ 107 file = argv[0]; 108 fd = open(file, OREAD); 109 if(fd < 0) 110 error("can't open %s", file); 111 } 112 y = readfile(fd, file, err); 113 if(y < 0) 114 error(err); 115 sprint(tbuf, "%11d %11d %11d %11d %11d ", gray, 0, 0, Dots/(gray+1), y*yscale); 116 write(1, tbuf, 5*12); 117 n = (Dots/8)*y*yscale; 118 /* write in pieces; brazil pipes work badly with huge counts */ 119 while(n > 0){ 120 if(yscale > 1) /* write one scan line */ 121 m = Dots/8; 122 else{ /* write lots */ 123 m = n; 124 if(m > 8192) 125 m = 8192; 126 } 127 for(y=0; y<yscale; y++){ 128 if(write(1, t, m) != m) 129 error("write error"); 130 n -= m; 131 } 132 t += m; 133 } 134 if(err[0]) 135 error(err); 136 error(nil); 137 } 138 139 enum{ 140 Hvres, 141 Hbaud, 142 Hwidth, 143 Hlength, 144 Hcomp, 145 HenabECM, 146 HenabBFT, 147 Hmsperscan, 148 }; 149 150 int defhdr[8] = { 151 0, /* 98 lpi */ 152 0, /* 2400 baud */ 153 0, /* 1728 pixels in 215mm */ 154 0, /* A4, 297mm */ 155 0, /* 1-D modified huffman */ 156 0, /* disable ECM */ 157 0, /* disable BFT */ 158 3, /* 10 ms per scan */ 159 }; 160 161 int 162 crackhdr(uchar *ap, int *hdr) 163 { 164 char *p, *q; 165 int i; 166 167 p = (char*)ap; 168 q = p; 169 for(i=0; i<8; i++){ 170 if(*p<'0' || '9'<*p) 171 return -1; 172 hdr[i] = strtol(p, &q, 0); 173 p = q+1; 174 } 175 return p-(char*)ap; 176 } 177 178 int 179 readfile(int f, char *file, char *err) 180 { 181 int i, r, lines; 182 uchar *rev; 183 int hdr[8]; 184 185 err[0] = 0; 186 memset(pixels, 0, (Dots/8) * Lines); 187 nbytes = readn(f, buf, 1024*1024); 188 if(nbytes==1024*1024 || nbytes<=100){ 189 bad: 190 sprint(err, "g3: file improper size or format: %s", file); 191 return -1; 192 } 193 bytes = buf; 194 if(bytes[0]=='I' && bytes[1]=='I' && bytes[2]=='*'){ /* dumb PC format */ 195 bytes += 0xf3; 196 nbytes -= 0xf3; 197 rev = bitrev; 198 memmove(hdr, defhdr, sizeof defhdr); 199 }else if(bytes[0] == 0 && strcmp((char*)bytes+1, "PC Research, Inc") == 0){ /* digifax format */ 200 memmove(hdr, defhdr, sizeof defhdr); 201 if(bytes[45] == 0x40 && bytes[29] == 1) /* high resolution */ 202 hdr[Hvres] = 1; 203 else 204 hdr[Hvres] = 0; 205 /* hdr[26] | (hdr[27]<<8) is page number */ 206 207 bytes += 64; 208 nbytes -= 64; 209 rev = bitnonrev; 210 }else{ 211 while(nbytes > 2){ 212 if(bytes[0]=='\n'){ 213 if(strncmp((char*)bytes+1, "FDCS=", 5) == 0){ 214 i = crackhdr(bytes+6, hdr); 215 if(i < 0){ 216 sprint(err, "g3: bad FDCS in header: %s", file); 217 return -1; 218 } 219 if(hdr[Hwidth] != 0){ 220 sprint(err, "g3: unsupported width: %s", file); 221 return -1; 222 } 223 if(hdr[Hcomp] != 0){ 224 sprint(err, "g3: unsupported compression: %s", file); 225 return -1; 226 } 227 bytes += i+1; 228 nbytes -= i+1; 229 continue; 230 } 231 if(bytes[1] == '\n'){ 232 bytes += 2; 233 nbytes -= 2; 234 break; 235 } 236 } 237 bytes++; 238 nbytes--; 239 } 240 if(nbytes < 2) 241 goto bad; 242 rev = bitnonrev; 243 } 244 bitoffset = 24; 245 word24 = 0; 246 sync(rev); 247 lines = Lines; 248 if(hdr[Hvres] == 1) 249 lines *= 2; 250 for(y=0; y<lines; y++){ 251 r = readrow(rev, hdr); 252 if(r < 0) 253 break; 254 if(r == 0) 255 sync(rev); 256 } 257 if(hdr[Hvres] == 1) 258 y /= 2; 259 // if(y < 100) 260 // goto bad; 261 return y; 262 } 263 264 int 265 readrow(uchar *rev, int *hdr) 266 { 267 int bo, state; 268 Tab *tab, *t; 269 int x, oldx, x2, oldx2, dx, xx; 270 uint w24; 271 uchar *p, *q; 272 273 state = White; 274 oldx = 0; 275 bo = bitoffset; 276 w24 = word24; 277 x = y; 278 if(hdr[Hvres] == 1) /* high resolution */ 279 x /= 2; 280 p = pixels + x*Dots/8; 281 x = 0; 282 283 loop: 284 if(x > Dots) 285 return 0; 286 if(state == White) 287 tab = wtab; 288 else 289 tab = btab; 290 if(bo > (24-13)) { 291 do { 292 if(nbytes <= 0) 293 return -1; 294 w24 = (w24<<8) | rev[*bytes]; 295 bo -= 8; 296 bytes++; 297 nbytes--; 298 } while(bo >= 8); 299 } 300 301 t = tab + ((w24 >> (24-13-bo)) & 8191); 302 x += t->run; 303 bo += t->bits; 304 if(t->code == TERM){ 305 if(state == White) 306 oldx = x; 307 else{ 308 oldx2 = oldx; 309 x2 = x; 310 xx = oldx2&7; 311 q = p+oldx2/8; 312 if(x2/8 == oldx2/8) /* all in one byte, but if((x2&7)==0), do harder case */ 313 *q |= (0xFF>>xx) & (0xFF<<(8-(x2&7))); 314 else{ 315 dx = x2 - oldx2; 316 /* leading edge */ 317 if(xx){ 318 *q++ |= 0xFF>>xx; 319 dx -= 8-xx; 320 } 321 /* middle */ 322 while(dx >= 8){ 323 *q++ = 0xFF; 324 dx -= 8; 325 } 326 /* trailing edge */ 327 if(dx) 328 *q |= 0xFF<<(8-dx); 329 } 330 } 331 state ^= White^Black; 332 goto loop; 333 } 334 if(t->code == ERR){ 335 bitoffset = bo; 336 word24 = w24; 337 return 0; 338 } 339 if(t->code == EOL){ 340 bitoffset = bo; 341 word24 = w24; 342 return 1; 343 } 344 goto loop; 345 return 0; 346 } 347 348 349 void 350 sync(uchar *rev) 351 { 352 Tab *t; 353 int c; 354 355 c = 0; 356 loop: 357 if(bitoffset > (24-13)) { 358 do { 359 if(nbytes <= 0) 360 return; 361 word24 = (word24<<8) | rev[*bytes]; 362 bitoffset -= 8; 363 bytes++; 364 nbytes--; 365 } while(bitoffset >= 8); 366 } 367 t = wtab + ((word24 >> (24-13-bitoffset)) & 8191); 368 if(t->code != EOL) { 369 bitoffset++; 370 c++; 371 goto loop; 372 } 373 bitoffset += t->bits; 374 } 375 376 typedef struct File 377 { 378 char *val; 379 int code; 380 }File; 381 382 File ibtab[] = { 383 #include "btab" 384 {nil, 0} 385 }; 386 387 File iwtab[] = { 388 #include "wtab" 389 {nil, 0} 390 }; 391 392 int 393 binary(char *s) 394 { 395 int n; 396 397 n = 0; 398 while(*s) 399 n = n*2 + *s++-'0'; 400 return n; 401 } 402 403 void 404 tabinit(File *file, Tab *tab) 405 { 406 int i, j, v, r, l; 407 char *b; 408 409 for(v=0; v<8192; v++) { 410 tab[v].run = 0; 411 tab[v].bits = 1; 412 tab[v].code = ERR; 413 } 414 for(i=0; b=file[i].val; i++){ 415 l = strlen(b); 416 v = binary(b); 417 r = file[i].code; 418 if(l > 13) 419 fprint(2, "g3: oops1 l = %d %s\n", l, b); 420 421 v = v<<(13-l); 422 for(j=0; j<(1<<((13-l))); j++) { 423 if(tab[v].code != ERR) 424 fprint(2, "g3: oops2 %d %s\n", r, b); 425 tab[v].run = r; 426 tab[v].bits = l; 427 tab[v].code = TERM; 428 if(r < 0) { 429 tab[v].run = 0; 430 tab[v].code = EOL; 431 if(r < -1) { 432 tab[v].bits = 1; 433 tab[v].code = MAKE; 434 } 435 } 436 if(r >= 64) { 437 tab[v].code = MAKE; 438 } 439 v++; 440 } 441 } 442 443 for(i=0; i<256; i++) 444 for(j=0; j<8; j++) 445 if(i & (1<<j)) 446 bitrev[i] |= 0x80 >> j; 447 for(i=0; i<256; i++) 448 bitnonrev[i] = i; 449 } 450 451 void 452 initwbtab(void) 453 { 454 tabinit(iwtab, wtab); 455 tabinit(ibtab, btab); 456 } 457