3 #define Copyright "Copyright 1999 Ed Casas"
5 #define Version "efix v 0.3"
8 Copyright (C) 1999 Ed Casas
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 Please contact the author if you wish to use efax or efix in
25 ways not covered by the GNU GPL.
27 You may contact the author by e-mail at: edc@cce.com, by mail
28 at: 2629 West 3rd Ave, Vancouver, BC, Canada, V6K 1M4, or by
29 fax at: +1 604 734 5291.
35 " %s [ option ]... file... \n"
36 "Options (defaults):\n"
37 " -i f input format (auto):\n"
38 " fax fax (\"Group3\") 1-D coded image\n"
40 " pbm raw PBM (portable bit map)\n"
41 " tiffg3 TIFF, Group 3 fax compression\n"
42 " tiffraw TIFF, no compression\n"
45 " -o f output format (tiffg3):\n"
46 " fax fax (\"Group3\") 1-D coded image\n"
47 " pbm Portable Bit Map\n"
48 " pgm Portable Gray Map (decimated by 4)\n"
49 " pcl HP-PCL (e.g. HP LaserJet)\n"
50 " ps Postscript (e.g. Apple Laserwriter)\n"
51 " tiffg3 TIFF, Group 3 fax compression\n"
52 " tiffraw TIFF, no compression\n"
55 " -n pat printf() pattern for output file name (ofile)\n"
56 " -f fnt use PBM font file fnt for text (built-in)\n"
57 " -l n lines per text page (66)\n"
58 " -v lvl print messages of type in string lvl (ewi)\n"
59 " -s XxY scale input by X and Y (Y optional) (1x1)\n"
60 " -r XxY resolution of output is X by Y (dpi, Y optional) (204x196)\n"
61 " -R XxY resolution of input is X by Y (dpi, Y optional) (204x196)\n"
62 " -p WxH pad/truncate output to width W by height H (215x297mm)\n"
63 " -d R,D displace output right R, down D (opposite if -ve) (0,0)\n"
64 " -O f overlay file f (none)\n"
65 " -M ignore other options and base64 (MIME) encode stdin to stdout\n"
67 "Add 'in', 'cm', 'mm', or 'pt' to -p and -d arguments (default in[ches]).\n"
68 "Default output size and resolution is same as input (if known).\n"
71 #include <ctype.h> /* ANSI C */
84 /* Allowed input and output formats. *** MUST match enum *** */
86 char *iformatstr[] = { " 3text", " 1pbm", " 2fax", " 4tiffg3", " 4tiffraw",
87 " 6pcx", " 6pcxraw", " 8dcx", 0 } ;
89 char *oformatstr[] = { " 1pbm" , " 2fax", " 3pcl", " 4ps", " 5pgm",
90 " 7tiffg3", " 8tiffraw",
91 "11pcx", "12pcxraw", "13dcx", 0 } ;
93 /* Look up a string in a NULL-delimited table where the first
94 character of each string is the digit to return if the rest of
95 the string matches. Returns the value of the digit for the
96 matching string or -1 if no matches. */
98 int lookup ( char **tab, char *s )
101 for ( p=tab ; p && *p && strcmp ( *p+2, s ) ; p++ ) ;
102 return p && *p ? atoi ( *p ) : -1 ;
106 /* Extract pair of values from string. If it's a `dim'ension,
107 two values are required and they are converted to inches, else
108 the y value is optional. Returns 0 or 2 on error. */
110 int getxy ( char *arg, float *x, float *y, int dim )
112 int i, n, nc=0, err=0 ;
114 static char *unitstr[] = { " 0in", " 1cm", " 2mm", " 3pt", 0 } ;
115 static float unitval[] = { 1.0, 2.54, 25.4, 72.0, 1.0 } ;
118 err = msg ( "E2 missing argument" ) ;
121 err = msg ( "E2 can't happen (getxy)" ) ;
124 n = sscanf ( arg , "%f%c%f%n", x, &c, y, &nc ) ;
126 case 0 : err = msg ( "E2bad X value in (%s)", arg ) ; break ;
127 case 2 : err = msg ( "E2bad Y value in (%s)", arg ) ; break ;
134 err = msg ( "Emissing Y dimension in (%s)", arg ) ;
136 while ( arg [ nc ] && isspace ( arg [ nc ] ) ) nc++ ;
138 if ( ( i = lookup ( unitstr, arg+nc ) ) >= 0 ) {
139 *x /= unitval [ i ] ;
140 *y /= unitval [ i ] ;
142 err = msg ( "E2bad units: `%s'", arg+nc ) ;
147 if ( n == 1 ) *y = *x ;
152 msg ( "Aconverted (%s) into %f x %f", arg, *x, *y ) ;
158 /* Copy stdin to stdout while applying base64 (RFC 1521)
159 encoding. This encoding must be applied after the file is
160 complete since some output formats (e.g. TIFF) require seeking
161 backwards within the (binary) file. */
163 int base64encode ( void )
166 uchar n=0, m=0, bits=0 ;
168 static uchar chartab[65] =
169 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
170 "abcdefghijklmnopqrstuvwxyz"
173 while ( ( c = fgetc ( stdin ) ) >= 0 ) {
176 putc ( chartab [ c >> 2 ], stdout ) ;
181 putc ( chartab [ (bits << 4) | ( c >> 4 ) ], stdout ) ;
186 putc ( chartab [ (bits << 2) | ( c >> 6 ) ], stdout ) ;
187 putc ( chartab [ c & 0x3f ], stdout ) ;
190 putc ( '\n', stdout ) ;
202 putc ( chartab [ (bits << 4) | ( 0 >> 4 ) ], stdout ) ;
203 putc ( '=', stdout ) ;
204 putc ( '=', stdout ) ;
207 putc ( chartab [ (bits << 2) | ( 0 >> 6 ) ], stdout ) ;
208 putc ( '=', stdout ) ;
212 putc ( '\n', stdout ) ;
218 int main( int argc, char **argv)
220 int err=0, done=0, i, c ;
221 int nr, pels, ovnr, ovpels, no ; /* run/pixel/repeat counts */
223 int page, ilines, olines ; /* page & line counts */
224 int xs, ys, w, h, ixsh, iysh ; /* integer scale, size & shift */
225 short runs [ MAXRUNS ] , ovruns [ MAXRUNS ] ;
227 float /* defaults: */
228 xsc=1.0, ysc=1.0, /* scale */
229 xsh=0.0, ysh=0.0, /* shift */
230 dxres = 204.145, /* o/p res'n: 1728/215mm * 25.4 x */
231 dyres = 195.58, /* 7.7 * 25.4 */
232 dxsz = 215 / 25.4, /* o/p size: 8.5" x A4 */
235 float /* arguments: */
236 axres = 0, ayres = 0, axsz = 0, aysz = 0, ainxres=0, ainyres=0 ;
238 float /* values used: */
239 xres = 0, yres = 0, xsz = 0, ysz = 0 ;
241 IFILE ifile, ovfile ;
244 char **ifnames, *ovfnames [ 2 ] = { 0, 0 } ;
246 int iformat=I_AUTO, oformat=O_TIFF_FAX, pglines=0 ;
249 faxfont font, *pfont=0 ; /* text font */
255 /* process arguments */
257 while ( !err && (c=nextopt(argc,argv,"n:i:o:O:v:l:f:r:s:p:d:R:M") ) != -1) {
263 if ( ( iformat = lookup ( iformatstr, nxtoptarg ) ) < 0 )
264 err = msg ( "E2invalid input type (%s)", nxtoptarg ) ;
267 if ( ( oformat = lookup ( oformatstr, nxtoptarg ) ) < 0 )
268 err = msg ( "E2invalid output type (%s)", nxtoptarg ) ;
271 ovfnames[0] = nxtoptarg ;
274 verb[0] = nxtoptarg ;
275 msg ( "A " Version ) ;
276 for ( i=0 ; i<argc ; i++ ) msg ( "Aargv[%d]=%s", i, argv[i]) ;
279 if ( sscanf ( nxtoptarg , "%d", &pglines ) != 1 || pglines <= 0 ) {
280 err = msg ( "E2bad page length (%s)", nxtoptarg ) ;
285 if ( ! ( err = readfont ( nxtoptarg, &font ) ) )
288 case 's' : err = getxy ( nxtoptarg, &xsc , &ysc , 0 ) ; break ;
289 case 'r' : err = getxy ( nxtoptarg, &axres, &ayres, 0 ) ; break ;
290 case 'R' : err = getxy ( nxtoptarg, &ainxres, &ainyres, 0 ) ; break ;
291 case 'p' : err = getxy ( nxtoptarg, &axsz , &aysz , 1 ) ; break ;
292 case 'd' : err = getxy ( nxtoptarg, &xsh , &ysh , 1 ) ; break ;
293 case 'M' : err = base64encode() ; done=1 ; break ;
294 default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
298 msg ( "I " Version " " Copyright ) ;
300 if ( ! err && ! done ) {
302 if ( nxtoptind < argc ) {
303 ifnames = argv + nxtoptind ;
304 if ( argv [ argc ] ) {
305 err = msg ("E2can't happen(unterminated argv)") ;
307 newIFILE ( &ifile, ifnames ) ;
310 err = msg ( "E3 missing input file name" ) ;
313 if ( pfont ) ifile.font = pfont ;
314 if ( pglines ) ifile.pglines = pglines ;
316 newIFILE ( &ovfile, ovfnames ) ;
318 newOFILE ( &ofile, oformat, ofname, 0, 0, 0, 0 ) ;
322 for ( page = 0 ; ! err && ! done ; page++ ) {
324 if ( nextipage ( &ifile, page != 0 ) ) {
329 /* set output size and resolution equal to input if none specified */
331 if ( ainxres > 0 ) ifile.page->xres = ainxres ;
332 if ( ainyres > 0 ) ifile.page->yres = ainyres ;
334 if ( ifile.page->xres <= 0 ) ifile.page->xres = dxres ;
335 if ( ifile.page->yres <= 0 ) ifile.page->yres = dyres ;
337 xres = axres > 0 ? axres : ifile.page->xres ;
338 yres = ayres > 0 ? ayres : ifile.page->yres ;
340 xsz = axsz > 0 ? axsz : ( ifile.page->w > 0 ?
341 ifile.page->w / ifile.page->xres : dxsz ) ;
342 ysz = aysz > 0 ? aysz : ( ifile.page->h > 0 ?
343 ifile.page->h / ifile.page->yres : dysz ) ;
346 w = xsz * xres + 0.5 ; /* output dimensions in pixels */
347 h = ysz * yres + 0.5 ;
349 ixsh = xsh * xres ; /* x/y shifts in pixels/lines */
352 if ( ( w & 7 ) != 0 ) /* just about everything requires... */
353 msg ("Iimage width rounded to %d pixels",
354 w = ( w + 7 ) & ~7 ) ;
356 if ( ofile.format == O_PGM && h & 3 ) /* PGM x4 decimation requires... */
357 msg ("I PGM image height rounded up to %d lines",
358 h = ( h + 3 ) & ~3 ) ;
360 if ( w <= 0 || h <= 0 || xres < 0 || yres < 0 )
361 err = msg ( "E2negative/zero scaling/size/resolution" ) ;
363 if ( ofile.format == O_PCL && /* check for strange PCL resolutions */
364 ( xres != yres || ( xres != 300 && xres != 150 && xres != 75 ) ) )
365 msg ( "Wstrange PCL resolution (%.0fx%.0f)", xres, yres ) ;
367 if ( w > MAXBITS*8 ) /* make sure output will fit... */
368 err = msg( "E2requested output width too large (%d pixels)", w ) ;
375 /* scale according to input file resolution */
377 xs = 256 * xsc * xres / ifile.page->xres + 0.5 ;
378 ys = 256 * ysc * yres / ifile.page->yres + 0.5 ;
380 if ( xs <= 0 || ys <= 0 )
381 err = msg ( "E2negative/zero scaling" ) ;
383 if ( *ovfnames ) /* [re-]open overlay file */
384 if ( nextipage ( &ovfile , 0 ) ) {
389 if ( nextopage ( &ofile, page ) ) {
398 writeline ( &ofile, ( ( *runs = w ), runs ), 1, iysh ) ;
401 for ( i=0 ; i < -iysh ; i++ )
402 readline ( &ifile, runs, 0 ) ;
405 /* copy input to output */
407 olines = ilines = 0 ;
409 while ( linesout < h ) {
411 if ( ( nr = readline ( &ifile, runs, &pels ) ) < 0 )
417 if ( ( ovnr = readline ( &ovfile, ovruns, &ovpels ) ) >= 0 )
418 nr = runor ( runs, nr, ovruns, ovnr, 0, &pels ) ;
421 /* x-scale, x-shift & x-pad input line */
423 pels = ( xs == 256 ) ? pels : xscale ( runs, nr, xs ) ;
424 pels += ( ixsh == 0 ) ? 0 : xshift ( runs, nr, ixsh ) ;
425 nr = ( pels == w ) ? nr : xpad ( runs, nr, w - pels ) ;
427 /* y-scale by deleting/duplicating lines. */
429 no = ( ( ilines * ys ) >> 8 ) - olines ;
431 if ( linesout + no > h ) no = h - linesout ;
434 writeline ( &ofile, runs, nr, no ) ;
441 writeline ( &ofile, ( ( *runs = w ), runs ), 1, h - linesout ) ;
443 if ( ferror ( ifile.f ) ) err = msg ( "ES2input error:" ) ;
446 nextopage ( &ofile, EOF ) ;