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