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