~ubuntu-branches/ubuntu/quantal/tiff/quantal

« back to all changes in this revision

Viewing changes to tools/fax2ps.c

  • Committer: Bazaar Package Importer
  • Author(s): Jay Berkenbilt
  • Date: 2009-08-28 15:44:23 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20090828154423-7oisj77n302jrroa
Tags: 3.9.1-1
New upstream release

Show diffs side-by-side

added added

removed removed

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