1 #define Copyright "Copyright 1999 Ed Casas"
3 #define Version "efix v 0.3"
6 Copyright (C) 1999 Ed Casas
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 Please contact the author if you wish to use efax or efix in
23 ways not covered by the GNU GPL.
25 You may contact the author by e-mail at: edc@cce.com, by mail
26 at: 2629 West 3rd Ave, Vancouver, BC, Canada, V6K 1M4, or by
27 fax at: +1 604 734 5291.
33 " %s [ option ]... file... \n"
34 "Options (defaults):\n"
35 " -i f input format (auto):\n"
36 " fax fax (\"Group3\") 1-D coded image\n"
38 " pbm raw PBM (portable bit map)\n"
39 " tiffg3 TIFF, Group 3 fax compression\n"
40 " tiffraw TIFF, no compression\n"
43 " -o f output format (tiffg3):\n"
44 " fax fax (\"Group3\") 1-D coded image\n"
45 " pbm Portable Bit Map\n"
46 " pgm Portable Gray Map (decimated by 4)\n"
47 " pcl HP-PCL (e.g. HP LaserJet)\n"
48 " ps Postscript (e.g. Apple Laserwriter)\n"
49 " tiffg3 TIFF, Group 3 fax compression\n"
50 " tiffraw TIFF, no compression\n"
53 " -n pat printf() pattern for output file name (ofile)\n"
54 " -f fnt use PBM font file fnt for text (built-in)\n"
55 " -l n lines per text page (66)\n"
56 " -v lvl print messages of type in string lvl (ewi)\n"
57 " -s XxY scale input by X and Y (Y optional) (1x1)\n"
58 " -r XxY resolution of output is X by Y (dpi, Y optional) (204x196)\n"
59 " -R XxY resolution of input is X by Y (dpi, Y optional) (204x196)\n"
60 " -p WxH pad/truncate output to width W by height H (215x297mm)\n"
61 " -d R,D displace output right R, down D (opposite if -ve) (0,0)\n"
62 " -O f overlay file f (none)\n"
63 " -M ignore other options and base64 (MIME) encode stdin to stdout\n"
65 "Add 'in', 'cm', 'mm', or 'pt' to -p and -d arguments (default in[ches]).\n"
66 "Default output size and resolution is same as input (if known).\n"
69 #include <ctype.h> /* ANSI C */
82 /* Allowed input and output formats. *** MUST match enum *** */
84 char *iformatstr[] = { " 3text", " 1pbm", " 2fax", " 4tiffg3", " 4tiffraw",
85 " 6pcx", " 6pcxraw", " 8dcx", 0 } ;
87 char *oformatstr[] = { " 1pbm" , " 2fax", " 3pcl", " 4ps", " 5pgm",
88 " 7tiffg3", " 8tiffraw",
89 "11pcx", "12pcxraw", "13dcx", 0 } ;
91 /* Look up a string in a NULL-delimited table where the first
92 character of each string is the digit to return if the rest of
93 the string matches. Returns the value of the digit for the
94 matching string or -1 if no matches. */
96 int lookup ( char **tab, char *s )
99 for ( p=tab ; p && *p && strcmp ( *p+2, s ) ; p++ ) ;
100 return p && *p ? atoi ( *p ) : -1 ;
104 /* Extract pair of values from string. If it's a `dim'ension,
105 two values are required and they are converted to inches, else
106 the y value is optional. Returns 0 or 2 on error. */
108 int getxy ( char *arg, float *x, float *y, int dim )
110 int i, n, nc=0, err=0 ;
112 static char *unitstr[] = { " 0in", " 1cm", " 2mm", " 3pt", 0 } ;
113 static float unitval[] = { 1.0, 2.54, 25.4, 72.0, 1.0 } ;
116 err = msg ( "E2 missing argument" ) ;
119 err = msg ( "E2 can't happen (getxy)" ) ;
122 n = sscanf ( arg , "%f%c%f%n", x, &c, y, &nc ) ;
124 case 0 : err = msg ( "E2bad X value in (%s)", arg ) ; break ;
125 case 2 : err = msg ( "E2bad Y value in (%s)", arg ) ; break ;
132 err = msg ( "Emissing Y dimension in (%s)", arg ) ;
134 while ( arg [ nc ] && isspace ( arg [ nc ] ) ) nc++ ;
136 if ( ( i = lookup ( unitstr, arg+nc ) ) >= 0 ) {
137 *x /= unitval [ i ] ;
138 *y /= unitval [ i ] ;
140 err = msg ( "E2bad units: `%s'", arg+nc ) ;
145 if ( n == 1 ) *y = *x ;
150 msg ( "Aconverted (%s) into %f x %f", arg, *x, *y ) ;
156 /* Copy stdin to stdout while applying base64 (RFC 1521)
157 encoding. This encoding must be applied after the file is
158 complete since some output formats (e.g. TIFF) require seeking
159 backwards within the (binary) file. */
161 int base64encode ( void )
164 uchar n=0, m=0, bits=0 ;
166 static uchar chartab[65] =
167 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
168 "abcdefghijklmnopqrstuvwxyz"
171 while ( ( c = fgetc ( stdin ) ) >= 0 ) {
174 putc ( chartab [ c >> 2 ], stdout ) ;
179 putc ( chartab [ (bits << 4) | ( c >> 4 ) ], stdout ) ;
184 putc ( chartab [ (bits << 2) | ( c >> 6 ) ], stdout ) ;
185 putc ( chartab [ c & 0x3f ], stdout ) ;
188 putc ( '\n', stdout ) ;
200 putc ( chartab [ (bits << 4) | ( 0 >> 4 ) ], stdout ) ;
201 putc ( '=', stdout ) ;
202 putc ( '=', stdout ) ;
205 putc ( chartab [ (bits << 2) | ( 0 >> 6 ) ], stdout ) ;
206 putc ( '=', stdout ) ;
210 putc ( '\n', stdout ) ;
216 int main( int argc, char **argv)
218 int err=0, done=0, i, c ;
219 int nr, pels, ovnr, ovpels, no ; /* run/pixel/repeat counts */
221 int page, ilines, olines ; /* page & line counts */
222 int xs, ys, w, h, ixsh, iysh ; /* integer scale, size & shift */
223 short runs [ MAXRUNS ] , ovruns [ MAXRUNS ] ;
225 float /* defaults: */
226 xsc=1.0, ysc=1.0, /* scale */
227 xsh=0.0, ysh=0.0, /* shift */
228 dxres = 204.145, /* o/p res'n: 1728/215mm * 25.4 x */
229 dyres = 195.58, /* 7.7 * 25.4 */
230 dxsz = 215 / 25.4, /* o/p size: 8.5" x A4 */
233 float /* arguments: */
234 axres = 0, ayres = 0, axsz = 0, aysz = 0, ainxres=0, ainyres=0 ;
236 float /* values used: */
237 xres = 0, yres = 0, xsz = 0, ysz = 0 ;
239 IFILE ifile, ovfile ;
242 char **ifnames, *ovfnames [ 2 ] = { 0, 0 } ;
244 int iformat=I_AUTO, oformat=O_TIFF_FAX, pglines=0 ;
247 faxfont font, *pfont=0 ; /* text font */
253 /* process arguments */
255 while ( !err && (c=nextopt(argc,argv,"n:i:o:O:v:l:f:r:s:p:d:R:M") ) != -1) {
261 if ( ( iformat = lookup ( iformatstr, nxtoptarg ) ) < 0 )
262 err = msg ( "E2invalid input type (%s)", nxtoptarg ) ;
265 if ( ( oformat = lookup ( oformatstr, nxtoptarg ) ) < 0 )
266 err = msg ( "E2invalid output type (%s)", nxtoptarg ) ;
269 ovfnames[0] = nxtoptarg ;
272 verb[0] = nxtoptarg ;
273 msg ( "A " Version ) ;
274 for ( i=0 ; i<argc ; i++ ) msg ( "Aargv[%d]=%s", i, argv[i]) ;
277 if ( sscanf ( nxtoptarg , "%d", &pglines ) != 1 || pglines <= 0 ) {
278 err = msg ( "E2bad page length (%s)", nxtoptarg ) ;
283 if ( ! ( err = readfont ( nxtoptarg, &font ) ) )
286 case 's' : err = getxy ( nxtoptarg, &xsc , &ysc , 0 ) ; break ;
287 case 'r' : err = getxy ( nxtoptarg, &axres, &ayres, 0 ) ; break ;
288 case 'R' : err = getxy ( nxtoptarg, &ainxres, &ainyres, 0 ) ; break ;
289 case 'p' : err = getxy ( nxtoptarg, &axsz , &aysz , 1 ) ; break ;
290 case 'd' : err = getxy ( nxtoptarg, &xsh , &ysh , 1 ) ; break ;
291 case 'M' : err = base64encode() ; done=1 ; break ;
292 default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
296 msg ( "I " Version " " Copyright ) ;
298 if ( ! err && ! done ) {
300 if ( nxtoptind < argc ) {
301 ifnames = argv + nxtoptind ;
302 if ( argv [ argc ] ) {
303 err = msg ("E2can't happen(unterminated argv)") ;
305 newIFILE ( &ifile, ifnames ) ;
308 err = msg ( "E3 missing input file name" ) ;
311 if ( pfont ) ifile.font = pfont ;
312 if ( pglines ) ifile.pglines = pglines ;
314 newIFILE ( &ovfile, ovfnames ) ;
316 newOFILE ( &ofile, oformat, ofname, 0, 0, 0, 0 ) ;
320 for ( page = 0 ; ! err && ! done ; page++ ) {
322 if ( nextipage ( &ifile, page != 0 ) ) {
327 /* set output size and resolution equal to input if none specified */
329 if ( ainxres > 0 ) ifile.page->xres = ainxres ;
330 if ( ainyres > 0 ) ifile.page->yres = ainyres ;
332 if ( ifile.page->xres <= 0 ) ifile.page->xres = dxres ;
333 if ( ifile.page->yres <= 0 ) ifile.page->yres = dyres ;
335 xres = axres > 0 ? axres : ifile.page->xres ;
336 yres = ayres > 0 ? ayres : ifile.page->yres ;
338 xsz = axsz > 0 ? axsz : ( ifile.page->w > 0 ?
339 ifile.page->w / ifile.page->xres : dxsz ) ;
340 ysz = aysz > 0 ? aysz : ( ifile.page->h > 0 ?
341 ifile.page->h / ifile.page->yres : dysz ) ;
344 w = xsz * xres + 0.5 ; /* output dimensions in pixels */
345 h = ysz * yres + 0.5 ;
347 ixsh = xsh * xres ; /* x/y shifts in pixels/lines */
350 if ( ( w & 7 ) != 0 ) /* just about everything requires... */
351 msg ("Iimage width rounded to %d pixels",
352 w = ( w + 7 ) & ~7 ) ;
354 if ( ofile.format == O_PGM && h & 3 ) /* PGM x4 decimation requires... */
355 msg ("I PGM image height rounded up to %d lines",
356 h = ( h + 3 ) & ~3 ) ;
358 if ( w <= 0 || h <= 0 || xres < 0 || yres < 0 )
359 err = msg ( "E2negative/zero scaling/size/resolution" ) ;
361 if ( ofile.format == O_PCL && /* check for strange PCL resolutions */
362 ( xres != yres || ( xres != 300 && xres != 150 && xres != 75 ) ) )
363 msg ( "Wstrange PCL resolution (%.0fx%.0f)", xres, yres ) ;
365 if ( w > MAXBITS*8 ) /* make sure output will fit... */
366 err = msg( "E2requested output width too large (%d pixels)", w ) ;
373 /* scale according to input file resolution */
375 xs = 256 * xsc * xres / ifile.page->xres + 0.5 ;
376 ys = 256 * ysc * yres / ifile.page->yres + 0.5 ;
378 if ( xs <= 0 || ys <= 0 )
379 err = msg ( "E2negative/zero scaling" ) ;
381 if ( *ovfnames ) /* [re-]open overlay file */
382 if ( nextipage ( &ovfile , 0 ) ) {
387 if ( nextopage ( &ofile, page ) ) {
396 writeline ( &ofile, ( ( *runs = w ), runs ), 1, iysh ) ;
399 for ( i=0 ; i < -iysh ; i++ )
400 readline ( &ifile, runs, 0 ) ;
403 /* copy input to output */
405 olines = ilines = 0 ;
407 while ( linesout < h ) {
409 if ( ( nr = readline ( &ifile, runs, &pels ) ) < 0 )
415 if ( ( ovnr = readline ( &ovfile, ovruns, &ovpels ) ) >= 0 )
416 nr = runor ( runs, nr, ovruns, ovnr, 0, &pels ) ;
419 /* x-scale, x-shift & x-pad input line */
421 pels = ( xs == 256 ) ? pels : xscale ( runs, nr, xs ) ;
422 pels += ( ixsh == 0 ) ? 0 : xshift ( runs, nr, ixsh ) ;
423 nr = ( pels == w ) ? nr : xpad ( runs, nr, w - pels ) ;
425 /* y-scale by deleting/duplicating lines. */
427 no = ( ( ilines * ys ) >> 8 ) - olines ;
429 if ( linesout + no > h ) no = h - linesout ;
432 writeline ( &ofile, runs, nr, no ) ;
439 writeline ( &ofile, ( ( *runs = w ), runs ), 1, h - linesout ) ;
441 if ( ferror ( ifile.f ) ) err = msg ( "ES2input error:" ) ;
444 nextopage ( &ofile, EOF ) ;