New comit of SDL2
[supertux.git] / src / SDL2 / external / tiff-4.0.3 / tools / fax2ps.c
1 /* $Id: fax2ps.c,v 1.27 2011-04-02 19:30:20 bfriesen Exp $" */
2
3 /*
4  * Copyright (c) 1991-1997 Sam Leffler
5  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and 
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that (i) the above copyright notices and this permission notice appear in
10  * all copies of the software and related documentation, and (ii) the names of
11  * Sam Leffler and Silicon Graphics may not be used in any advertising or
12  * publicity relating to the software without the specific, prior written
13  * permission of Sam Leffler and Silicon Graphics.
14  * 
15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
18  * 
19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
24  * OF THIS SOFTWARE.
25  */
26 #include "tif_config.h"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 #include <time.h>
33
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37
38 #ifdef HAVE_FCNTL_H
39 # include <fcntl.h>
40 #endif
41
42 #ifdef HAVE_IO_H
43 # include <io.h>
44 #endif
45
46 #ifdef NEED_LIBPORT
47 # include "libport.h"
48 #endif
49
50 #include "tiffio.h"
51
52 float   defxres = 204.;         /* default x resolution (pixels/inch) */
53 float   defyres = 98.;          /* default y resolution (lines/inch) */
54 const float half = 0.5;
55 const float points = 72.0;
56 float   pageWidth = 0;          /* image page width (inches) */
57 float   pageHeight = 0;         /* image page length (inches) */
58 int     scaleToPage = 0;        /* if true, scale raster to page dimensions */
59 int     totalPages = 0;         /* total # pages printed */
60 int     row;                    /* current output row */
61 int     maxline = 512;          /* max output line of PostScript */
62
63 /*
64  * Turn a bit-mapped scanline into the appropriate sequence
65  * of PostScript characters to be rendered.
66  *  
67  * Original version written by Bret D. Whissel,
68  * Florida State University Meteorology Department
69  * March 13-15, 1995.
70  */
71 static void
72 printruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
73 {
74     static struct {
75         char white, black;
76         unsigned short width;
77     } WBarr[] = {
78         { 'd', 'n', 512 }, { 'e', 'o', 256 }, { 'f', 'p', 128 },
79         { 'g', 'q',  64 }, { 'h', 'r',  32 }, { 'i', 's',  16 },
80         { 'j', 't',   8 }, { 'k', 'u',   4 }, { 'l', 'v',   2 },
81         { 'm', 'w',   1 }
82     };
83     static char* svalue =
84         " !\"#$&'*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abc";
85     int colormode = 1;          /* 0 for white, 1 for black */
86     uint32 runlength = 0;
87     int n = maxline;
88     uint32 x = 0;
89     int l;
90
91     (void) buf;
92     printf("%d m(", row++);
93     while (runs < erun) {
94         if (runlength <= 0) {
95             colormode ^= 1;
96             runlength = *runs++;
97             if (x+runlength > lastx)
98                 runlength = runs[-1] = lastx-x;
99             x += runlength;
100             if (!colormode && runs == erun)     
101                 break;          /* don't bother printing the final white run */
102         }
103         /*
104          * If a runlength is greater than 6 pixels, then spit out
105          * black or white characters until the runlength drops to
106          * 6 or less.  Once a runlength is <= 6, then combine black
107          * and white runlengths until a 6-pixel pattern is obtained.
108          * Then write out the special character.  Six-pixel patterns
109          * were selected since 64 patterns is the largest power of
110          * two less than the 92 "easily printable" PostScript
111          * characters (i.e., no escape codes or octal chars).
112          */
113         l = 0;
114         while (runlength > 6) { /* Run is greater than six... */
115             if (runlength >= WBarr[l].width) {
116                 if (n == 0) {
117                     putchar('\n');
118                     n = maxline;
119                 }
120                 putchar(colormode ? WBarr[l].black : WBarr[l].white), n--;
121                 runlength -= WBarr[l].width;
122             } else
123                 l++;
124         }
125         while (runlength > 0 && runlength <= 6) {
126             uint32 bitsleft = 6;
127             int t = 0;
128             while (bitsleft) {
129                 if (runlength <= bitsleft) {
130                     if (colormode)
131                         t |= ((1 << runlength)-1) << (bitsleft-runlength);
132                     bitsleft -= runlength;
133                     runlength = 0;
134                     if (bitsleft) {
135                         if (runs >= erun)
136                             break;
137                         colormode ^= 1;
138                         runlength = *runs++;
139                         if (x+runlength > lastx)
140                             runlength = runs[-1] = lastx-x;
141                         x += runlength;
142                     }
143                 } else {                /* runlength exceeds bits left */
144                     if (colormode)
145                         t |= ((1 << bitsleft)-1);
146                     runlength -= bitsleft;
147                     bitsleft = 0;
148                 }
149             }
150             if (n == 0) {
151                 putchar('\n');
152                 n = maxline;
153             }
154             putchar(svalue[t]), n--;
155         }
156     }
157     printf(")s\n");
158 }
159
160 /* 
161  * Create a special PostScript font for printing FAX documents.  By taking
162  * advantage of the font-cacheing mechanism, a substantial speed-up in 
163  * rendering time is realized. 
164  */
165 static void
166 emitFont(FILE* fd)
167 {
168     static const char* fontPrologue[] = {
169         "/newfont 10 dict def newfont begin /FontType 3 def /FontMatrix [1",
170         "0 0 1 0 0] def /FontBBox [0 0 512 1] def /Encoding 256 array def",
171         "0 1 31{Encoding exch /255 put}for 120 1 255{Encoding exch /255",
172         "put}for Encoding 37 /255 put Encoding 40 /255 put Encoding 41 /255",
173         "put Encoding 92 /255 put /count 0 def /ls{Encoding exch count 3",
174         "string cvs cvn put /count count 1 add def}def 32 1 36{ls}for",
175         "38 1 39{ls}for 42 1 91{ls}for 93 1 99{ls}for /count 100",
176         "def 100 1 119{ls}for /CharDict 5 dict def CharDict begin /white",
177         "{dup 255 eq{pop}{1 dict begin 100 sub neg 512 exch bitshift",
178         "/cw exch def cw 0 0 0 cw 1 setcachedevice end}ifelse}def /black",
179         "{dup 255 eq{pop}{1 dict begin 110 sub neg 512 exch bitshift",
180         "/cw exch def cw 0 0 0 cw 1 setcachedevice 0 0 moveto cw 0 rlineto",
181         "0 1 rlineto cw neg 0 rlineto closepath fill end}ifelse}def /numbuild",
182         "{dup 255 eq{pop}{6 0 0 0 6 1 setcachedevice 0 1 5{0 moveto",
183         "dup 32 and 32 eq{1 0 rlineto 0 1 rlineto -1 0 rlineto closepath",
184         "fill newpath}if 1 bitshift}for pop}ifelse}def /.notdef {}",
185         "def /255 {}def end /BuildChar{exch begin dup 110 ge{Encoding",
186         "exch get 3 string cvs cvi CharDict /black get}{dup 100 ge {Encoding",
187         "exch get 3 string cvs cvi CharDict /white get}{Encoding exch get",
188         "3 string cvs cvi CharDict /numbuild get}ifelse}ifelse exec end",
189         "}def end /Bitfont newfont definefont 1 scalefont setfont",
190         NULL
191     };
192     int i;
193     for (i = 0; fontPrologue[i] != NULL; i++)
194         fprintf(fd, "%s\n", fontPrologue[i]);
195 }
196
197 void
198 printTIF(TIFF* tif, uint16 pageNumber)
199 {
200     uint32 w, h;
201     uint16 unit, compression;
202     float xres, yres, scale = 1.0;
203     tstrip_t s, ns;
204     time_t creation_time;
205
206     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
207     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
208     if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression)
209         || compression < COMPRESSION_CCITTRLE
210         || compression > COMPRESSION_CCITT_T6)
211         return;
212     if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) || !xres) {
213         TIFFWarning(TIFFFileName(tif),
214             "No x-resolution, assuming %g dpi", defxres);
215         xres = defxres;
216     }
217     if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) || !yres) {
218         TIFFWarning(TIFFFileName(tif),
219             "No y-resolution, assuming %g lpi", defyres);
220         yres = defyres;                                 /* XXX */
221     }
222     if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) &&
223       unit == RESUNIT_CENTIMETER) {
224         xres *= 2.54F;
225         yres *= 2.54F;
226     }
227     if (pageWidth == 0)
228         pageWidth = w / xres;
229     if (pageHeight == 0)
230         pageHeight = h / yres;
231
232     printf("%%!PS-Adobe-3.0\n");
233     printf("%%%%Creator: fax2ps\n");
234 #ifdef notdef
235     printf("%%%%Title: %s\n", file);
236 #endif
237     creation_time = time(0);
238     printf("%%%%CreationDate: %s", ctime(&creation_time));
239     printf("%%%%Origin: 0 0\n");
240     printf("%%%%BoundingBox: 0 0 %u %u\n",
241         (int)(pageWidth * points), (int)(pageHeight * points)); /* XXX */
242     printf("%%%%Pages: (atend)\n");
243     printf("%%%%EndComments\n");
244     printf("%%%%BeginProlog\n");
245     emitFont(stdout);
246     printf("/d{bind def}def\n"); /* bind and def proc */
247     printf("/m{0 exch moveto}d\n");
248     printf("/s{show}d\n");
249     printf("/p{showpage}d \n"); /* end page */
250     printf("%%%%EndProlog\n");
251     printf("%%%%Page: \"%u\" %u\n", pageNumber, pageNumber);
252     printf("/$pageTop save def gsave\n");
253     if (scaleToPage)
254         scale = pageHeight / (h/yres) < pageWidth / (w/xres) ?
255             pageHeight / (h/yres) : pageWidth / (w/xres);
256     printf("%g %g translate\n",
257            points * (pageWidth - scale*w/xres) * half,
258            points * (scale*h/yres + (pageHeight - scale*h/yres) * half));
259     printf("%g %g scale\n", points/xres*scale, -points/yres*scale);
260     printf("0 setgray\n");
261     TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, printruns);
262     ns = TIFFNumberOfStrips(tif);
263     row = 0;
264     for (s = 0; s < ns; s++)
265         (void) TIFFReadEncodedStrip(tif, s, (tdata_t) NULL, (tsize_t) -1);
266     printf("p\n");
267     printf("grestore $pageTop restore\n");
268     totalPages++;
269 }
270
271 #define GetPageNumber(tif) \
272 TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pn, &ptotal)
273
274 int
275 findPage(TIFF* tif, uint16 pageNumber)
276 {
277     uint16 pn = (uint16) -1;
278     uint16 ptotal = (uint16) -1;
279     if (GetPageNumber(tif)) {
280         while (pn != (pageNumber-1) && TIFFReadDirectory(tif) && GetPageNumber(tif))
281             ;
282         return (pn == (pageNumber-1));
283     } else
284         return (TIFFSetDirectory(tif, (tdir_t)(pageNumber-1)));
285 }
286
287 void
288 fax2ps(TIFF* tif, uint16 npages, uint16* pages, char* filename)
289 {
290     if (npages > 0) {
291         uint16 pn, ptotal;
292         int i;
293
294         if (!GetPageNumber(tif))
295             fprintf(stderr, "%s: No page numbers, counting directories.\n",
296                 filename);
297         for (i = 0; i < npages; i++) {
298             if (findPage(tif, pages[i]))
299                 printTIF(tif, pages[i]);
300             else
301                 fprintf(stderr, "%s: No page number %d\n", filename, pages[i]);
302         }
303     } else {
304         uint16 pageNumber = 0;
305         do
306             printTIF(tif, pageNumber++);
307         while (TIFFReadDirectory(tif));
308     }
309 }
310
311 #undef GetPageNumber
312
313 static int
314 pcompar(const void* va, const void* vb)
315 {
316     const int* pa = (const int*) va;
317     const int* pb = (const int*) vb;
318     return (*pa - *pb);
319 }
320
321 static  void usage(int code);
322
323 int
324 main(int argc, char** argv)
325 {
326     extern int optind;
327     extern char* optarg;
328     uint16 *pages = NULL, npages = 0, pageNumber;
329     int c, dowarnings = 0;              /* if 1, enable library warnings */
330     TIFF* tif;
331
332     while ((c = getopt(argc, argv, "l:p:x:y:W:H:wS")) != -1)
333         switch (c) {
334         case 'H':               /* page height */
335             pageHeight = (float)atof(optarg);
336             break;
337         case 'S':               /* scale to page */
338             scaleToPage = 1;
339             break;
340         case 'W':               /* page width */
341             pageWidth = (float)atof(optarg);
342             break;
343         case 'p':               /* print specific page */
344             pageNumber = (uint16)atoi(optarg);
345             if (pages)
346                 pages = (uint16*) realloc(pages, (npages+1)*sizeof(uint16));
347             else
348                 pages = (uint16*) malloc(sizeof(uint16));
349             pages[npages++] = pageNumber;
350             break;
351         case 'w':
352             dowarnings = 1;
353             break;
354         case 'x':
355             defxres = (float)atof(optarg);
356             break;
357         case 'y':
358             defyres = (float)atof(optarg);
359             break;
360         case 'l':
361             maxline = atoi(optarg);
362             break;
363         case '?':
364             usage(-1);
365         }
366     if (npages > 0)
367         qsort(pages, npages, sizeof(uint16), pcompar);
368     if (!dowarnings)
369         TIFFSetWarningHandler(0);
370     if (optind < argc) {
371         do {
372             tif = TIFFOpen(argv[optind], "r");
373             if (tif) {
374                 fax2ps(tif, npages, pages, argv[optind]);
375                 TIFFClose(tif);
376             } else
377                 fprintf(stderr, "%s: Can not open, or not a TIFF file.\n",
378                     argv[optind]);
379         } while (++optind < argc);
380     } else {
381         int n;
382         FILE* fd;
383         char buf[16*1024];
384
385         fd = tmpfile();
386         if (fd == NULL) {
387             fprintf(stderr, "Could not obtain temporary file.\n");
388             exit(-2);
389         }
390 #if defined(HAVE_SETMODE) && defined(O_BINARY)
391         setmode(fileno(stdin), O_BINARY);
392 #endif
393         while ((n = read(fileno(stdin), buf, sizeof (buf))) > 0)
394             write(fileno(fd), buf, n);
395         lseek(fileno(fd), 0, SEEK_SET);
396 #if defined(_WIN32) && defined(USE_WIN32_FILEIO)
397         tif = TIFFFdOpen(_get_osfhandle(fileno(fd)), "temp", "r");
398 #else
399         tif = TIFFFdOpen(fileno(fd), "temp", "r");
400 #endif
401         if (tif) {
402             fax2ps(tif, npages, pages, "<stdin>");
403             TIFFClose(tif);
404         } else
405             fprintf(stderr, "Can not open, or not a TIFF file.\n");
406         fclose(fd);
407     }
408     printf("%%%%Trailer\n");
409     printf("%%%%Pages: %u\n", totalPages);
410     printf("%%%%EOF\n");
411
412     return (0);
413 }
414
415 char* stuff[] = {
416 "usage: fax2ps [options] [input.tif ...]",
417 "where options are:",
418 " -w            suppress warning messages",
419 " -l chars      set maximum output line length for generated PostScript",
420 " -p page#      select page to print (can use multiple times)",
421 " -x xres       set default horizontal resolution of input data (dpi)",
422 " -y yres       set default vertical resolution of input data (lpi)",
423 " -S            scale output to page size",
424 " -W width      set output page width (inches), default is 8.5",
425 " -H height     set output page height (inches), default is 11",
426 NULL
427 };
428
429 static void
430 usage(int code)
431 {
432         char buf[BUFSIZ];
433         int i;
434
435         setbuf(stderr, buf);
436         fprintf(stderr, "%s\n\n", TIFFGetVersion());
437         for (i = 0; stuff[i] != NULL; i++)
438                 fprintf(stderr, "%s\n", stuff[i]);
439         exit(code);
440 }
441
442 /* vim: set ts=8 sts=8 sw=8 noet: */
443 /*
444  * Local Variables:
445  * mode: c
446  * c-basic-offset: 8
447  * fill-column: 78
448  * End:
449  */