1 #ident "$Id: g32pbm.c,v 4.3 1998/06/01 12:00:09 gert Exp $ (c) Gert Doering, Chris Lewis et.al."
2 
3 /* G32pbm.c
4  *
5  * convert raw G3 data (optionally with a digifax header) to PBM or
6  * Laserjet, optionally scaling the image in the process.
7  *
8  * G3 and PBM code by Gert Doering
9  * HP Laserjet and scaling code by Chris Lewis
10  */
11 
12 #include <stdio.h>
13 #include <unistd.h>
14 #include "syslibs.h"
15 #include <string.h>
16 #include <fcntl.h>
17 
18 #include "ugly.h"
19 
20 #include "g3.h"
21 
22 int  pixblock _PROTO((char *start, char *end));
23 int  nullscan _PROTO((char *start, char *end));
24 void emitlj _PROTO((int resolution, int numx, int numy, char *image));
25 
26 void emitpbm _PROTO((int hcol, int row, char *bitmap, int bperrow ));
27 
28 
29 #ifdef DEBUG
30 void putbin _P1( (d), unsigned long d )
31 {
32 unsigned long i = 0x80000000;
33 
34     while ( i!=0 )
35     {
36 	putc( ( d & i ) ? '1' : '0', stderr );
37 	i >>= 1;
38     }
39     putc( '\n', stderr );
40 }
41 #endif
42 
43 static int byte_tab[ 256 ];
44 static int o_stretch;			/* -stretch: double each line */
45 static int o_stretch_force=-1;		/* -1: guess from filename */
46 static int o_lj;			/* -l: LJ output */
47 static int o_turn;			/* -t: turn 90 degrees right */
48 
49 struct g3_tree * black, * white;
50 
51 #define CHUNK 2048;
52 static	char rbuf[2048];	/* read buffer */
53 static	int  rp;		/* read pointer */
54 static	int  rs;		/* read buffer size */
55 
56 #define MAX_ROWS 4300
57 #define MAX_COLS 1728		/* !! FIXME - command line parameter */
58 
59 #define BASERES 200		/* resolution of G3 */
60 
61 #define MVTYPE	int
62 
63 /* scale the bitmap */
64 
65 char *scalebm _P5( (res, cols, rows, map, bperrow),
66 		    int res, int *cols, int *rows, char *map, int *bperrow)
67 {
68     int nc, nr, i, newbperrow;
69     register char *orp, *nrp;
70     char *newmap;
71     MVTYPE *mulvec;
72 
73     if ( res == BASERES ) 		/* don't do anything of not scaled */
74     {
75 	return map;
76     }
77 
78     /* do scaling, from "BASERES" to "res" dpi */
79 
80     nr = (*rows * res) / BASERES;
81     nc = (((*cols * res) / BASERES) + 7) & ~7;
82     newbperrow = (nc + 7) >> 3;
83 
84 
85     newmap = malloc(nr * newbperrow );
86     if (!newmap)
87     {
88 	fprintf (stderr, "g32pbm: cannot allocate %d bytes for scale raster\n",
89 	                 nr * newbperrow );
90 	exit(1);
91     }
92     memset( newmap, 0, nr * newbperrow );
93 
94     {
95 	int max = ( *cols > *rows ) ? *cols: *rows;
96 	MVTYPE *mv;
97 
98 	mulvec = (MVTYPE *) malloc(max * sizeof(MVTYPE));
99 	if (!mulvec)
100 	{
101 	    fprintf (stderr, "g32pbm: cannot allocate multiplier vector\n");
102 	    exit(1);
103 	}
104 	for (mv = mulvec, i = 0; i < max; i++)
105 	{
106 	    *mv++ = (i * res) / BASERES;
107 	}
108     }
109 
110     orp = map;
111 
112     for (i = 0; i < *rows; i++)
113     {
114 	register MVTYPE *mv;
115 	register int j;
116 	nrp = newmap + (mulvec[i] * newbperrow);
117 
118 	for (j = 0, mv = mulvec; j < *cols; j++, mv++)
119 	{
120 	    if (!(j & 0x7) && !orp[j >> 3])
121 	    {
122 		j += 8;
123 		mv += 8;
124 		continue;
125 	    }
126 
127 	    if (orp[j >> 3] & (0x80 >> (j & 0x7)))
128 		    nrp[(*mv) >> 3] |= (0x80 >> ((*mv) & 0x7));
129 	}
130 
131 	orp += *bperrow;
132     }
133 
134     free (map);
135     *rows = nr;
136     *cols = nc;
137     *bperrow = newbperrow;
138     return (newmap);
139 }
140 
141 /* turn the bitmap */
142 
143 char * turnbm _P4 (( cols, rows, map, bperrow ),
144 		     int * cols, int * rows, char * map, int * bperrow )
145 {
146 char * newmap;
147 int newbperrow, nr, nc, nx, ny;
148 
149 register int obit;
150 register char * newbp, * obyte;
151 
152 char * oldbp;
153 int byte, bit;
154 
155     o_turn &= 3;
156     if ( o_turn == 0 ) return map;
157 
158     /* turn right */
159     nc = *rows;		/* new columns */
160     nr = *cols;		/* new rows */
161     newbperrow = ( nc+7 ) / 8;
162 
163     newmap = malloc( nr * newbperrow );
164 
165     if ( newmap == NULL )
166     {
167 	fprintf( stderr, "g32pbm: cannot allocate %d bytes for turn bitmap",
168 			 nr * newbperrow );
169 	exit(1);
170     }
171 
172     memset( newmap, 0, nr * newbperrow );
173 
174     for( nx = 0; nx<nc; nx++ )			/* new X coordinate */
175     {
176 	bit  = 0x80 >> (nx&7);
177 	byte = nx >> 3;
178 
179 	oldbp = &map[ (*rows - nx - 1) * *bperrow ];
180 
181 	for ( ny = nr, newbp= &newmap[byte],	/* new y */
182 	      obyte = oldbp, obit=0x80;
183 	      ny>0; ny--, newbp += newbperrow )
184 	{
185 	    if ( (*obyte) & obit )
186 	    {
187 		*newbp |= bit;
188 	    }
189 	    obit >>= 1; if ( obit == 0 ) { obit=0x80; obyte++; }
190 	}
191     }
192 
193     free( map );
194     *rows = nr;
195     *cols = nc;
196     *bperrow = newbperrow;
197     return newmap;
198 }
199 
200 int main _P2( (argc, argv), int argc, char ** argv )
201 {
202 int data;
203 int hibit;
204 struct	g3_tree * p;
205 int	nr_pels;
206 int fd;
207 int color;
208 int i;
209 int cons_eol;
210 
211 int	bperrow = MAX_COLS/8;	/* bytes per bit row */
212 char *	bitmap;			/* MAX_ROWS by (bperrow) bytes */
213 char *	bp;			/* bitmap pointer */
214 int	row;
215 int	max_rows;		/* max. rows allocated */
216 int	col, hcol;		/* column, highest column ever used */
217 extern  int optind;
218 extern  char *optarg;
219 int	resolution = BASERES;
220 
221     /* initialize lookup trees */
222     build_tree( &white, t_white );
223     build_tree( &white, m_white );
224     build_tree( &black, t_black );
225     build_tree( &black, m_black );
226 
227     init_byte_tab( 0, byte_tab );
228 
229     while((i = getopt(argc, argv, "rsnfld:t")) != EOF)
230     {
231 	switch (i)
232 	{
233 	    case 'r':
234 		init_byte_tab( 1, byte_tab );
235 		break;
236 	    case 's':				/* stretch */
237 	    case 'n':				/* "n"ormal */
238 		o_stretch_force=1;
239 		break;
240 	    case 'f':				/* "f"ine */
241 		o_stretch_force=0;
242 		break;
243 	    case 'l':
244 		o_lj=1;
245 		break;
246 	    case 'd':
247 		resolution = atoi(optarg);
248 		if ( resolution != 75 && resolution != 150 &&
249 		     resolution != 300 )
250 		{
251 		    fprintf( stderr, "g32pbm: only supports 75, 150, or 300 dpi\n");
252 		    exit(1);
253 		}
254 		break;
255 	    case 't':
256 		o_turn++;
257 		break;
258 	    case '?':
259 		fprintf( stderr, "usage: g32pbm [-l|-r|-n/f|-d <dpi>|-t] [g3 file]\n");
260 		exit(1);
261 	}
262     }
263 
264     if (o_lj && resolution == BASERES)
265 	resolution = 150;
266 
267     o_stretch = (o_stretch_force<0) ? 0: o_stretch_force;
268 
269     if ( optind < argc ) 			/* read from file */
270     {
271 	if ( o_stretch_force < 0 )		/* no resolution given yet */
272 	{
273 	    char * p = argv[optind];
274 	    if ( strrchr( p, '/' ) != NULL ) p = strrchr( p, '/' )+1;
275 	    o_stretch = ( p[1] == 'n' );	/* 'fn...' -> stretch */
276 	}
277 
278 	fd = open( argv[optind], O_RDONLY );
279 	if ( fd == -1 )
280 	{    perror( argv[optind] ); exit( 1 ); }
281     }
282     else
283 	fd = 0;
284 
285     hibit = 0;
286     data = 0;
287 
288     cons_eol = 0;	/* consecutive EOLs read - zero yet */
289 
290     color = 0;		/* start with white */
291 
292     rs = read( fd, rbuf, sizeof(rbuf) );
293     if ( rs < 0 ) { perror( "read" ); close( rs ); exit(8); }
294 
295 			/* skip GhostScript header */
296     rp = ( rs >= 64 && strcmp( rbuf+1, "PC Research, Inc" ) == 0 ) ? 64 : 0;
297 
298     /* initialize bitmap */
299 
300     row = col = hcol = 0;
301     bitmap = (char *) malloc( ( max_rows = MAX_ROWS ) * MAX_COLS / 8 );
302     if ( bitmap == NULL )
303     {
304 	fprintf( stderr, "cannot allocate %d bytes for bitmap",
305 		 max_rows * MAX_COLS/8 );
306 	close( fd );
307 	exit(9);
308     }
309     memset( bitmap, 0, max_rows * MAX_COLS/8 );
310     bp = &bitmap[ row * MAX_COLS/8 ];
311 
312     while ( rs > 0 && cons_eol < 4 )	/* i.e., while (!EOF) */
313     {
314 #ifdef DEBUG
315 	fprintf( stderr, "hibit=%2d, data=", hibit );
316 	putbin( data );
317 #endif
318 	while ( hibit < 20 )
319 	{
320 	    data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit );
321 	    hibit += 8;
322 
323 	    if ( rp >= rs )
324 	    {
325 		rs = read( fd, rbuf, sizeof( rbuf ) );
326 		if ( rs < 0 ) { perror( "read2"); break; }
327 		rp = 0;
328 		if ( rs == 0 ) { goto do_write; }
329 	    }
330 #ifdef DEBUG
331 	    fprintf( stderr, "hibit=%2d, data=", hibit );
332 	    putbin( data );
333 #endif
334 	}
335 
336 	if ( color == 0 )		/* white */
337 	    p = white->nextb[ data & BITM ];
338 	else				/* black */
339 	    p = black->nextb[ data & BITM ];
340 
341 	while ( p != NULL && ! ( p->nr_bits ) )
342 	{
343 	    data >>= BITS;
344 	    hibit -= BITS;
345 	    p = p->nextb[ data & BITM ];
346 	}
347 
348 	if ( p == NULL )	/* invalid code */
349 	{
350 	    fprintf( stderr, "invalid code, row=%d, col=%d, file offset=%lx, skip to eol\n",
351 		     row, col, (unsigned long) lseek( fd, 0, 1 ) - rs + rp );
352 	    while ( ( data & 0x03f ) != 0 )
353 	    {
354 		data >>= 1; hibit--;
355 		if ( hibit < 20 )
356 		{
357 		    data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit );
358 		    hibit += 8;
359 
360 		    if ( rp >= rs )	/* buffer underrun */
361 		    {   rs = read( fd, rbuf, sizeof( rbuf ) );
362 			if ( rs < 0 ) { perror( "read4"); break; }
363 			rp = 0;
364 			if ( rs == 0 ) goto do_write;
365 		    }
366 		}
367 	    }
368 	    nr_pels = -1;		/* handle as if eol */
369 	}
370 	else				/* p != NULL <-> valid code */
371 	{
372 	    data >>= p->nr_bits;
373 	    hibit -= p->nr_bits;
374 
375 	    nr_pels = ( (struct g3_leaf *) p ) ->nr_pels;
376 #ifdef DEBUG
377 	    fprintf( stderr, "PELs: %d (%c)\n", nr_pels, '0'+color );
378 #endif
379 	}
380 
381 	/* handle EOL (including fill bits) */
382 	if ( nr_pels == -1 )
383 	{
384 #ifdef DEBUG
385 	    fprintf( stderr, "hibit=%2d, data=", hibit );
386 	    putbin( data );
387 #endif
388 	    /* skip filler 0bits -> seek for "1"-bit */
389 	    while ( ( data & 0x01 ) != 1 )
390 	    {
391 		if ( ( data & 0xf ) == 0 )	/* nibble optimization */
392 		{
393 		    hibit-= 4; data >>= 4;
394 		}
395 		else
396 		{
397 		    hibit--; data >>= 1;
398 		}
399 		/* fill higher bits */
400 		if ( hibit < 20 )
401 		{
402 		    data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit );
403 		    hibit += 8;
404 
405 		    if ( rp >= rs )	/* buffer underrun */
406 		    {   rs = read( fd, rbuf, sizeof( rbuf ) );
407 			if ( rs < 0 ) { perror( "read3"); break; }
408 			rp = 0;
409 			if ( rs == 0 ) goto do_write;
410 		    }
411 		}
412 #ifdef DEBUG
413 	    fprintf( stderr, "hibit=%2d, data=", hibit );
414 	    putbin( data );
415 #endif
416 	    }				/* end skip 0bits */
417 	    hibit--; data >>=1;
418 
419 	    color=0;
420 
421 	    if ( col == 0 )
422 		cons_eol++;		/* consecutive EOLs */
423 	    else
424 	    {
425 	        if ( col > hcol && col <= MAX_COLS ) hcol = col;
426 		row++;
427 
428 		/* bitmap memory full? make it larger! */
429 		if ( row >= max_rows )
430 		{
431 		    char * p = realloc( bitmap,
432 				       ( max_rows += 500 ) * MAX_COLS/8 );
433 		    if ( p == NULL )
434 		    {
435 			perror( "realloc() failed, page truncated" );
436 			rs = 0;
437 		    }
438 		    else
439 		    {
440 			bitmap = p;
441 			memset( &bitmap[ row * MAX_COLS/8 ], 0,
442 			       ( max_rows - row ) * MAX_COLS/8 );
443 		    }
444 		}
445 
446 		col=0; bp = &bitmap[ row * MAX_COLS/8 ];
447 		cons_eol = 0;
448 	    }
449 	}
450 	else		/* not eol */
451 	{
452 	    if ( col+nr_pels > MAX_COLS ) nr_pels = MAX_COLS - col;
453 
454 	    if ( color == 0 )                  /* white */
455 		col += nr_pels;
456 	    else                               /* black */
457 	    {
458             register int bit = ( 0x80 >> ( col & 07 ) );
459 	    register char *w = & bp[ col>>3 ];
460 
461 		for ( i=nr_pels; i > 0; i-- )
462 		{
463 		    *w |= bit;
464 		    bit >>=1; if ( bit == 0 ) { bit = 0x80; w++; }
465 		    col++;
466 		}
467 	    }
468 	    if ( nr_pels < 64 ) color = !color;		/* terminating code */
469 	}
470     }		/* end main loop */
471 
472 do_write:      	/* write pbm (or whatever) file */
473 
474     if( fd != 0 ) close(fd);	/* close input file */
475 
476 #ifdef DEBUG
477     fprintf( stderr, "consecutive EOLs: %d, max columns: %d\n", cons_eol, hcol );
478 #endif
479 
480     bitmap = scalebm(resolution, &hcol, &row, bitmap, &bperrow );
481 
482     bitmap = turnbm( &hcol, &row, bitmap, &bperrow );
483 
484     if (o_lj)
485 	emitlj(resolution, hcol, row, bitmap);
486     else
487 	emitpbm(hcol, row, bitmap, bperrow );
488 
489 
490     return 0;
491 }
492 
493 /* hcol is the number of columns, row the number of rows
494  * bperrow is the number of bytes actually used by hcol, which may
495  * be greater than (hcol+7)/8 [in case of an unscaled g3 image less
496  * than 1728 pixels wide]
497  */
498 
499 void emitpbm _P4(( hcol, row, bitmap, bperrow),
500 		   int hcol, int row, char *bitmap, int bperrow )
501 {
502     register int i;
503 
504     sprintf( rbuf, "P4\n%d %d\n", hcol, ( o_stretch? row*2 : row ) );
505     write( 1, rbuf, strlen( rbuf ));
506 
507     if ( hcol == (bperrow*8) && !o_stretch )
508         write( 1, bitmap, row * bperrow );
509     else
510     {
511 	if ( !o_stretch )
512 	  for ( i=0; i<row; i++ )
513 	{
514 	    write( 1, &bitmap[ i*bperrow ], (hcol+7)/8 );
515 	}
516 	else				/* Double each row */
517 	  for ( i=0; i<row; i++ )
518         {
519 	    write( 1, &bitmap[ i*bperrow ], (hcol+7)/8 );
520 	    write( 1, &bitmap[ i*bperrow ], (hcol+7)/8 );
521 	}
522     }
523 }
524 
525 /* The following code is copyright 1994, Chris Lewis.  Permission is hereby
526    permanently granted to Gert Doering to include this software in his
527    g32pbm program, whether distributed as freeware or commercially.
528  */
529 
530 #define ESCLEN	25	/* avg # bytes in raster escape prolog/epilog */
531 
532 int nullscan _P2((start, end), char *start, char *end)
533 {
534     register char *cur;
535     for (cur = start; cur < end && !*cur; cur++);
536     return(cur - start);
537 }
538 
539 int pixblock _P2((start, end), char *start, char *end)
540 {
541     register char *cur;
542     register int numnulls;
543     if (end - start <= ESCLEN * 2)	/* no point optimizing */
544 	return(end - start);
545     cur = start;
546 
547     while(cur < end) {
548 
549 	for(; *cur && cur < end; cur++);
550 
551 	numnulls = nullscan(cur, end);
552 
553 	if (numnulls > ESCLEN)
554 	    return(cur - start);
555 	else
556 	    cur += numnulls;
557     }
558     return(end - start);
559 }
560 
561 void emitlj _P4((resolution, numx, numy, image),
562 		int resolution, int numx, int numy, char *image)
563 {
564     int bperline;
565     int resmult = 300/resolution;
566     register char *ip, *lineanch, *nip;
567     register int currow, bcount;
568     bperline = ((numx + 7) / 8);
569 
570     /* some spoolers use a "cut" to do printer-type selection
571        (eg: "%!" processing).  The newline is to prevent cut
572        (or other line-length-limited UNIX utilities) dying. */
573     printf("\033*t%dR\n", resolution);
574 
575     for(currow = 0; currow < numy; currow++)
576     {
577 	lineanch = ip = &image[bperline * currow];
578 	nip = ip + bperline;
579 	while (ip < nip && !*ip) ip++;
580 	if (ip >= nip)
581 	    continue;	/* line has no pixels */
582 	while (!*(nip - 1)) nip--;	/* truncate trailing nulls */
583 	while (ip < nip) {	/* inv: !*ip && !*nip */
584 	    bcount = pixblock(ip, nip);
585 	    printf("\033*p%dx%dY\033*r1A\033*b%dW",
586 		(int) ((ip - lineanch) * 8 * resmult), (currow * resmult) << o_stretch, bcount);
587 	    fwrite(ip, 1, bcount, stdout);
588 	    if (o_stretch) {
589 		printf("\033*b%dW", bcount);
590 		fwrite(ip, 1, bcount, stdout);
591 	    }
592 	    fputs("\033*rB", stdout);
593 	    for(ip += bcount; ip < nip && !*ip; ip++);
594 	}
595     }
596     putchar('\f');
597 }
598