/* * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include "libport.h" #include "tif_config.h" #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_IO_H #include #endif #include "tiffio.h" #include "tiffiop.h" #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif float defxres = 204.; /* default x resolution (pixels/inch) */ float defyres = 98.; /* default y resolution (lines/inch) */ const float half = 0.5; const float points = 72.0; float pageWidth = 0; /* image page width (inches) */ float pageHeight = 0; /* image page length (inches) */ int scaleToPage = 0; /* if true, scale raster to page dimensions */ int totalPages = 0; /* total # pages printed */ int row; /* current output row */ int maxline = 512; /* max output line of PostScript */ /* * Turn a bit-mapped scanline into the appropriate sequence * of PostScript characters to be rendered. * * Original version written by Bret D. Whissel, * Florida State University Meteorology Department * March 13-15, 1995. */ static void printruns(unsigned char *buf, uint32_t *runs, uint32_t *erun, uint32_t lastx) { static struct { char white, black; unsigned short width; } WBarr[] = {{'d', 'n', 512}, {'e', 'o', 256}, {'f', 'p', 128}, {'g', 'q', 64}, {'h', 'r', 32}, {'i', 's', 16}, {'j', 't', 8}, {'k', 'u', 4}, {'l', 'v', 2}, {'m', 'w', 1}}; static char *svalue = " !\"#$&'*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abc"; int colormode = 1; /* 0 for white, 1 for black */ uint32_t runlength = 0; int n = maxline; uint32_t x = 0; int l; (void)buf; printf("%d m(", row++); while (runs < erun) { if (runlength <= 0) { colormode ^= 1; runlength = *runs++; if (x + runlength > lastx) runlength = runs[-1] = lastx - x; x += runlength; if (!colormode && runs == erun) break; /* don't bother printing the final white run */ } /* * If a runlength is greater than 6 pixels, then spit out * black or white characters until the runlength drops to * 6 or less. Once a runlength is <= 6, then combine black * and white runlengths until a 6-pixel pattern is obtained. * Then write out the special character. Six-pixel patterns * were selected since 64 patterns is the largest power of * two less than the 92 "easily printable" PostScript * characters (i.e., no escape codes or octal chars). */ l = 0; while (runlength > 6) { /* Run is greater than six... */ if (runlength >= WBarr[l].width) { if (n == 0) { putchar('\n'); n = maxline; } putchar(colormode ? WBarr[l].black : WBarr[l].white), n--; runlength -= WBarr[l].width; } else l++; } while (runlength > 0 && runlength <= 6) { uint32_t bitsleft = 6; int t = 0; while (bitsleft) { if (runlength <= bitsleft) { if (colormode) t |= ((1 << runlength) - 1) << (bitsleft - runlength); bitsleft -= runlength; runlength = 0; if (bitsleft) { if (runs >= erun) break; colormode ^= 1; runlength = *runs++; if (x + runlength > lastx) runlength = runs[-1] = lastx - x; x += runlength; } } else { /* runlength exceeds bits left */ if (colormode) t |= ((1 << bitsleft) - 1); runlength -= bitsleft; bitsleft = 0; } } if (n == 0) { putchar('\n'); n = maxline; } putchar(svalue[t]), n--; } } printf(")s\n"); } /* * Create a special PostScript font for printing FAX documents. By taking * advantage of the font-cacheing mechanism, a substantial speed-up in * rendering time is realized. */ static void emitFont(FILE *fd) { static const char *fontPrologue[] = { "/newfont 10 dict def newfont begin /FontType 3 def /FontMatrix [1", "0 0 1 0 0] def /FontBBox [0 0 512 1] def /Encoding 256 array def", "0 1 31{Encoding exch /255 put}for 120 1 255{Encoding exch /255", "put}for Encoding 37 /255 put Encoding 40 /255 put Encoding 41 /255", "put Encoding 92 /255 put /count 0 def /ls{Encoding exch count 3", "string cvs cvn put /count count 1 add def}def 32 1 36{ls}for", "38 1 39{ls}for 42 1 91{ls}for 93 1 99{ls}for /count 100", "def 100 1 119{ls}for /CharDict 5 dict def CharDict begin /white", "{dup 255 eq{pop}{1 dict begin 100 sub neg 512 exch bitshift", "/cw exch def cw 0 0 0 cw 1 setcachedevice end}ifelse}def /black", "{dup 255 eq{pop}{1 dict begin 110 sub neg 512 exch bitshift", "/cw exch def cw 0 0 0 cw 1 setcachedevice 0 0 moveto cw 0 rlineto", "0 1 rlineto cw neg 0 rlineto closepath fill end}ifelse}def /numbuild", "{dup 255 eq{pop}{6 0 0 0 6 1 setcachedevice 0 1 5{0 moveto", "dup 32 and 32 eq{1 0 rlineto 0 1 rlineto -1 0 rlineto closepath", "fill newpath}if 1 bitshift}for pop}ifelse}def /.notdef {}", "def /255 {}def end /BuildChar{exch begin dup 110 ge{Encoding", "exch get 3 string cvs cvi CharDict /black get}{dup 100 ge {Encoding", "exch get 3 string cvs cvi CharDict /white get}{Encoding exch get", "3 string cvs cvi CharDict /numbuild get}ifelse}ifelse exec end", "}def end /Bitfont newfont definefont 1 scalefont setfont", NULL}; int i; for (i = 0; fontPrologue[i] != NULL; i++) fprintf(fd, "%s\n", fontPrologue[i]); } void printTIF(TIFF *tif, uint16_t pageNumber) { uint32_t w, h; uint16_t unit, compression; float xres, yres, scale = 1.0; tstrip_t s, ns; time_t creation_time; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression) || compression < COMPRESSION_CCITTRLE || compression > COMPRESSION_CCITT_T6) return; if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) || !xres) { TIFFWarning(TIFFFileName(tif), "No x-resolution, assuming %g dpi", defxres); xres = defxres; } if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) || !yres) { TIFFWarning(TIFFFileName(tif), "No y-resolution, assuming %g lpi", defyres); yres = defyres; /* XXX */ } if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) && unit == RESUNIT_CENTIMETER) { xres *= 2.54F; yres *= 2.54F; } if (pageWidth == 0) pageWidth = w / xres; if (pageHeight == 0) pageHeight = h / yres; printf("%%!PS-Adobe-3.0\n"); printf("%%%%Creator: fax2ps\n"); #ifdef notdef printf("%%%%Title: %s\n", file); #endif creation_time = time(0); printf("%%%%CreationDate: %s", ctime(&creation_time)); printf("%%%%Origin: 0 0\n"); printf("%%%%BoundingBox: 0 0 %u %u\n", (int)(pageWidth * points), (int)(pageHeight * points)); /* XXX */ printf("%%%%Pages: (atend)\n"); printf("%%%%EndComments\n"); printf("%%%%BeginProlog\n"); emitFont(stdout); printf("/d{bind def}def\n"); /* bind and def proc */ printf("/m{0 exch moveto}d\n"); printf("/s{show}d\n"); printf("/p{showpage}d \n"); /* end page */ printf("%%%%EndProlog\n"); printf("%%%%Page: \"%u\" %u\n", pageNumber, pageNumber); printf("/$pageTop save def gsave\n"); if (scaleToPage) scale = pageHeight / (h / yres) < pageWidth / (w / xres) ? pageHeight / (h / yres) : pageWidth / (w / xres); printf("%g %g translate\n", points * (pageWidth - scale * w / xres) * half, points * (scale * h / yres + (pageHeight - scale * h / yres) * half)); printf("%g %g scale\n", points / xres * scale, -points / yres * scale); printf("0 setgray\n"); TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, printruns); ns = TIFFNumberOfStrips(tif); row = 0; for (s = 0; s < ns; s++) (void)TIFFReadEncodedStrip(tif, s, (tdata_t)NULL, (tsize_t)-1); printf("p\n"); printf("grestore $pageTop restore\n"); totalPages++; } #define GetPageNumber(tif) TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pn, &ptotal) int findPage(TIFF *tif, uint16_t pageNumber) { uint16_t pn = (uint16_t)-1; uint16_t ptotal = (uint16_t)-1; if (GetPageNumber(tif)) { while (pn != (pageNumber - 1) && TIFFReadDirectory(tif) && GetPageNumber(tif)) ; return (pn == (pageNumber - 1)); } else return (TIFFSetDirectory(tif, (tdir_t)(pageNumber - 1))); } void fax2ps(TIFF *tif, uint16_t npages, uint16_t *pages, char *filename) { if (npages > 0) { uint16_t pn, ptotal; int i; if (!GetPageNumber(tif)) fprintf(stderr, "%s: No page numbers, counting directories.\n", filename); for (i = 0; i < npages; i++) { if (findPage(tif, pages[i])) printTIF(tif, pages[i]); else fprintf(stderr, "%s: No page number %d\n", filename, pages[i]); } } else { uint16_t pageNumber = 0; do printTIF(tif, pageNumber++); while (TIFFReadDirectory(tif)); } } #undef GetPageNumber static int pcompar(const void *va, const void *vb) { const uint16_t *pa = (const uint16_t *)va; const uint16_t *pb = (const uint16_t *)vb; return ((int32_t)*pa - (int32_t)*pb); } static void usage(int code); int main(int argc, char **argv) { #if !HAVE_DECL_OPTARG extern int optind; extern char *optarg; #endif uint16_t *pages = NULL, npages = 0, pageNumber; int c, dowarnings = 0; /* if 1, enable library warnings */ TIFF *tif; while ((c = getopt(argc, argv, "l:p:x:y:W:H:wSh")) != -1) switch (c) { case 'H': /* page height */ pageHeight = (float)atof(optarg); break; case 'S': /* scale to page */ scaleToPage = 1; break; case 'W': /* page width */ pageWidth = (float)atof(optarg); break; case 'p': /* print specific page */ pageNumber = (uint16_t)atoi(optarg); if (pages) pages = (uint16_t *)realloc(pages, (npages + 1) * sizeof(uint16_t)); else pages = (uint16_t *)malloc(sizeof(uint16_t)); if (pages == NULL) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } pages[npages++] = pageNumber; break; case 'w': dowarnings = 1; break; case 'x': defxres = (float)atof(optarg); break; case 'y': defyres = (float)atof(optarg); break; case 'l': maxline = atoi(optarg); break; case 'h': usage(EXIT_SUCCESS); break; case '?': usage(EXIT_FAILURE); } if (npages > 0) qsort(pages, npages, sizeof(uint16_t), pcompar); if (!dowarnings) TIFFSetWarningHandler(0); if (optind < argc) { do { tif = TIFFOpen(argv[optind], "r"); if (tif) { fax2ps(tif, npages, pages, argv[optind]); TIFFClose(tif); } else fprintf(stderr, "%s: Can not open, or not a TIFF file.\n", argv[optind]); } while (++optind < argc); } else { int n; FILE *fd; char buf[16 * 1024]; fd = tmpfile(); if (fd == NULL) { fprintf(stderr, "Could not obtain temporary file.\n"); exit(EXIT_FAILURE); } #if defined(HAVE_SETMODE) && defined(O_BINARY) setmode(fileno(stdin), O_BINARY); #endif while ((n = read(fileno(stdin), buf, sizeof(buf))) > 0) { if (write(fileno(fd), buf, n) != n) { fclose(fd); fprintf(stderr, "Could not copy stdin to temporary file.\n"); exit(EXIT_FAILURE); } } _TIFF_lseek_f(fileno(fd), 0, SEEK_SET); #if defined(_WIN32) && defined(USE_WIN32_FILEIO) tif = TIFFFdOpen(_get_osfhandle(fileno(fd)), "temp", "r"); #else tif = TIFFFdOpen(fileno(fd), "temp", "r"); #endif if (tif) { fax2ps(tif, npages, pages, ""); TIFFClose(tif); } else fprintf(stderr, "Can not open, or not a TIFF file.\n"); fclose(fd); } printf("%%%%Trailer\n"); printf("%%%%Pages: %u\n", totalPages); printf("%%%%EOF\n"); return (EXIT_SUCCESS); } static const char usage_info[] = "Convert a TIFF facsimile to compressed PostScript\n\n" "usage: fax2ps [options] [input.tif ...]\n" "where options are:\n" " -w suppress warning messages\n" " -l chars set maximum output line length for generated PostScript\n" " -p page# select page to print (can use multiple times)\n" " -x xres set default horizontal resolution of input data (dpi)\n" " -y yres set default vertical resolution of input data (lpi)\n" " -S scale output to page size\n" " -W width set output page width (inches), default is 8.5\n" " -H height set output page height (inches), default is 11\n"; static void usage(int code) { FILE *out = (code == EXIT_SUCCESS) ? stdout : stderr; fprintf(out, "%s\n\n", TIFFGetVersion()); fprintf(out, "%s", usage_info); exit(code); }