xref: /plan9/sys/src/cmd/postscript/g3p9bit/g3p9bit.c (revision a7a38e3ec879cc47b5698ff7334c127003b75b14)
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