1 #ident "$Id: pbm2g3.c,v 4.2 1998/05/07 10:37:38 gert Exp $ Copyright (C) 1994 Gert Doering"
2
3 /* pbm2g3
4 *
5 * convert a "portable bitmap" file into CCITT T.4 fax format
6 * the output can directly be sent with mgetty+sendfax
7 *
8 * options: -d output digifax header
9 * -w xxx use a page width of xxx pels (default 1728)
10 * -h xxx start page with xxx blank lines (default 0)
11 * -a byte-align EOLs
12 * -r reverse bytes
13 */
14
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include "syslibs.h"
20 #include <ctype.h>
21
22 #include "ugly.h"
23
24 #include "g3.h"
25
26 #ifndef TRUE
27 #define TRUE 1
28 #define FALSE 0
29 #endif
30
31 /* g3 stuff */
32
33 int byte_align = FALSE;
34
35 static unsigned char buf[2048];
36 static int buflen = 0;
37 static unsigned int out_data = 0;
38 static unsigned int out_hibit = 0;
39
40 static int out_byte_tab[ 256 ]; /* for g3 byte reversal */
41
42 #ifdef __GNUC__
43 inline
44 #endif
45 void putcode _P2( (code, len), int code, int len )
46 {
47 out_data |= ( code << out_hibit );
48 out_hibit += len;
49
50 while( out_hibit >= 8 )
51 {
52 buf[ buflen++ ] = out_byte_tab[( out_data ) & 0xff];
53 out_data >>= 8;
54 out_hibit -= 8;
55 if ( buflen >= sizeof( buf ) )
56 {
57 write( 1, buf, buflen ); buflen = 0;
58 }
59 }
60 }
61
62 #ifdef __GNUC__
63 inline
64 #endif
_P0(void)65 void puteol _P0( void ) /* write byte-aligned EOL */
66 {
67 if ( byte_align ) while( out_hibit != 4 ) putcode( 0, 1 );
68 putcode( 0x800, 12 );
69 }
70
71 #ifdef __GNUC__
72 inline
73 #endif
74 void putwhitespan _P1( (l), int l )
75 {
76 if ( l >= 64 )
77 {
78 int mkup = ( l & ~63 );
79 int idx = (mkup / 64) -1;
80
81 if ( mkup > 1728 ) /* extended makeup table */
82 {
83 fprintf( stderr,
84 "run length too long (%d) - not yet implemented\n", l );
85 exit(99);
86 }
87 else
88 {
89 if ( m_white[idx].nr_pels != mkup ) /* paranoia alert */
90 {
91 fprintf( stderr, "no match: idx=%d, mkup=%d", idx, mkup );
92 exit(99);
93 }
94 putcode( m_white[idx].bit_code, m_white[idx].bit_length );
95 }
96 l -= mkup;
97 }
98
99 putcode( t_white[l].bit_code, t_white[l].bit_length );
100 }
101
102 #ifdef __GNUC__
103 inline
104 #endif
105 void putblackspan _P1( (l), int l )
106 {
107 if ( l >= 64 )
108 {
109 int mkup = ( l & ~63 );
110 int idx = (mkup / 64) -1;
111
112 if ( mkup > 1728 ) /* extended makeup table */
113 {
114 fprintf( stderr,
115 "run length too long (%d) - not yet implemented\n", l );
116 exit(99);
117 }
118 else
119 {
120 if ( m_black[idx].nr_pels != mkup ) /* paranoia alert */
121 {
122 fprintf( stderr, "no match: idx=%d, mkup=%d", idx, mkup );
123 exit(99);
124 }
125 putcode( m_black[idx].bit_code, m_black[idx].bit_length );
126 }
127 l -= mkup;
128 }
129
130 putcode( t_black[l].bit_code, t_black[l].bit_length );
131 }
132
133 /* pbm file header stuff */
134
135 typedef enum { unknown,
136 pbm, pgm, ppm,
137 pbm_raw, pgm_raw, ppm_raw
138 } pbm_file_types;
139
140 pbm_file_types pbm_type;
141 int pbm_xsize;
142 int pbm_ysize;
143
144 int pbm_getint _P1( (fd), int fd )
145 {
146 char buf[50];
147 int i;
148
149 /* skip leading whitespace */
150 do
151 {
152 if ( read( fd, buf, 1 ) != 1 ) return -1;
153
154 if ( buf[0] == '#' )
155 {
156 while( buf[0] != '\n' && read( fd, buf, 1 ) == 1 ) {}
157 }
158 }
159 while ( isspace( buf[0] ) );
160
161 i = 1;
162 while ( i < sizeof( buf ) -1 &&
163 read( fd, &buf[i], 1 ) == 1 &&
164 ! isspace( buf[i] ) )
165 {
166 i++;
167 }
168
169 if ( ! isspace( buf[i] ) ) return -1;
170
171 buf[i] = 0;
172
173 return ( atoi( buf ) );
174 }
175
176 void pbm_getheader _P1( (fd), int fd )
177 {
178 char buf[10];
179
180 if ( read( fd, buf, 2 ) != 2 || buf[0] != 'P' )
181 {
182 pbm_type = unknown; return;
183 }
184
185 switch( buf[1] )
186 {
187 case '1': pbm_type = pbm; break;
188 case '2': pbm_type = pgm; break;
189 case '3': pbm_type = ppm; break;
190 case '4': pbm_type = pbm_raw; break;
191 case '5': pbm_type = pgm_raw; break;
192 case '6': pbm_type = ppm_raw; break;
193 default: pbm_type = unknown; return;
194 }
195
196 pbm_xsize = pbm_getint( fd );
197 pbm_ysize = pbm_getint( fd );
198 }
199
200
201
202 void exit_usage _P1( (name), char * name )
203 {
204 fprintf( stderr,
205 "usage: %s [-w width] [-h blank_lines] [-d] [-a] [-r] [pbm file]\n",
206 name );
207 exit(1);
208 }
209
210
211 void convert_pbm_raw _P2( (fd, g3_page_width), int fd, int
212 g3_page_width )
213 {
214 extern void make_run_tables _PROTO((void));
215 extern char w_rtab[8][256],
216 b_rtab[8][256];
217
218 int x, y, maxx;
219 int run, c;
220 int bit;
221
222 int ll;
223 unsigned char * linebuf, * r;
224
225 /* initialize run length tables */
226 make_run_tables();
227
228 /* round up page width to byte boundary */
229 pbm_xsize = ( pbm_xsize + 7 ) & ~7;
230
231 /* malloc memory for line buffer */
232 ll = pbm_xsize / 8;
233 linebuf = (unsigned char *) malloc( ll );
234
235 if ( linebuf == NULL )
236 {
237 fprintf( stderr, "cannot malloc %d bytes: ", ll );
238 perror( "" );
239 exit(5);
240 }
241
242 /* maximum number of PELs to write pbm -> g3 */
243 if ( g3_page_width > pbm_xsize ) maxx = pbm_xsize;
244 else maxx = g3_page_width;
245
246 for ( y=0; y<pbm_ysize; y++ )
247 {
248 int h;
249
250 c = 0; /* start with white */
251 run = 0;
252 x = 0;
253 bit = 7;
254
255 /* read line into buffer (pipe -> multiple tries may be necessary!) */
256 h = 0;
257 while ( h < ll )
258 {
259 int h2;
260
261 h2 = read( fd, linebuf+h, ll-h );
262 if ( h2 == 0 )
263 {
264 fprintf( stderr, "line %d: want %d, got %d bytes, EOF", y, ll, h );
265 return; /* the page will be short... */
266 }
267 h += h2;
268 }
269
270 r = linebuf;
271
272 while ( x+run < maxx )
273 {
274 #ifdef NOISY
275 fprintf( stderr, "c=%d, bit=%d, x=%d, *r(%d)=%03o ", c, bit, x, r-linebuf, *r);
276 #endif
277 if ( c == 0 ) /* white run */
278 {
279 run += w_rtab[ bit ][ *r ];
280 bit -= w_rtab[ bit ][ *r ];
281 }
282 else /* black run */
283 {
284 run += b_rtab[ bit ][ *r ];
285 bit -= b_rtab[ bit ][ *r ];
286 }
287 #ifdef NOISY
288 fprintf( stderr, "-> run=%d, bit=%d\n", run, bit );
289 #endif
290 if ( bit < 0 ) /* continue in next byte */
291 {
292 if ( bit != -1 ) fprintf( stderr, "bit panic: %d\n", bit );
293 bit = 7;
294 r++;
295 }
296 else /* write out run, change color */
297 {
298 if ( c == 0 ) /* white */
299 putwhitespan( run );
300 else /* black */
301 putblackspan( run );
302
303 x += run;
304 run = 0;
305 c = !c;
306 }
307 } /* end while ( x+run < maxx ) */
308 #ifdef NOISY
309 fprintf( stderr, "end of line, c=%d, run=%d, bit=%d, x=%d\n", c, run, bit, x );
310 #endif
311
312 /* write rest of line */
313 if ( c == 0 ) putwhitespan( run + (g3_page_width - maxx) );
314 else
315 {
316 putblackspan( run );
317 putwhitespan( g3_page_width - maxx );
318 }
319 puteol();
320 } /* end for ( all y ) */
321 }
322
323 void convert_pbm _P2( (fd, g3_page_width), int fd, int g3_page_width )
324 {
325 int x, y;
326 int c, ch = 0;
327 int run;
328 FILE * fp;
329 int maxx;
330
331 if ( ( fp = fdopen( fd, "r" ) ) == NULL )
332 {
333 perror( "cannot fdopen: " );
334 exit( 5 );
335 }
336
337 /* maximum size of PELs to write pbm -> g3 */
338 if ( g3_page_width > pbm_xsize ) maxx = pbm_xsize;
339 else maxx = g3_page_width;
340
341 for ( y = 0; y < pbm_ysize; y++ )
342 {
343 c = '0'; /* start with white run length */
344 run = 0;
345
346 x = 0;
347 while ( x < maxx && ch != EOF )
348 {
349 ch = fgetc( fp );
350 if ( ch == '#' ) /* comment lines */
351 {
352 while ( ch != '\n' ) ch = fgetc( fp );
353 }
354 if ( ch == '0' || ch == '1' ) /* bits */
355 {
356 x++;
357 if ( ch == c ) run++;
358 else
359 {
360 if ( c == '0' ) putwhitespan( run );
361 else putblackspan( run );
362 c = ch;
363 run = 1;
364 }
365 }
366 } /* end while (x<maxx) */
367
368 /* read remainder of line (if pbm was wider than the G3 page) */
369 while ( x < pbm_xsize && ch != EOF )
370 {
371 ch = fgetc( fp );
372 if ( ch == '#' ) /* comment lines */
373 { while ( ch != '\n' ) ch = fgetc( fp ); }
374 if ( ch == '0' || ch == '1' ) /* bits */
375 { x++; }
376 }
377
378 if ( c == '0' ) putwhitespan( run + (g3_page_width - maxx) );
379 else
380 {
381 putblackspan( run );
382 putwhitespan( g3_page_width - maxx );
383 }
384
385 puteol();
386 }
387 }
388
389
390 extern int optind;
391 extern char * optarg;
392
393 int main _P2( (argc, argv), int argc, char ** argv )
394 {
395 int c, fd, i;
396 int empty_lines = 0;
397 int g3_page_width = 1728;
398 int digifax_header = FALSE;
399
400 init_byte_tab( FALSE, out_byte_tab );
401
402 while ( (c = getopt(argc, argv, "h:w:dar") ) != EOF)
403 {
404 switch (c)
405 {
406 case 'h': empty_lines = atoi( optarg ); break;
407 case 'w': g3_page_width = atoi( optarg ); break;
408 case 'd': digifax_header = TRUE; break;
409 case 'a': byte_align = TRUE; break;
410 case 'r': init_byte_tab( TRUE, out_byte_tab ); break;
411
412 default: exit_usage( argv[0] );
413 }
414 }
415
416 if ( optind == argc ||
417 strcmp( argv[optind], "-" ) == 0 ) /* read from stdin */
418 {
419 fd = 0;
420 }
421 else /* read from file */
422 {
423 if ( optind != argc -1 ) exit_usage( argv[0] );
424
425 fd = open( argv[optind], O_RDONLY );
426 if ( fd == -1 )
427 {
428 fprintf( stderr, "%s: cannot open %s: ", argv[0], argv[optind] );
429 perror( "" );
430 exit(2);
431 }
432 }
433
434 /* ok, open succeeded. now get file type */
435 pbm_getheader( fd );
436
437 /* reject unknown file types */
438 if ( pbm_type == unknown )
439 {
440 fprintf( stderr, "%s: input file type unknown\n", argv[0] );
441 exit(3);
442 }
443
444 /* barf if problems reading the header occured */
445 if ( pbm_xsize == -1 || pbm_ysize == -1 )
446 {
447 fprintf( stderr, "%s: error reading PBM header\n", argv[0] );
448 exit(4);
449 }
450
451 /* unsupported bitmap types */
452
453 if ( pbm_type == pgm || pbm_type == pgm_raw )
454 {
455 fprintf( stderr, "%s: portable greymaps (pgm) not supported, use ``pgmtopbm'' first.\n", argv[0] );
456 exit(3);
457 }
458 if ( pbm_type == ppm || pbm_type == ppm_raw )
459 {
460 fprintf( stderr, "%s: portable pixmap (ppm) not supported, use ``ppmtopgm | pgmtopbm'' first.\n", argv[0] );
461 exit(3);
462 }
463
464 /* the only remaing types are PBM and PBM RawBits */
465
466
467 /* if the g3_page_width is 0, use the width of the pbm file */
468 if ( g3_page_width == 0 ) g3_page_width = pbm_xsize;
469
470 /* if it's a RAW pbm file, round up the g3_page_width to
471 * multiples of 8 (to avoid byte-boundary problems)
472 */
473 if ( pbm_type == pbm_raw && g3_page_width < ( ( pbm_xsize+7 ) & ~7) )
474 {
475 g3_page_width = ( g3_page_width + 7 ) & ~7;
476 }
477
478 /* output leading EOL and possibly leading blank lines */
479 puteol();
480 for ( i=0; i<empty_lines; i++ )
481 {
482 putwhitespan( g3_page_width ); puteol();
483 }
484
485 /* convert file */
486 if ( pbm_type == pbm )
487 {
488 convert_pbm( fd, g3_page_width );
489 }
490 else
491 {
492 convert_pbm_raw( fd, g3_page_width );
493 }
494
495 /* over & out */
496 close( fd );
497
498 /* output final RTC */
499 for ( i=0; i<6; i++ ) puteol();
500
501 /* flush buffer */
502 if ( out_hibit != 0 )
503 buf[buflen++] = out_byte_tab[out_data & 0xff];
504 write( 1, buf, buflen );
505
506 exit(0);
507 }
508