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