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
error(char * fmt,...)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
usage(void)66 usage(void)
67 {
68 fprint(2, "usage: g3p9bit [-gy] file\n");
69 exits("usage");
70 }
71
72 void
main(int argc,char ** argv)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
crackhdr(uchar * ap,int * hdr)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
readfile(int f,char * file,char * err)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
readrow(uchar * rev,int * hdr)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 }
346
347
348 void
sync(uchar * rev)349 sync(uchar *rev)
350 {
351 Tab *t;
352 int c;
353
354 c = 0;
355 loop:
356 if(bitoffset > (24-13)) {
357 do {
358 if(nbytes <= 0)
359 return;
360 word24 = (word24<<8) | rev[*bytes];
361 bitoffset -= 8;
362 bytes++;
363 nbytes--;
364 } while(bitoffset >= 8);
365 }
366 t = wtab + ((word24 >> (24-13-bitoffset)) & 8191);
367 if(t->code != EOL) {
368 bitoffset++;
369 c++;
370 goto loop;
371 }
372 bitoffset += t->bits;
373 }
374
375 typedef struct File
376 {
377 char *val;
378 int code;
379 }File;
380
381 File ibtab[] = {
382 #include "btab"
383 {nil, 0}
384 };
385
386 File iwtab[] = {
387 #include "wtab"
388 {nil, 0}
389 };
390
391 int
binary(char * s)392 binary(char *s)
393 {
394 int n;
395
396 n = 0;
397 while(*s)
398 n = n*2 + *s++-'0';
399 return n;
400 }
401
402 void
tabinit(File * file,Tab * tab)403 tabinit(File *file, Tab *tab)
404 {
405 int i, j, v, r, l;
406 char *b;
407
408 for(v=0; v<8192; v++) {
409 tab[v].run = 0;
410 tab[v].bits = 1;
411 tab[v].code = ERR;
412 }
413 for(i=0; b=file[i].val; i++){
414 l = strlen(b);
415 v = binary(b);
416 r = file[i].code;
417 if(l > 13)
418 fprint(2, "g3: oops1 l = %d %s\n", l, b);
419
420 v = v<<(13-l);
421 for(j=0; j<(1<<((13-l))); j++) {
422 if(tab[v].code != ERR)
423 fprint(2, "g3: oops2 %d %s\n", r, b);
424 tab[v].run = r;
425 tab[v].bits = l;
426 tab[v].code = TERM;
427 if(r < 0) {
428 tab[v].run = 0;
429 tab[v].code = EOL;
430 if(r < -1) {
431 tab[v].bits = 1;
432 tab[v].code = MAKE;
433 }
434 }
435 if(r >= 64) {
436 tab[v].code = MAKE;
437 }
438 v++;
439 }
440 }
441
442 for(i=0; i<256; i++)
443 for(j=0; j<8; j++)
444 if(i & (1<<j))
445 bitrev[i] |= 0x80 >> j;
446 for(i=0; i<256; i++)
447 bitnonrev[i] = i;
448 }
449
450 void
initwbtab(void)451 initwbtab(void)
452 {
453 tabinit(iwtab, wtab);
454 tabinit(ibtab, btab);
455 }
456