/* pbmtopsg3 Reads a series of PBM images and writes a Postscript program containing these images as individual pages with Fax-G3 (CCITT-Fiter) compression. (Useful for combining scanned pages into a comfortably printable document.) Copyright (C) 2001 Kristof Koehler Netpbm adaptation by Bryan Henderson June 2001. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include #include #include "pm_c_util.h" #include "pbm.h" #include "shhopt.h" struct cmdline_info { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFilespec; /* Filespec of input file */ float dpi; /* requested resolution, dpi */ char * title; /* -title option. NULL for none */ }; static void parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) { optStruct3 opt; unsigned int option_def_index = 0; optEntry *option_def = malloc(100*sizeof(optEntry)); unsigned int dpiSpec, titleSpec; float dpiOpt; char * titleOpt; OPTENT3(0, "dpi", OPT_FLOAT, &dpiOpt, &dpiSpec, 0); OPTENT3(0, "title", OPT_STRING, &titleOpt, &titleSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; opt.allowNegNum = FALSE; pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (argc-1 == 0) cmdlineP->inputFilespec = "-"; else { cmdlineP->inputFilespec = argv[1]; if (argc-1 > 1) pm_error("Too many arguments. The only argument is the input " "file specification"); } cmdlineP->dpi = dpiSpec ? dpiOpt : 72.0; cmdlineP->title = titleSpec ? titleOpt : NULL; } static void write85 ( unsigned int bits, int *col ) { char buf[5] ; if ( bits == 0 ) { fputc ( 'z', stdout ) ; *col += 1 ; } else { buf[4] = bits % 85 + '!' ; bits /= 85 ; buf[3] = bits % 85 + '!' ; bits /= 85 ; buf[2] = bits % 85 + '!' ; bits /= 85 ; buf[1] = bits % 85 + '!' ; bits /= 85 ; buf[0] = bits % 85 + '!' ; fwrite ( buf, 1, 5, stdout ) ; *col += 5 ; } if ( *col > 70 ) { printf ( "\n" ) ; *col = 0 ; } } static void writebits ( unsigned int *outbits, int *outbitsidx, int *col, unsigned int bits, int n ) { int k, m ; unsigned int usedbits ; while ( n > 0 ) { if ( *outbitsidx == 0 ) *outbits = 0 ; k = 32 - *outbitsidx ; m = n > k ? k : n ; usedbits = (bits >> (n-m)) & ((1< 0 ) { write85 ( *outbits, col ) ; *outbitsidx = 0 ; } } struct { unsigned int b, l ; } makeup[40][2] = { { { 0x001b, 5 } /* 11011 */ , { 0x000f,10 } /* 0000001111 */ }, { { 0x0012, 5 } /* 10010 */ , { 0x00c8,12 } /* 000011001000 */ }, { { 0x0017, 6 } /* 010111 */ , { 0x00c9,12 } /* 000011001001 */ }, { { 0x0037, 7 } /* 0110111 */ , { 0x005b,12 } /* 000001011011 */ }, { { 0x0036, 8 } /* 00110110 */ , { 0x0033,12 } /* 000000110011 */ }, { { 0x0037, 8 } /* 00110111 */ , { 0x0034,12 } /* 000000110100 */ }, { { 0x0064, 8 } /* 01100100 */ , { 0x0035,12 } /* 000000110101 */ }, { { 0x0065, 8 } /* 01100101 */ , { 0x006c,13 } /* 0000001101100 */ }, { { 0x0068, 8 } /* 01101000 */ , { 0x006d,13 } /* 0000001101101 */ }, { { 0x0067, 8 } /* 01100111 */ , { 0x004a,13 } /* 0000001001010 */ }, { { 0x00cc, 9 } /* 011001100 */ , { 0x004b,13 } /* 0000001001011 */ }, { { 0x00cd, 9 } /* 011001101 */ , { 0x004c,13 } /* 0000001001100 */ }, { { 0x00d2, 9 } /* 011010010 */ , { 0x004d,13 } /* 0000001001101 */ }, { { 0x00d3, 9 } /* 011010011 */ , { 0x0072,13 } /* 0000001110010 */ }, { { 0x00d4, 9 } /* 011010100 */ , { 0x0073,13 } /* 0000001110011 */ }, { { 0x00d5, 9 } /* 011010101 */ , { 0x0074,13 } /* 0000001110100 */ }, { { 0x00d6, 9 } /* 011010110 */ , { 0x0075,13 } /* 0000001110101 */ }, { { 0x00d7, 9 } /* 011010111 */ , { 0x0076,13 } /* 0000001110110 */ }, { { 0x00d8, 9 } /* 011011000 */ , { 0x0077,13 } /* 0000001110111 */ }, { { 0x00d9, 9 } /* 011011001 */ , { 0x0052,13 } /* 0000001010010 */ }, { { 0x00da, 9 } /* 011011010 */ , { 0x0053,13 } /* 0000001010011 */ }, { { 0x00db, 9 } /* 011011011 */ , { 0x0054,13 } /* 0000001010100 */ }, { { 0x0098, 9 } /* 010011000 */ , { 0x0055,13 } /* 0000001010101 */ }, { { 0x0099, 9 } /* 010011001 */ , { 0x005a,13 } /* 0000001011010 */ }, { { 0x009a, 9 } /* 010011010 */ , { 0x005b,13 } /* 0000001011011 */ }, { { 0x0018, 6 } /* 011000 */ , { 0x0064,13 } /* 0000001100100 */ }, { { 0x009b, 9 } /* 010011011 */ , { 0x0065,13 } /* 0000001100101 */ }, { { 0x0008,11 } /* 00000001000 */ , { 0x0008,11 } /* 00000001000 */ }, { { 0x000c,11 } /* 00000001100 */ , { 0x000c,11 } /* 00000001100 */ }, { { 0x000d,11 } /* 00000001101 */ , { 0x000d,11 } /* 00000001101 */ }, { { 0x0012,12 } /* 000000010010 */ , { 0x0012,12 } /* 000000010010 */ }, { { 0x0013,12 } /* 000000010011 */ , { 0x0013,12 } /* 000000010011 */ }, { { 0x0014,12 } /* 000000010100 */ , { 0x0014,12 } /* 000000010100 */ }, { { 0x0015,12 } /* 000000010101 */ , { 0x0015,12 } /* 000000010101 */ }, { { 0x0016,12 } /* 000000010110 */ , { 0x0016,12 } /* 000000010110 */ }, { { 0x0017,12 } /* 000000010111 */ , { 0x0017,12 } /* 000000010111 */ }, { { 0x001c,12 } /* 000000011100 */ , { 0x001c,12 } /* 000000011100 */ }, { { 0x001d,12 } /* 000000011101 */ , { 0x001d,12 } /* 000000011101 */ }, { { 0x001e,12 } /* 000000011110 */ , { 0x001e,12 } /* 000000011110 */ }, { { 0x001f,12 } /* 000000011111 */ , { 0x001f,12 } /* 000000011111 */ } } ; struct { unsigned int b, l ; } term[64][2] = { { { 0x0035, 8 } /* 00110101 */ , { 0x0037,10 } /* 0000110111 */ }, { { 0x0007, 6 } /* 000111 */ , { 0x0002, 3 } /* 010 */ }, { { 0x0007, 4 } /* 0111 */ , { 0x0003, 2 } /* 11 */ }, { { 0x0008, 4 } /* 1000 */ , { 0x0002, 2 } /* 10 */ }, { { 0x000b, 4 } /* 1011 */ , { 0x0003, 3 } /* 011 */ }, { { 0x000c, 4 } /* 1100 */ , { 0x0003, 4 } /* 0011 */ }, { { 0x000e, 4 } /* 1110 */ , { 0x0002, 4 } /* 0010 */ }, { { 0x000f, 4 } /* 1111 */ , { 0x0003, 5 } /* 00011 */ }, { { 0x0013, 5 } /* 10011 */ , { 0x0005, 6 } /* 000101 */ }, { { 0x0014, 5 } /* 10100 */ , { 0x0004, 6 } /* 000100 */ }, { { 0x0007, 5 } /* 00111 */ , { 0x0004, 7 } /* 0000100 */ }, { { 0x0008, 5 } /* 01000 */ , { 0x0005, 7 } /* 0000101 */ }, { { 0x0008, 6 } /* 001000 */ , { 0x0007, 7 } /* 0000111 */ }, { { 0x0003, 6 } /* 000011 */ , { 0x0004, 8 } /* 00000100 */ }, { { 0x0034, 6 } /* 110100 */ , { 0x0007, 8 } /* 00000111 */ }, { { 0x0035, 6 } /* 110101 */ , { 0x0018, 9 } /* 000011000 */ }, { { 0x002a, 6 } /* 101010 */ , { 0x0017,10 } /* 0000010111 */ }, { { 0x002b, 6 } /* 101011 */ , { 0x0018,10 } /* 0000011000 */ }, { { 0x0027, 7 } /* 0100111 */ , { 0x0008,10 } /* 0000001000 */ }, { { 0x000c, 7 } /* 0001100 */ , { 0x0067,11 } /* 00001100111 */ }, { { 0x0008, 7 } /* 0001000 */ , { 0x0068,11 } /* 00001101000 */ }, { { 0x0017, 7 } /* 0010111 */ , { 0x006c,11 } /* 00001101100 */ }, { { 0x0003, 7 } /* 0000011 */ , { 0x0037,11 } /* 00000110111 */ }, { { 0x0004, 7 } /* 0000100 */ , { 0x0028,11 } /* 00000101000 */ }, { { 0x0028, 7 } /* 0101000 */ , { 0x0017,11 } /* 00000010111 */ }, { { 0x002b, 7 } /* 0101011 */ , { 0x0018,11 } /* 00000011000 */ }, { { 0x0013, 7 } /* 0010011 */ , { 0x00ca,12 } /* 000011001010 */ }, { { 0x0024, 7 } /* 0100100 */ , { 0x00cb,12 } /* 000011001011 */ }, { { 0x0018, 7 } /* 0011000 */ , { 0x00cc,12 } /* 000011001100 */ }, { { 0x0002, 8 } /* 00000010 */ , { 0x00cd,12 } /* 000011001101 */ }, { { 0x0003, 8 } /* 00000011 */ , { 0x0068,12 } /* 000001101000 */ }, { { 0x001a, 8 } /* 00011010 */ , { 0x0069,12 } /* 000001101001 */ }, { { 0x001b, 8 } /* 00011011 */ , { 0x006a,12 } /* 000001101010 */ }, { { 0x0012, 8 } /* 00010010 */ , { 0x006b,12 } /* 000001101011 */ }, { { 0x0013, 8 } /* 00010011 */ , { 0x00d2,12 } /* 000011010010 */ }, { { 0x0014, 8 } /* 00010100 */ , { 0x00d3,12 } /* 000011010011 */ }, { { 0x0015, 8 } /* 00010101 */ , { 0x00d4,12 } /* 000011010100 */ }, { { 0x0016, 8 } /* 00010110 */ , { 0x00d5,12 } /* 000011010101 */ }, { { 0x0017, 8 } /* 00010111 */ , { 0x00d6,12 } /* 000011010110 */ }, { { 0x0028, 8 } /* 00101000 */ , { 0x00d7,12 } /* 000011010111 */ }, { { 0x0029, 8 } /* 00101001 */ , { 0x006c,12 } /* 000001101100 */ }, { { 0x002a, 8 } /* 00101010 */ , { 0x006d,12 } /* 000001101101 */ }, { { 0x002b, 8 } /* 00101011 */ , { 0x00da,12 } /* 000011011010 */ }, { { 0x002c, 8 } /* 00101100 */ , { 0x00db,12 } /* 000011011011 */ }, { { 0x002d, 8 } /* 00101101 */ , { 0x0054,12 } /* 000001010100 */ }, { { 0x0004, 8 } /* 00000100 */ , { 0x0055,12 } /* 000001010101 */ }, { { 0x0005, 8 } /* 00000101 */ , { 0x0056,12 } /* 000001010110 */ }, { { 0x000a, 8 } /* 00001010 */ , { 0x0057,12 } /* 000001010111 */ }, { { 0x000b, 8 } /* 00001011 */ , { 0x0064,12 } /* 000001100100 */ }, { { 0x0052, 8 } /* 01010010 */ , { 0x0065,12 } /* 000001100101 */ }, { { 0x0053, 8 } /* 01010011 */ , { 0x0052,12 } /* 000001010010 */ }, { { 0x0054, 8 } /* 01010100 */ , { 0x0053,12 } /* 000001010011 */ }, { { 0x0055, 8 } /* 01010101 */ , { 0x0024,12 } /* 000000100100 */ }, { { 0x0024, 8 } /* 00100100 */ , { 0x0037,12 } /* 000000110111 */ }, { { 0x0025, 8 } /* 00100101 */ , { 0x0038,12 } /* 000000111000 */ }, { { 0x0058, 8 } /* 01011000 */ , { 0x0027,12 } /* 000000100111 */ }, { { 0x0059, 8 } /* 01011001 */ , { 0x0028,12 } /* 000000101000 */ }, { { 0x005a, 8 } /* 01011010 */ , { 0x0058,12 } /* 000001011000 */ }, { { 0x005b, 8 } /* 01011011 */ , { 0x0059,12 } /* 000001011001 */ }, { { 0x004a, 8 } /* 01001010 */ , { 0x002b,12 } /* 000000101011 */ }, { { 0x004b, 8 } /* 01001011 */ , { 0x002c,12 } /* 000000101100 */ }, { { 0x0032, 8 } /* 00110010 */ , { 0x005a,12 } /* 000001011010 */ }, { { 0x0033, 8 } /* 00110011 */ , { 0x0066,12 } /* 000001100110 */ }, { { 0x0034, 8 } /* 00110100 */ , { 0x0067,12 } /* 000001100111 */ } } ; static void writelength ( unsigned int *outbits, int *outbitsidx, int *col, int bit, int length ) { while ( length >= 64 ) { int m = length / 64 ; if ( m > 40 ) m = 40 ; writebits ( outbits, outbitsidx, col, makeup[m-1][bit].b, makeup[m-1][bit].l ) ; length -= 64*m ; } writebits ( outbits, outbitsidx, col, term[length][bit].b, term[length][bit].l ) ; } static void doPage(FILE * const ifP, unsigned int const pageNum, double const dpi) { int cols, rows, format; bit * bitrow; unsigned int row; unsigned int outbits ; int outbitsidx, col ; pbm_readpbminit(ifP, &cols, &rows, &format); bitrow = pbm_allocrow(cols); pm_message("[%u]\n", pageNum); printf ("%%%%Page: %u %u\n", pageNum, pageNum); printf ("%u %u 1 [ %f 0 0 %f 0 %u ]\n" "{ currentfile /ASCII85Decode filter\n" " << /Columns %u /Rows %u /EndOfBlock false >> " "/CCITTFaxDecode filter\n" " image } exec\n", cols, rows, dpi/72.0, -dpi/72.0, rows, cols, rows) ; outbitsidx = col = 0 ; for (row = 0 ; row < rows; ++row) { int lastbit, cnt ; unsigned int j; pbm_readpbmrow(ifP, bitrow, cols, format); lastbit = cnt = 0 ; for (j = 0; j < cols; ++j) { if (bitrow[j] != lastbit) { writelength(&outbits, &outbitsidx, &col, lastbit, cnt) ; lastbit = 1 ^ lastbit ; cnt = 0 ; } ++cnt; } writelength(&outbits, &outbitsidx, &col, lastbit, cnt); } flushbits(&outbits, &outbitsidx, &col) ; printf("~>\nshowpage\n") ; pbm_freerow(bitrow); } static void doPages(FILE * const ifP, unsigned int * const pagesP, double const dpi) { int eof; unsigned int pagesDone; eof = FALSE; pagesDone = 0; while (!eof) { doPage(ifP, pagesDone + 1, dpi); ++pagesDone; pbm_nextimage(ifP, &eof); } *pagesP = pagesDone; } int main(int argc, char * argv[]) { FILE *ifP; unsigned int pages; struct cmdline_info cmdline; pbm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); printf ("%%!PS-Adobe-3.0\n"); if (cmdline.title) printf("%%%%Title: %s\n", cmdline.title) ; printf ("%%%%Creator: pbmtopsg3, Copyright (C) 2001 Kristof Koehler\n" "%%%%Pages: (atend)\n" "%%%%EndComments\n") ; doPages(ifP, &pages, cmdline.dpi); printf ("%%%%Trailer\n" "%%%%Pages: %u\n" "%%%%EOF\n", pages); pm_close(ifP); pm_close(stdout); return 0; }