1 /* pnmtops.c - read a PNM image and produce a PostScript program.
2 
3    Copyright information is at end of file.
4 
5    We produce two main kinds of Postscript program:
6 
7       1) Use built in Postscript filters /ASCII85Decode, /ASCIIHexDecode,
8          /RunLengthDecode, and /FlateDecode;
9 
10          We use methods we learned from Dirk Krause's program Bmeps.
11          Previous versions used raster encoding code based on Bmeps
12          code.  This program does not used any code from Bmeps.
13 
14       2) Use our own filters and redefine /readstring .  This is aboriginal
15          Netpbm code, from when Postscript was young.  The filters are
16          nearly identical to /ASCIIHexDecode and /RunLengthDecode.  We
17          use the same raster encoding code with slight modifications.
18 
19    (2) is the default.  (1) gives more options, but relies on features
20    introduced in Postscript Level 2, which appeared in 1991.  Postcript
21    devices made before 1991 can't handle them.  The user selects (1)
22    with the -psfilter option.
23 
24    We also do a few other bold new things only when the user specifies
25    -psfilter, because we're not sure they work for everyone.
26 
27    (I actually don't know Postscript, so some of this description, not to
28    mention the code, may be totally bogus.)
29 
30    NOTE: it is possible to put transparency information in an
31    encapsulated Postscript program.  Bmeps does this.  We don't.  It
32    might be hard to do, because in Postscript, the transparency information
33    goes in separate from the rest of the raster.
34 */
35 
36 #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
37 #define _BSD_SOURCE  /* Make sure string.h contains strdup() */
38 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44 #include <assert.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <signal.h>
48 #ifndef NOFLATE
49 #include <zlib.h>
50 #endif
51 
52 #include "pm_c_util.h"
53 #include "pam.h"
54 #include "mallocvar.h"
55 #include "shhopt.h"
56 #include "nstring.h"
57 #include "runlength.h"
58 
59 
60 
61 static void
setSignals()62 setSignals() {
63 /*----------------------------------------------------------------------------
64    Set up the process-global signal-related state.
65 
66    Note that we can't rely on defaults, because much of this is inherited
67    from the process that forked and exec'ed this program.
68 -----------------------------------------------------------------------------*/
69     /* See waitForChildren() for why we do this to SIGCHLD */
70 
71     struct sigaction sigchldAction;
72     int rc;
73     sigset_t emptySet;
74 
75     sigemptyset(&emptySet);
76 
77     sigchldAction.sa_handler = SIG_DFL;
78     sigchldAction.sa_mask = emptySet;
79     sigchldAction.sa_flags = SA_NOCLDSTOP;
80 
81     rc = sigaction(SIGCHLD, &sigchldAction, NULL);
82 
83     if (rc != 0)
84         pm_error("sigaction() to set up signal environment failed, "
85                  "errno = %d (%s)", errno, strerror(errno));
86 }
87 
88 
89 
90 struct CmdlineInfo {
91     /* All the information the user supplied in the command line,
92        in a form easy for the program to use.
93     */
94     const char * inputFileName;  /* Filespecs of input file */
95     float        scale;
96     unsigned int dpiX;     /* horiz component of DPI option */
97     unsigned int dpiY;     /* vert component of DPI option */
98     unsigned int width;              /* in 1/72 inch */
99     unsigned int height;             /* in 1/72 inch */
100     unsigned int mustturn;
101     bool         canturn;
102     unsigned int rle;
103     bool         center;
104     unsigned int imagewidth;         /* in 1/72 inch; zero if unspec */
105     unsigned int imageheight;        /* in 1/72 inch; zero if unspec */
106     unsigned int equalpixels;
107     unsigned int bitspersampleSpec;
108     unsigned int bitspersample;
109     unsigned int setpage;
110     bool         showpage;
111     unsigned int level;
112     unsigned int levelSpec;
113     unsigned int psfilter;
114     unsigned int flate;
115     unsigned int ascii85;
116     unsigned int dict;
117     unsigned int vmreclaim;
118     unsigned int verbose;
119     unsigned int debug;
120 };
121 
122 static bool debug;
123 static bool verbose;
124 
125 
126 
127 static void
parseDpi(const char * const dpiOpt,unsigned int * const dpiXP,unsigned int * const dpiYP)128 parseDpi(const char *   const dpiOpt,
129          unsigned int * const dpiXP,
130          unsigned int * const dpiYP) {
131 
132     char *dpistr2;
133     unsigned long int dpiX, dpiY;
134 
135     dpiX = strtol(dpiOpt, &dpistr2, 10);
136     if (dpistr2 == dpiOpt)
137         pm_error("Invalid value for -dpi: '%s'.  Must be either number "
138                  "or NxN ", dpiOpt);
139     else if (dpiX > INT_MAX)
140         pm_error("Invalid value for -dpi: '%s'.  "
141                  "Value too large for computation", dpiOpt);
142     else {
143         if (*dpistr2 == '\0') {
144             *dpiXP = dpiX;
145             *dpiYP = dpiX;
146         } else if (*dpistr2 == 'x') {
147             char * dpistr3;
148 
149             dpistr2++;  /* Move past 'x' */
150             dpiY = strtol(dpistr2, &dpistr3, 10);
151             if (dpiY > INT_MAX)
152                 pm_error("Invalid value for -dpi: '%s'.  "
153                          "Value too large for computation", dpiOpt);
154             else if (dpistr3 != dpistr2 && *dpistr3 == '\0') {
155                 *dpiXP = dpiX;
156                 *dpiYP = dpiY;
157             } else {
158                 pm_error("Invalid value for -dpi: '%s'.  Must be either "
159                          "number or NxN", dpiOpt);
160             }
161         }
162     }
163 }
164 
165 
166 
167 static void
validateBps_1_2_4_8_12(unsigned int const bitsPerSample)168 validateBps_1_2_4_8_12(unsigned int const bitsPerSample) {
169 
170     switch (bitsPerSample) {
171     case 1:
172     case 2:
173     case 4:
174     case 8:
175     case 12:
176         break;
177     default:
178         pm_error("Invalid -bitspersample value: %u.  Must be "
179                  "1, 2, 4, 8, or 12", bitsPerSample);
180     }
181 }
182 
183 
184 
185 static void
validateCompDimension(unsigned int const value,unsigned int const scaleFactor,const char * const vname)186 validateCompDimension(unsigned int const value,
187                       unsigned int const scaleFactor,
188                       const char * const vname) {
189 /*----------------------------------------------------------------------------
190   Validate that the image dimension (width or height) 'value' isn't so big
191   that in this program's calculations, involving scale factor 'scaleFactor',
192   it would cause a register overflow.  If it is, abort the program and refer
193   to the offending dimension as 'vname' in the error message.
194 
195   Note that this early validation approach (calling this function) means
196   the actual computations don't have to be complicated with arithmetic
197   overflow checks, so they're easier to read.
198 -----------------------------------------------------------------------------*/
199     if (value > 0) {
200         unsigned int const maxWidthHeight = INT_MAX - 2;
201         unsigned int const maxScaleFactor = maxWidthHeight / value;
202 
203         if (scaleFactor > maxScaleFactor)
204             pm_error("%s is too large for compuations: %u", vname, value);
205     }
206 }
207 
208 
209 
210 static void
parseCommandLine(int argc,const char ** argv,struct CmdlineInfo * const cmdlineP)211 parseCommandLine(int argc, const char ** argv,
212                  struct CmdlineInfo * const cmdlineP) {
213 
214     unsigned int imagewidthSpec, imageheightSpec;
215     float imagewidth, imageheight;
216     unsigned int center, nocenter;
217     unsigned int nosetpage;
218     float width, height;
219     unsigned int noturn;
220     unsigned int showpage, noshowpage;
221     const char * dpiOpt;
222     unsigned int dpiSpec, scaleSpec, widthSpec, heightSpec;
223 
224     optStruct3 opt;
225     unsigned int option_def_index = 0;
226     optEntry * option_def;
227 
228     MALLOCARRAY_NOFAIL(option_def, 100);
229 
230     OPTENT3(0, "scale",       OPT_FLOAT, &cmdlineP->scale, &scaleSpec,   0);
231     OPTENT3(0, "dpi",         OPT_STRING, &dpiOpt,         &dpiSpec,     0);
232     OPTENT3(0, "width",       OPT_FLOAT, &width,           &widthSpec,   0);
233     OPTENT3(0, "height",      OPT_FLOAT, &height,          &heightSpec,  0);
234     OPTENT3(0, "psfilter",    OPT_FLAG,  NULL, &cmdlineP->psfilter,      0);
235     OPTENT3(0, "turn",        OPT_FLAG,  NULL, &cmdlineP->mustturn,      0);
236     OPTENT3(0, "noturn",      OPT_FLAG,  NULL, &noturn,                  0);
237     OPTENT3(0, "rle",         OPT_FLAG,  NULL, &cmdlineP->rle,           0);
238     OPTENT3(0, "runlength",   OPT_FLAG,  NULL, &cmdlineP->rle,           0);
239     OPTENT3(0, "ascii85",     OPT_FLAG,  NULL, &cmdlineP->ascii85,       0);
240     OPTENT3(0, "center",      OPT_FLAG,  NULL, &center,                  0);
241     OPTENT3(0, "nocenter",    OPT_FLAG,  NULL, &nocenter,                0);
242     OPTENT3(0, "equalpixels", OPT_FLAG,  NULL, &cmdlineP->equalpixels,   0);
243     OPTENT3(0, "imagewidth",  OPT_FLOAT, &imagewidth,  &imagewidthSpec,  0);
244     OPTENT3(0, "imageheight", OPT_FLOAT, &imageheight, &imageheightSpec, 0);
245     OPTENT3(0, "bitspersample", OPT_UINT, &cmdlineP->bitspersample,
246             &cmdlineP->bitspersampleSpec, 0);
247     OPTENT3(0, "nosetpage",   OPT_FLAG,  NULL, &nosetpage,               0);
248     OPTENT3(0, "setpage",     OPT_FLAG,  NULL, &cmdlineP->setpage,       0);
249     OPTENT3(0, "noshowpage",  OPT_FLAG,  NULL, &noshowpage,              0);
250     OPTENT3(0, "flate",       OPT_FLAG,  NULL, &cmdlineP->flate,         0);
251     OPTENT3(0, "dict",        OPT_FLAG,  NULL, &cmdlineP->dict,          0);
252     OPTENT3(0, "vmreclaim",   OPT_FLAG,  NULL, &cmdlineP->vmreclaim,     0);
253     OPTENT3(0, "showpage",    OPT_FLAG,  NULL, &showpage,                0);
254     OPTENT3(0, "verbose",     OPT_FLAG,  NULL, &cmdlineP->verbose,       0);
255     OPTENT3(0, "debug",       OPT_FLAG,  NULL, &cmdlineP->debug,         0);
256     OPTENT3(0, "level",       OPT_UINT, &cmdlineP->level,
257             &cmdlineP->levelSpec,              0);
258 
259     opt.opt_table = option_def;
260     opt.short_allowed = FALSE;
261     opt.allowNegNum = FALSE;
262 
263     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
264 
265     if (cmdlineP->mustturn && noturn)
266         pm_error("You cannot specify both -turn and -noturn");
267     if (center && nocenter)
268         pm_error("You cannot specify both -center and -nocenter");
269     if (showpage && noshowpage)
270         pm_error("You cannot specify both -showpage and -noshowpage");
271     if (cmdlineP->setpage && nosetpage)
272         pm_error("You cannot specify both -setpage and -nosetpage");
273 
274     if (!scaleSpec)
275         cmdlineP->scale = 1.0;
276 
277     if (!widthSpec)
278         width = 8.5;
279 
280     if (!heightSpec)
281         height = 11.0;
282 
283     if (dpiSpec)
284         parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
285     else {
286         cmdlineP->dpiX = 300;
287         cmdlineP->dpiY = 300;
288     }
289 
290     cmdlineP->center  =  !nocenter;
291     cmdlineP->canturn =  !noturn;
292     cmdlineP->showpage = !noshowpage;
293 
294     validateCompDimension(width, 72, "-width value");
295     validateCompDimension(height, 72, "-height value");
296 
297     cmdlineP->width  = width * 72;
298     cmdlineP->height = height * 72;
299 
300     if (imagewidthSpec) {
301         validateCompDimension(imagewidth, 72, "-imagewidth value");
302         cmdlineP->imagewidth = imagewidth * 72;
303     }
304     else
305         cmdlineP->imagewidth = 0;
306     if (imageheightSpec) {
307         validateCompDimension(imagewidth, 72, "-imageheight value");
308         cmdlineP->imageheight = imageheight * 72;
309     }
310     else
311         cmdlineP->imageheight = 0;
312 
313     if (!cmdlineP->psfilter &&
314         (cmdlineP->flate || cmdlineP->ascii85))
315         pm_error("You must specify -psfilter in order to specify "
316                  "-flate or -ascii85");
317 
318     if (cmdlineP->bitspersampleSpec)
319         validateBps_1_2_4_8_12(cmdlineP->bitspersample);
320 
321     if (argc-1 == 0)
322         cmdlineP->inputFileName = "-";
323     else if (argc-1 != 1)
324         pm_error("Program takes zero or one argument (filename).  You "
325                  "specified %d", argc-1);
326     else
327         cmdlineP->inputFileName = argv[1];
328 
329     free(option_def);
330 }
331 
332 
333 
334 static bool
progIsFlateCapable(void)335 progIsFlateCapable(void) {
336 
337     return
338 #ifdef NOFLATE
339         false
340 #else
341         true
342 #endif
343         ;
344 }
345 
346 
347 
348 static const char *
basebasename(const char * const filespec)349 basebasename(const char * const filespec) {
350 /*----------------------------------------------------------------------------
351   Return filename up to first period
352 -----------------------------------------------------------------------------*/
353     char const dirsep = '/';
354     const char * const lastSlashPos = strrchr(filespec, dirsep);
355 
356     char * name;
357     const char * filename;
358 
359     if (lastSlashPos)
360         filename = lastSlashPos + 1;
361     else
362         filename = filespec;
363 
364     name = strdup(filename);
365     if (name != NULL) {
366         char * const dotPosition = strchr(name, '.');
367 
368         if (dotPosition)
369             *dotPosition = '\0';
370     }
371     return name;
372 }
373 
374 
375 
376 static void
writeFile(const unsigned char * const buffer,size_t const writeCt,const char * const name,FILE * const ofP)377 writeFile(const unsigned char * const buffer,
378           size_t                const writeCt,
379           const char *          const name,
380           FILE *                const ofP) {
381 
382     size_t writtenCt;
383 
384     writtenCt = fwrite(buffer, 1, writeCt, ofP);
385 
386     if (writtenCt != writeCt)
387         pm_error("Error writing to %s output file", name);
388 }
389 
390 
391 
392 static void
writeFileChar(const char * const buffer,size_t const writeCt,const char * const name,FILE * const ofP)393 writeFileChar(const char * const buffer,
394               size_t       const writeCt,
395               const char * const name,
396               FILE *       const ofP) {
397 
398     writeFile((const unsigned char *)buffer, writeCt, name, ofP);
399 }
400 
401 
402 
403 #define MAX_FILTER_CT 10
404     /* The maximum number of filters this code is capable of applying */
405 
406 
407 
408 static void
initPidList(pid_t * const pidList)409 initPidList(pid_t * const pidList) {
410 
411     pidList[0] = (pid_t)0;  /* end of list marker */
412 }
413 
414 
415 
416 static void
addToPidList(pid_t * const pidList,pid_t const newPid)417 addToPidList(pid_t * const pidList,
418              pid_t   const newPid) {
419 
420     unsigned int i;
421 
422     for (i = 0; i < MAX_FILTER_CT && pidList[i]; ++i);
423 
424     assert(i < MAX_FILTER_CT);
425 
426     pidList[i] = newPid;
427     pidList[i+1] = (pid_t)0;  /* end of list marker */
428 }
429 
430 
431 
432 /*===========================================================================
433   The output encoder
434   ===========================================================================*/
435 
436 enum OutputType {AsciiHex, Ascii85};
437 
438 typedef struct {
439     enum OutputType    outputType;
440     bool               compressRle;
441     bool               compressFlate;
442     unsigned int       runlengthRefresh;
443 } OutputEncoder;
444 
445 
446 
447 static unsigned int
bytesPerRow(unsigned int const cols,unsigned int const bitsPerSample)448 bytesPerRow (unsigned int const cols,
449              unsigned int const bitsPerSample) {
450 /*----------------------------------------------------------------------------
451   Size of row buffer, padded up to byte boundary, given that the image
452   has 'cols' samples per row, 'bitsPerSample' bits per sample.
453 -----------------------------------------------------------------------------*/
454     unsigned int retval;
455 
456     assert(bitsPerSample==1 || bitsPerSample==2 || bitsPerSample==4 ||
457            bitsPerSample==8 || bitsPerSample==12);
458 
459     switch (bitsPerSample) {
460     case 1:
461     case 2:
462     case 4:
463         retval = cols / (8/bitsPerSample)
464             + (cols % (8/bitsPerSample) > 0 ? 1 : 0);
465         /* A more straightforward calculation would be
466            (cols * bitsPerSample + 7) / 8 ,
467            but this overflows when icols is large.
468         */
469         break;
470     case 8:
471         retval = cols;
472         break;
473     case 12:
474         retval = cols + (cols+1)/2;
475         break;
476     }
477 
478     return retval;
479 }
480 
481 
482 
483 static void
initOutputEncoder(OutputEncoder * const oeP,unsigned int const icols,unsigned int const bitsPerSample,bool const rle,bool const flate,bool const ascii85,bool const psFilter)484 initOutputEncoder(OutputEncoder  * const oeP,
485                   unsigned int     const icols,
486                   unsigned int     const bitsPerSample,
487                   bool             const rle,
488                   bool             const flate,
489                   bool             const ascii85,
490                   bool             const psFilter) {
491 
492     oeP->outputType = ascii85 ? Ascii85 : AsciiHex;
493 
494     if (rle) {
495         oeP->compressRle = true;
496         oeP->runlengthRefresh =
497              psFilter ? 1024*1024*16 : bytesPerRow(icols, bitsPerSample);
498     } else
499         oeP->compressRle = false;
500 
501     if (flate) {
502         assert(psFilter);
503         oeP->compressFlate = true;
504     } else
505         oeP->compressFlate = false;
506 
507     if (ascii85) {
508         assert(psFilter);
509         oeP->outputType = Ascii85;
510     } else
511         oeP->outputType = AsciiHex;
512 }
513 
514 
515 
516 typedef void FilterFn(FILE *          const ifP,
517                       FILE *          const ofP,
518                       OutputEncoder * const oeP);
519     /* This is a function that can be run in a separate process to do
520        arbitrary modifications of the raster data stream.
521     */
522 
523 
524 
525 #ifndef NOFLATE
526 static void
initZlib(z_stream * const strmP)527 initZlib(z_stream * const strmP) {
528 
529     int const level = 9; /* maximum compression.  see zlib.h */
530 
531     int ret;
532 
533     /* allocate deflate state */
534     strmP->zalloc = Z_NULL;
535     strmP->zfree  = Z_NULL;
536     strmP->opaque = Z_NULL;
537 
538     ret = deflateInit(strmP, level);
539     if (ret != Z_OK)
540         pm_error("Failed to initialize zlib.");
541 }
542 #endif
543 
544 
545 
546 static FilterFn flateFilter;
547 
548 static void
flateFilter(FILE * const ifP,FILE * const ofP,OutputEncoder * const oeP)549 flateFilter(FILE *          const ifP,
550             FILE *          const ofP,
551             OutputEncoder * const oeP) {
552 
553 #ifndef NOFLATE
554 
555     /* This code is based on def() in zpipe.c.  zpipe is an example program
556        which comes with the zlib source package.  zpipe.c is public domain and
557        is available from the Zlib website: http://www.zlib.net/
558 
559        See zlib.h for details on zlib parameters Z_NULL, Z_OK, etc.
560     */
561     unsigned int const chunkSz = 128*1024;
562         /* 128K recommended in zpipe.c.  4096 is not efficient but works. */
563 
564     int flush;
565     z_stream strm;
566     unsigned char * in;
567     unsigned char * out;
568 
569     in  = pm_allocrow(chunkSz, 1);
570     out = pm_allocrow(chunkSz, 1);
571 
572     initZlib(&strm);
573 
574     /* compress until end of file */
575     do {
576         strm.avail_in = fread(in, 1, chunkSz, ifP);
577         if (ferror(ifP)) {
578             deflateEnd(&strm);
579             pm_error("Error reading from internal pipe during "
580                      "flate compression.");
581         }
582         flush = feof(ifP) ? Z_FINISH : Z_NO_FLUSH;
583         strm.next_in = in;
584 
585         /* run deflate() on input until output buffer not full, finish
586            compression if we have reached end of input.
587         */
588         do {
589             unsigned int have;
590 
591             strm.avail_out = chunkSz;
592             strm.next_out = out;
593             deflate(&strm, flush);
594             have = chunkSz - strm.avail_out;
595             writeFile(out, have, "flate filter", ofP);
596         } while (strm.avail_out == 0);
597         assert(strm.avail_in == 0);     /* all input is used */
598 
599         /* done when last data in file processed */
600     } while (flush != Z_FINISH);
601 
602     free(in);
603     free(out);
604     deflateEnd(&strm);
605     fclose(ifP);
606     fclose(ofP);
607 #else
608     assert(false);    /* filter is never used */
609 #endif
610 }
611 
612 
613 
614 /* Run length encoding
615 
616    In this simple run-length encoding scheme, compressed and uncompressed
617    strings follow a single index byte N.  N 0-127 means the next N+1
618    bytes are uncompressed; 129-255 means the next byte is to be repeated
619    257-N times.
620 
621    In native (non-psfilter) mode, the run length filter must flush at
622    the end of every row.  But the entire raster is sent to the run length
623    filter as one continuous stream.  The run length filter learns the
624    refresh interval from oeP->runlengthRefresh.  In ps-filter mode the
625    run length filter ignores row boundaries and flushes every 4096 bytes.
626 */
627 
628 static FilterFn rleFilter;
629 
630 static void
rleFilter(FILE * const ifP,FILE * const ofP,OutputEncoder * const oeP)631 rleFilter (FILE *          const ifP,
632            FILE *          const ofP,
633            OutputEncoder * const oeP) {
634 
635     unsigned int const inSize = oeP->runlengthRefresh;
636 
637     bool eof;
638     unsigned char * inbuf;
639     unsigned char * outbuf;
640     size_t outSize;
641 
642     MALLOCARRAY(inbuf, inSize);
643     if (inbuf == NULL)
644         pm_error("Failed to allocate %u bytes of memory for RLE filter",
645                   inSize);
646     pm_rlenc_allocoutbuf(&outbuf, inSize, PM_RLE_PACKBITS);
647 
648     for (eof = false; !eof; ) {
649         size_t const bytesRead = fread(inbuf, 1, inSize, ifP);
650 
651         if (feof(ifP))
652             eof = true;
653         else if (ferror(ifP) || bytesRead == 0)
654             pm_error("Internal read error: RLE compression");
655 
656         pm_rlenc_compressbyte(inbuf, outbuf, PM_RLE_PACKBITS,
657                               bytesRead, &outSize);
658         writeFile(outbuf, outSize, "rlePutBuffer", ofP);
659     }
660 
661     fclose(ifP);
662     fclose(ofP);
663 }
664 
665 
666 
667 static FilterFn asciiHexFilter;
668 
669 static void
asciiHexFilter(FILE * const ifP,FILE * const ofP,OutputEncoder * const oeP)670 asciiHexFilter(FILE *          const ifP,
671                FILE *          const ofP,
672                OutputEncoder * const oeP) {
673 
674     char const hexits[16] = "0123456789abcdef";
675 
676     bool eof;
677     unsigned char inbuff[40], outbuff[81];
678 
679     for (eof = false; !eof; ) {
680         size_t readCt;
681 
682         readCt = fread(inbuff, 1, 40, ifP);
683 
684         if (readCt == 0)
685             eof = true;
686         else {
687             unsigned int i;
688 
689             for (i = 0; i < readCt; ++i) {
690                 int const item = inbuff[i];
691                 outbuff[i*2]   = hexits[item >> 4];
692                 outbuff[i*2+1] = hexits[item & 15];
693             }
694             outbuff[readCt * 2] = '\n';
695             writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP);
696         }
697     }
698 
699     fclose(ifP);
700     fclose(ofP);
701 }
702 
703 
704 
705 static FilterFn ascii85Filter;
706 
707 static void
ascii85Filter(FILE * const ifP,FILE * const ofP,OutputEncoder * const oeP)708 ascii85Filter(FILE *          const ifP,
709               FILE *          const ofP,
710               OutputEncoder * const oeP) {
711 
712     bool eof;
713     char outbuff[5];
714     unsigned long int value; /* requires 32 bits */
715     int count;
716     int outcount;
717 
718     value = 0;  /* initial value */
719     count = 0;  /* initial value */
720     outcount = 0; /* initial value */
721 
722     for (eof = false; !eof; ) {
723         int c;
724 
725         c = fgetc(ifP);
726 
727         if (c == EOF)
728             eof = true;
729         else {
730             value = value*256 + c;
731             ++count;
732 
733             if (value == 0 && count == 4) {
734                 writeFileChar("z", 1, "ASCII 85 filter", ofP);
735                     /* Ascii85 encoding z exception */
736                 ++outcount;
737                 count = 0;
738             } else if (count == 4) {
739                 outbuff[4] = value % 85 + 33;  value/=85;
740                 outbuff[3] = value % 85 + 33;  value/=85;
741                 outbuff[2] = value % 85 + 33;  value/=85;
742                 outbuff[1] = value % 85 + 33;
743                 outbuff[0] = value / 85 + 33;
744 
745                 writeFileChar(outbuff, count + 1, "ASCII 85 filter", ofP);
746 
747                 count = value = 0;
748                 outcount += 5;
749             }
750 
751             if (outcount > 75) {
752                 writeFileChar("\n", 1, "ASCII 85 filter", ofP);
753                 outcount = 0;
754             }
755         }
756     }
757 
758     if (count > 0) { /* EOF, flush */
759         assert (count < 4);
760 
761         value <<= (4 - count) * 8;   value/=85;
762         outbuff[3] = value % 85 + 33;  value/=85;
763         outbuff[2] = value % 85 + 33;  value/=85;
764         outbuff[1] = value % 85 + 33;
765         outbuff[0] = value / 85 + 33;
766         outbuff[count + 1] = '\n';
767 
768         writeFileChar(outbuff, count + 2, "ASCII 85 filter", ofP);
769     }
770 
771     fclose(ifP);
772     fclose(ofP);
773 }
774 
775 
776 
777 static void
makePipe(int * const pipeFdArray)778 makePipe(int * const pipeFdArray) {
779 
780     int rc;
781     rc = pm_pipe(pipeFdArray);
782     if (rc == -1)
783         pm_error("pipe() failed, errno = %d (%s)", errno, strerror(errno));
784 }
785 
786 
787 
788 static void
closeAllBut(int const saveFd0,int const saveFd1,int const saveFd2)789 closeAllBut(int const saveFd0,
790             int const saveFd1,
791             int const saveFd2) {
792 /*----------------------------------------------------------------------------
793    Close every file descriptor in this process except 'saveFd0',
794    'saveFd1', and 'saveFd2'.
795 
796    This is helpful because even if this process doesn't touch other file
797    descriptors, its very existence will keep the files open.
798 -----------------------------------------------------------------------------*/
799 
800     /* Unix provides no good way to do this; we just assume file descriptors
801        above 9 are not used in this program; Caller must ensure that is true.
802     */
803     int fd;
804 
805     for (fd = 0; fd < 10; ++fd) {
806         if (fd != saveFd0 && fd != saveFd1 && fd != saveFd2)
807             close(fd);
808     }
809 }
810 
811 
812 
813 static void
spawnFilter(FILE * const ofP,FilterFn * const filterFn,OutputEncoder * const oeP,FILE ** const feedFilePP,pid_t * const pidP)814 spawnFilter(FILE *          const ofP,
815             FilterFn *      const filterFn,
816             OutputEncoder * const oeP,
817             FILE **         const feedFilePP,
818             pid_t *         const pidP) {
819 /*----------------------------------------------------------------------------
820    Fork a child process to run filter function 'filterFn' and send its
821    output to *ofP.
822 
823    Create a pipe for feeding the filter and return as *feedFilePP the
824    stream to which Caller can write to push stuff into the filter.
825 
826    *oeP is the parameter to 'filterFn'.
827 -----------------------------------------------------------------------------*/
828     int pipeFd[2];
829     pid_t rc;
830 
831     makePipe(pipeFd);
832 
833     rc = fork();
834 
835     if (rc == (pid_t)-1)
836         pm_error("fork() of filter process failed.  errno=%d (%s)",
837                  errno, strerror(errno));
838     else if (rc == 0) {
839         /* This is the child process */
840 
841         FILE * ifP;
842 
843         ifP = fdopen(pipeFd[0], "r");
844 
845         if (!ifP)
846             pm_error("filter process failed to make "
847                      "file stream (\"FILE\") "
848                      "out of the file descriptor which is input to the "
849                      "filter.  errno=%d (%s)",
850                      errno, strerror(errno));
851 
852         closeAllBut(fileno(ifP), fileno(ofP), STDERR_FILENO);
853 
854         filterFn(ifP, ofP, oeP);
855 
856         exit(EXIT_SUCCESS);
857     } else {
858         /* This is the parent process */
859 
860         pid_t const childPid = rc;
861 
862         close(pipeFd[0]);
863 
864         *feedFilePP = fdopen(pipeFd[1], "w");
865 
866         *pidP = childPid;
867     }
868 }
869 
870 
871 
872 static void
addFilter(const char * const description,FilterFn * const filter,OutputEncoder * const oeP,FILE ** const feedFilePP,pid_t * const pidList)873 addFilter(const char *    const description,
874           FilterFn *      const filter,
875           OutputEncoder * const oeP,
876           FILE **         const feedFilePP,
877           pid_t *         const pidList) {
878 /*----------------------------------------------------------------------------
879    Add a filter to the front of the chain.
880 
881    Spawn a process to do the filtering, by running function 'filter'.
882 
883    *feedFilePP is the present head of the chain.  We make the new filter
884    process write its output to that and get its input from a new pipe.
885    We update *feedFilePP to the sending end of the new pipe.
886 
887    Add to the list pidList[] the PID of the process we spawn.
888 -----------------------------------------------------------------------------*/
889     FILE * const oldFeedFileP = *feedFilePP;
890 
891     FILE * newFeedFileP;
892     pid_t pid;
893 
894     spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid);
895 
896     if (verbose)
897         pm_message("%s filter spawned: pid %u",
898                    description, (unsigned)pid);
899 
900     if (debug) {
901         int const outFd    = fileno(oldFeedFileP);
902         int const supplyFd = fileno(newFeedFileP);
903         pm_message("PID %u writes to FD %u, its supplier writes to FD %u",
904                    (unsigned)pid, outFd, supplyFd);
905     }
906     fclose(oldFeedFileP);  /* Child keeps this open now */
907 
908     addToPidList(pidList, pid);
909 
910     *feedFilePP = newFeedFileP;
911 }
912 
913 
914 
915 static void
spawnFilters(FILE * const ofP,OutputEncoder * const oeP,FILE ** const feedFilePP,pid_t * const pidList)916 spawnFilters(FILE *          const ofP,
917              OutputEncoder * const oeP,
918              FILE **         const feedFilePP,
919              pid_t *         const pidList) {
920 /*----------------------------------------------------------------------------
921    Get all the child processes for the filters running and connected.
922    Return at *feedFileP the file stream to which to write the raw data,
923    with the filtered data going to *ofP.
924 
925    Filter according to *oeP.
926 -----------------------------------------------------------------------------*/
927 
928     /* Build up the pipeline from the final to the initial stage.  The
929        result is one of:
930 
931           FEED | convertRow | asciiHexFilter | *ofP
932           FEED | convertRow | ascii85Filter | *ofP
933           FEED | convertRow | rleFilter   | asciiHexFilter | *ofP
934           FEED | convertRow | flateFilter | asciiHexFilter | *ofP
935           FEED | convertRow | flateFilter | rleFilter | asciiHexFilter | *ofP
936     */
937 
938     FILE * feedFileP;
939         /* The current head of the filter chain; changes as we add filters */
940 
941     initPidList(pidList);
942 
943     feedFileP = ofP;  /* Initial state: no filter at all */
944 
945     addFilter(
946         "output",
947         oeP->outputType == Ascii85 ? &ascii85Filter : asciiHexFilter,
948         oeP,
949         &feedFileP,
950         pidList);
951 
952     if (oeP->compressFlate)
953         addFilter("flate", flateFilter, oeP, &feedFileP, pidList);
954 
955     if (oeP->compressRle)
956         addFilter("rle", rleFilter, oeP, &feedFileP, pidList);
957 
958     *feedFilePP = feedFileP;
959 }
960 
961 
962 
963 static void
waitForChildren(const pid_t * const pidList)964 waitForChildren(const pid_t * const pidList) {
965 /*----------------------------------------------------------------------------
966    Wait for all child processes with PIDs in pidList[] to exit.
967    In pidList[], end-of-list is marked with a special zero value.
968 -----------------------------------------------------------------------------*/
969     /* There's an odd behavior in Unix such that if you have set the
970        action for SIGCHLD to ignore the signal (even though ignoring the
971        signal is the default), the process' children do not become
972        zombies.  Consequently, waitpid() always fails with ECHILD - but
973        nonetheless waits for the child to exit.
974 
975        We expect the process not to have the action for SIGCHLD set that
976        way.
977     */
978     unsigned int i;
979 
980     for (i = 0; pidList[i]; ++i) {
981         pid_t rc;
982         int status;
983 
984         if (verbose)
985             pm_message("Waiting for PID %u to exit", (unsigned)pidList[i]);
986 
987         rc = waitpid(pidList[i], &status, 0);
988         if (rc == -1)
989             pm_error ("waitpid() for child %u failed, errno=%d (%s)",
990                       i, errno, strerror(errno));
991         else if (status != EXIT_SUCCESS)
992             pm_error ("Child process %u terminated abnormally", i);
993     }
994     if (verbose)
995         pm_message("All children have exited");
996 }
997 
998 
999 
1000 /*============================================================================
1001   END OF OUTPUT ENCODERS
1002 ============================================================================*/
1003 
1004 
1005 
1006 static void
validateComputableBoundingBox(float const scols,float const srows,float const llx,float const lly)1007 validateComputableBoundingBox(float const scols,
1008                               float const srows,
1009                               float const llx,
1010                               float const lly) {
1011 
1012     float const bbWidth  = llx + scols + 0.5;
1013     float const bbHeight = lly + srows + 0.5;
1014 
1015     if (bbHeight < INT_MIN || bbHeight > INT_MAX ||
1016         bbWidth  < INT_MIN || bbWidth  > INT_MAX)
1017         pm_error("Bounding box dimensions %.1f x %.1f are too large "
1018                  "for computations.  "
1019                  "This probably means input image width, height, "
1020                  "or scale factor is too large", bbWidth, bbHeight);
1021 }
1022 
1023 
1024 
1025 static void
warnUserRescaling(float const scale)1026 warnUserRescaling(float const scale) {
1027 
1028     const char * const baseMsg = "warning, image too large for page";
1029 
1030     if (pm_have_float_format())
1031         pm_message("%s; rescaling to %g", baseMsg, scale);
1032     else
1033         pm_message("%s; rescaling", baseMsg);
1034 }
1035 
1036 
1037 
1038 static void
computeImagePosition(int const dpiX,int const dpiY,int const icols,int const irows,bool const mustturn,bool const canturn,bool const center,int const pagewid,int const pagehgt,float const requestedScale,float const imagewidth,float const imageheight,bool const equalpixels,float * const scolsP,float * const srowsP,float * const llxP,float * const llyP,bool * const turnedP)1039 computeImagePosition(int     const dpiX,
1040                      int     const dpiY,
1041                      int     const icols,
1042                      int     const irows,
1043                      bool    const mustturn,
1044                      bool    const canturn,
1045                      bool    const center,
1046                      int     const pagewid,
1047                      int     const pagehgt,
1048                      float   const requestedScale,
1049                      float   const imagewidth,
1050                      float   const imageheight,
1051                      bool    const equalpixels,
1052                      float * const scolsP,
1053                      float * const srowsP,
1054                      float * const llxP,
1055                      float * const llyP,
1056                      bool *  const turnedP ) {
1057 /*----------------------------------------------------------------------------
1058   Determine where on the page the image is to go.  This means position,
1059   dimensions, and orientation.
1060 
1061   icols/irows are the dimensions of the PNM input in xels.
1062 
1063   'mustturn' means we are required to rotate the image.
1064 
1065   'canturn' means we may rotate the image if it fits better, but don't
1066   have to.
1067 
1068   *scolsP, *srowsP are the dimensions of the image in 1/72 inch.
1069 
1070   *llxP, *llyP are the coordinates in the Postcript frame, of the lower left
1071   corner of the image on the page.  The Postscript frame is different from the
1072   Neptbm frame: units are 1/72 inch (1 point) and (0,0) is the lower left
1073   corner.
1074 
1075   *turnedP is true iff the image is to be rotated 90 degrees on the page.
1076 
1077   imagewidth/imageheight are the requested dimensions of the image on
1078   the page, in 1/72 inch.  Image will be as large as possible within
1079   those dimensions.  Zero means unspecified, so 'scale', 'pagewid',
1080   'pagehgt', 'irows', and 'icols' determine image size.
1081 
1082   'equalpixels' means the user wants one printed pixel per input pixel.
1083   It is inconsistent with imagewidth or imageheight != 0
1084 
1085   'requestedScale' is meaningful only when imageheight/imagewidth == 0
1086   and equalpixels == FALSE.  It tells how many inches the user wants
1087   72 pixels of input to occupy, if it fits on the page.
1088 -----------------------------------------------------------------------------*/
1089     int cols, rows;
1090     /* Number of columns, rows of input xels in the output, as
1091        rotated if applicable
1092     */
1093     bool shouldturn;  /* The image fits the page better if we turn it */
1094 
1095     if (icols > irows && pagehgt > pagewid)
1096         shouldturn = TRUE;
1097     else if (irows > icols && pagewid > pagehgt)
1098         shouldturn = TRUE;
1099     else
1100         shouldturn = FALSE;
1101 
1102     if (mustturn || (canturn && shouldturn)) {
1103         *turnedP = TRUE;
1104         cols = irows;
1105         rows = icols;
1106     } else {
1107         *turnedP = FALSE;
1108         cols = icols;
1109         rows = irows;
1110     }
1111     if (equalpixels) {
1112         *scolsP = (72.0/dpiX)*cols;
1113         *srowsP = (72.0/dpiY)*rows;
1114     } else if (imagewidth > 0 || imageheight > 0) {
1115         float scale;
1116 
1117         if (imagewidth == 0)
1118             scale = (float) imageheight/rows;
1119         else if (imageheight == 0)
1120             scale = (float) imagewidth/cols;
1121         else
1122             scale = MIN((float)imagewidth/cols, (float)imageheight/rows);
1123 
1124         *scolsP = cols*scale;
1125         *srowsP = rows*scale;
1126     } else {
1127         /* He didn't give us a bounding box for the image so figure
1128            out output image size from other inputs.
1129         */
1130         const int devpixX = dpiX / 72.0 + 0.5;
1131         const int devpixY = dpiY / 72.0 + 0.5;
1132         /* How many device pixels make up 1/72 inch, rounded to
1133            nearest integer */
1134         const float pixfacX = 72.0 / dpiX * devpixX;  /* 1, approx. */
1135         const float pixfacY = 72.0 / dpiY * devpixY;  /* 1, approx. */
1136         float scale;
1137 
1138         scale = MIN(requestedScale,
1139                     MIN((float)pagewid/cols, (float)pagehgt/rows));
1140 
1141         *scolsP = scale * cols * pixfacX;
1142         *srowsP = scale * rows * pixfacY;
1143 
1144         if (scale != requestedScale)
1145             warnUserRescaling(scale);
1146 
1147         /* Before May 2001, Pnmtops enforced a 5% margin around the page.
1148            If the image would be too big to leave a 5% margin, Pnmtops would
1149            scale it down.  But people have images that are exactly the size
1150            of a page, e.g. because they created them with Sane's 'scanimage'
1151            program from a full page of input.  So we removed the gratuitous
1152            5% margin.  -Bryan.
1153         */
1154     }
1155     *llxP = (center) ? ( pagewid - *scolsP ) / 2 : 0;
1156     *llyP = (center) ? ( pagehgt - *srowsP ) / 2 : 0;
1157 
1158     validateComputableBoundingBox( *scolsP, *srowsP, *llxP, *llyP);
1159 
1160     if (verbose)
1161         pm_message("Image will be %3.2f points wide by %3.2f points high, "
1162                    "left edge %3.2f points from left edge of page, "
1163                    "bottom edge %3.2f points from bottom of page; "
1164                    "%sturned to landscape orientation",
1165                    *scolsP, *srowsP, *llxP, *llyP, *turnedP ? "" : "NOT ");
1166 }
1167 
1168 
1169 
1170 static void
determineDictionaryRequirement(bool const userWantsDict,bool const psFilter,unsigned int * const dictSizeP)1171 determineDictionaryRequirement(bool           const userWantsDict,
1172                                bool           const psFilter,
1173                                unsigned int * const dictSizeP) {
1174 
1175     if (userWantsDict) {
1176         if (psFilter) {
1177             /* The Postscript this program generates to use built-in
1178                Postscript filters does not define any variables.
1179             */
1180             *dictSizeP = 0;
1181         } else
1182             *dictSizeP = 8;
1183     } else
1184         *dictSizeP = 0;
1185 }
1186 
1187 
1188 
1189 static void
defineReadstring(bool const rle)1190 defineReadstring(bool const rle) {
1191 /*----------------------------------------------------------------------------
1192   Write to Standard Output Postscript statements to define /readstring.
1193 -----------------------------------------------------------------------------*/
1194     if (rle) {
1195         printf("/rlestr1 1 string def\n");
1196         printf("/readrlestring {\n");             /* s -- nr */
1197         printf("  /rlestr exch def\n");           /* - */
1198         printf("  currentfile rlestr1 readhexstring pop\n");  /* s1 */
1199         printf("  0 get\n");                  /* c */
1200         printf("  dup 127 le {\n");               /* c */
1201         printf("    currentfile rlestr 0\n");         /* c f s 0 */
1202         printf("    4 3 roll\n");             /* f s 0 c */
1203         printf("    1 add  getinterval\n");           /* f s */
1204         printf("    readhexstring pop\n");            /* s */
1205         printf("    length\n");               /* nr */
1206         printf("  } {\n");                    /* c */
1207         printf("    257 exch sub dup\n");         /* n n */
1208         printf("    currentfile rlestr1 readhexstring pop\n");/* n n s1 */
1209         printf("    0 get\n");                /* n n c */
1210         printf("    exch 0 exch 1 exch 1 sub {\n");       /* n c 0 1 n-1*/
1211         printf("      rlestr exch 2 index put\n");
1212         printf("    } for\n");                /* n c */
1213         printf("    pop\n");                  /* nr */
1214         printf("  } ifelse\n");               /* nr */
1215         printf("} bind def\n");
1216         printf("/readstring {\n");                /* s -- s */
1217         printf("  dup length 0 {\n");             /* s l 0 */
1218         printf("    3 copy exch\n");              /* s l n s n l*/
1219         printf("    1 index sub\n");              /* s l n s n r*/
1220         printf("    getinterval\n");              /* s l n ss */
1221         printf("    readrlestring\n");            /* s l n nr */
1222         printf("    add\n");                  /* s l n */
1223         printf("    2 copy le { exit } if\n");        /* s l n */
1224         printf("  } loop\n");                 /* s l l */
1225         printf("  pop pop\n");                /* s */
1226         printf("} bind def\n");
1227     } else {
1228         printf("/readstring {\n");                /* s -- s */
1229         printf("  currentfile exch readhexstring pop\n");
1230         printf("} bind def\n");
1231     }
1232 }
1233 
1234 
1235 
1236 static void
setupReadstringNative(bool const rle,bool const color,unsigned int const icols,unsigned int const bitsPerSample)1237 setupReadstringNative(bool         const rle,
1238                       bool         const color,
1239                       unsigned int const icols,
1240                       unsigned int const bitsPerSample) {
1241 /*----------------------------------------------------------------------------
1242   Write to Standard Output statements to define /readstring and also
1243   arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr).
1244 -----------------------------------------------------------------------------*/
1245     unsigned int const bytesPerRow = icols / (8/bitsPerSample) +
1246         (icols % (8/bitsPerSample) > 0 ? 1 : 0);
1247         /* Size of row buffer, padded up to byte boundary. */
1248 
1249     defineReadstring(rle);
1250 
1251     if (color) {
1252         printf("/rpicstr %d string def\n", bytesPerRow);
1253         printf("/gpicstr %d string def\n", bytesPerRow);
1254         printf("/bpicstr %d string def\n", bytesPerRow);
1255     } else
1256         printf("/picstr %d string def\n", bytesPerRow);
1257 }
1258 
1259 
1260 
1261 static void
putFilters(unsigned int const postscriptLevel,bool const rle,bool const flate,bool const ascii85,bool const color)1262 putFilters(unsigned int const postscriptLevel,
1263            bool         const rle,
1264            bool         const flate,
1265            bool         const ascii85,
1266            bool         const color) {
1267 
1268     assert(postscriptLevel > 1);
1269 
1270     /* We say to decode flate, then rle, so Caller must ensure it encodes
1271        rel, then flate.
1272     */
1273 
1274     if (ascii85)
1275         printf("/ASCII85Decode filter ");
1276     else
1277         printf("/ASCIIHexDecode filter ");
1278     if (flate)
1279         printf("/FlateDecode filter ");
1280     if (rle)
1281         printf("/RunLengthDecode filter ");
1282 }
1283 
1284 
1285 
1286 static void
putReadstringNative(bool const color)1287 putReadstringNative(bool const color) {
1288 
1289     if (color) {
1290         printf("{ rpicstr readstring }\n");
1291         printf("{ gpicstr readstring }\n");
1292         printf("{ bpicstr readstring }\n");
1293     } else
1294         printf("{ picstr readstring }\n");
1295 }
1296 
1297 
1298 
1299 static void
putSetup(unsigned int const dictSize,bool const psFilter,bool const rle,bool const color,unsigned int const icols,unsigned int const bitsPerSample)1300 putSetup(unsigned int const dictSize,
1301          bool         const psFilter,
1302          bool         const rle,
1303          bool         const color,
1304          unsigned int const icols,
1305          unsigned int const bitsPerSample) {
1306 /*----------------------------------------------------------------------------
1307   Put the setup section in the Postscript program on Standard Output.
1308 -----------------------------------------------------------------------------*/
1309     printf("%%%%BeginSetup\n");
1310 
1311     if (dictSize > 0)
1312         /* inputf {r,g,b,}pictsr readstring readrlestring rlestring */
1313         printf("%u dict begin\n", dictSize);
1314 
1315     if (!psFilter)
1316         setupReadstringNative(rle, color, icols, bitsPerSample);
1317 
1318     printf("%%%%EndSetup\n");
1319 }
1320 
1321 
1322 
1323 static void
putImage(bool const psFilter,bool const color)1324 putImage(bool const psFilter,
1325          bool const color) {
1326 /*----------------------------------------------------------------------------
1327   Put the image/colorimage statement in the Postscript program on
1328   Standard Output.
1329 -----------------------------------------------------------------------------*/
1330     if (color) {
1331         if (psFilter)
1332             printf("false 3\n");
1333         else
1334             printf("true 3\n");
1335         printf("colorimage");
1336     } else
1337         printf("image");
1338 }
1339 
1340 
1341 
1342 static void
putInitPsFilter(unsigned int const postscriptLevel,bool const rle,bool const flate,bool const ascii85,bool const color)1343 putInitPsFilter(unsigned int const postscriptLevel,
1344                 bool         const rle,
1345                 bool         const flate,
1346                 bool         const ascii85,
1347                 bool         const color) {
1348 
1349     bool const filterTrue = TRUE;
1350 
1351     printf("{ currentfile ");
1352 
1353     putFilters(postscriptLevel, rle, flate, ascii85, color);
1354 
1355     putImage(filterTrue, color);
1356 
1357     printf(" } exec");
1358 }
1359 
1360 
1361 
1362 static void
putInitReadstringNative(bool const color)1363 putInitReadstringNative(bool const color) {
1364 
1365     bool const filterFalse = FALSE;
1366 
1367     putReadstringNative(color);
1368 
1369     putImage(filterFalse, color);
1370 }
1371 
1372 
1373 
1374 static void
putInit(unsigned int const postscriptLevel,char const name[],int const icols,int const irows,float const scols,float const srows,float const llx,float const lly,int const bitsPerSample,int const pagewid,int const pagehgt,bool const color,bool const turned,bool const rle,bool const flate,bool const ascii85,bool const setpage,bool const psFilter,unsigned int const dictSize)1375 putInit(unsigned int const postscriptLevel,
1376         char         const name[],
1377         int          const icols,
1378         int          const irows,
1379         float        const scols,
1380         float        const srows,
1381         float        const llx,
1382         float        const lly,
1383         int          const bitsPerSample,
1384         int          const pagewid,
1385         int          const pagehgt,
1386         bool         const color,
1387         bool         const turned,
1388         bool         const rle,
1389         bool         const flate,
1390         bool         const ascii85,
1391         bool         const setpage,
1392         bool         const psFilter,
1393         unsigned int const dictSize) {
1394 /*----------------------------------------------------------------------------
1395   Write out to Standard Output the headers stuff for the Postscript
1396   program (everything up to the raster).
1397 -----------------------------------------------------------------------------*/
1398     /* The numbers in the %! line often confuse people. They are NOT the
1399        PostScript language level.  The first is the level of the DSC comment
1400        spec being adhered to, the second is the level of the EPSF spec being
1401        adhered to.  It is *incorrect* to claim EPSF compliance if the file
1402        contains a setpagedevice.
1403     */
1404     printf("%%!PS-Adobe-3.0%s\n", setpage ? "" : " EPSF-3.0");
1405     printf("%%%%LanguageLevel: %u\n", postscriptLevel);
1406     printf("%%%%Creator: pnmtops\n");
1407     printf("%%%%Title: %s.ps\n", name);
1408     printf("%%%%Pages: 1\n");
1409     printf(
1410         "%%%%BoundingBox: %d %d %d %d\n",
1411         (int) llx, (int) lly,
1412         (int) (llx + scols + 0.5), (int) (lly + srows + 0.5));
1413     printf("%%%%EndComments\n");
1414 
1415     putSetup(dictSize, psFilter, rle, color, icols, bitsPerSample);
1416 
1417     printf("%%%%Page: 1 1\n");
1418     if (setpage)
1419         printf("<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n",
1420                pagewid, pagehgt);
1421     printf("gsave\n");
1422     printf("%g %g translate\n", llx, lly);
1423     printf("%g %g scale\n", scols, srows);
1424     if (turned)
1425         printf("0.5 0.5 translate  90 rotate  -0.5 -0.5 translate\n");
1426     printf("%d %d %d\n", icols, irows, bitsPerSample);
1427     printf("[ %d 0 0 -%d 0 %d ]\n", icols, irows, irows);
1428 
1429     if (psFilter)
1430         putInitPsFilter(postscriptLevel, rle, flate, ascii85, color);
1431     else
1432         putInitReadstringNative(color);
1433 
1434     printf("\n");
1435     fflush(stdout);
1436 }
1437 
1438 
1439 
1440 static void
putEnd(bool const showpage,bool const psFilter,bool const ascii85,unsigned int const dictSize,bool const vmreclaim)1441 putEnd(bool         const showpage,
1442        bool         const psFilter,
1443        bool         const ascii85,
1444        unsigned int const dictSize,
1445        bool         const vmreclaim) {
1446 
1447     if (psFilter) {
1448         if (ascii85)
1449             printf("%s\n", "~>");
1450         else
1451             printf("%s\n", ">");
1452     } else {
1453         printf("currentdict /inputf undef\n");
1454         printf("currentdict /picstr undef\n");
1455         printf("currentdict /rpicstr undef\n");
1456         printf("currentdict /gpicstr undef\n");
1457         printf("currentdict /bpicstr undef\n");
1458     }
1459 
1460     if (dictSize > 0)
1461         printf("end\n");
1462 
1463     if (vmreclaim)
1464         printf("1 vmreclaim\n");
1465 
1466     printf("grestore\n");
1467 
1468     if (showpage)
1469         printf("showpage\n");
1470     printf("%%%%Trailer\n");
1471 }
1472 
1473 
1474 
1475 static void
validateBpsRequest(unsigned int const bitsPerSampleReq,unsigned int const postscriptLevel,bool const psFilter)1476 validateBpsRequest(unsigned int const bitsPerSampleReq,
1477                    unsigned int const postscriptLevel,
1478                    bool         const psFilter) {
1479 
1480     if (postscriptLevel < 2 && bitsPerSampleReq > 8)
1481         pm_error("You requested %u bits per sample, but in Postscript "
1482                  "level 1, 8 is the maximum.  You can get 12 with "
1483                  "-level 2 and -psfilter", bitsPerSampleReq);
1484     else if (!psFilter && bitsPerSampleReq > 8)
1485         pm_error("You requested %u bits per sample, but without "
1486                  "-psfilter, the maximum is 8", bitsPerSampleReq);
1487 }
1488 
1489 
1490 
1491 static unsigned int
bpsFromInput(unsigned int const bitsRequiredByMaxval,unsigned int const postscriptLevel,bool const psFilter)1492 bpsFromInput(unsigned int const bitsRequiredByMaxval,
1493              unsigned int const postscriptLevel,
1494              bool         const psFilter) {
1495 
1496     unsigned int retval;
1497 
1498     if (bitsRequiredByMaxval <= 1)
1499         retval = 1;
1500     else if (bitsRequiredByMaxval <= 2)
1501         retval = 2;
1502     else if (bitsRequiredByMaxval <= 4)
1503         retval = 4;
1504     else if (bitsRequiredByMaxval <= 8)
1505         retval = 8;
1506     else {
1507         /* Post script level 2 defines a format with 12 bits per sample,
1508            but I don't know the details of that format (both RLE and
1509            non-RLE variations) and existing native raster generation code
1510            simply can't handle bps > 8.  But the built-in filters know
1511            how to do 12 bps.
1512         */
1513         if (postscriptLevel >= 2 && psFilter)
1514             retval = 12;
1515         else
1516             retval = 8;
1517     }
1518     return retval;
1519 }
1520 
1521 
1522 
1523 static void
warnUserAboutReducedDepth(unsigned int const bitsGot,unsigned int const bitsWanted,bool const userRequested,unsigned int const postscriptLevel,bool const psFilter)1524 warnUserAboutReducedDepth(unsigned int const bitsGot,
1525                           unsigned int const bitsWanted,
1526                           bool         const userRequested,
1527                           unsigned int const postscriptLevel,
1528                           bool         const psFilter) {
1529 
1530     if (bitsGot < bitsWanted) {
1531         pm_message("Postscript will have %u bits of color resolution, "
1532                    "though the input has %u bits.",
1533                    bitsGot, bitsWanted);
1534 
1535         if (!userRequested) {
1536             if (postscriptLevel < 2)
1537                 pm_message("Postscript level %u has a maximum depth of "
1538                            "8 bits.  "
1539                            "You could get up to 12 with -level=2 "
1540                            "and -psfilter.",
1541                            postscriptLevel);
1542             else {
1543                 if (!psFilter)
1544                     pm_message("You can get up to 12 bits with -psfilter");
1545                 else
1546                     pm_message("The Postscript maximum is 12.");
1547             }
1548         }
1549     }
1550 }
1551 
1552 
1553 
1554 static void
computeDepth(xelval const inputMaxval,unsigned int const postscriptLevel,bool const psFilter,unsigned int const bitsPerSampleReq,unsigned int * const bitsPerSampleP)1555 computeDepth(xelval         const inputMaxval,
1556              unsigned int   const postscriptLevel,
1557              bool           const psFilter,
1558              unsigned int   const bitsPerSampleReq,
1559              unsigned int * const bitsPerSampleP) {
1560 /*----------------------------------------------------------------------------
1561   Figure out how many bits will represent each sample in the Postscript
1562   program, and the maxval of the Postscript program samples.  The maxval
1563   is just the maximum value allowable in the number of bits.
1564 
1565   'bitsPerSampleReq' is the bits per sample that the user requests, or
1566   zero if he made no request.
1567 -----------------------------------------------------------------------------*/
1568     unsigned int const bitsRequiredByMaxval = pm_maxvaltobits(inputMaxval);
1569 
1570     if (bitsPerSampleReq != 0) {
1571         validateBpsRequest(bitsPerSampleReq, postscriptLevel, psFilter);
1572         *bitsPerSampleP = bitsPerSampleReq;
1573     } else {
1574         *bitsPerSampleP = bpsFromInput(bitsRequiredByMaxval,
1575                                        postscriptLevel, psFilter);
1576     }
1577     warnUserAboutReducedDepth(*bitsPerSampleP, bitsRequiredByMaxval,
1578                               bitsPerSampleReq != 0,
1579                               postscriptLevel, psFilter);
1580 
1581     if (verbose) {
1582         unsigned int const psMaxval = pm_bitstomaxval(*bitsPerSampleP);
1583         pm_message("Input maxval is %u.  Postscript raster will have "
1584                    "%u bits per sample, so maxval = %u",
1585                    inputMaxval, *bitsPerSampleP, psMaxval);
1586     }
1587 }
1588 
1589 
1590 
1591 /*===========================================================================
1592   The bit accumulator
1593 ===========================================================================*/
1594 
1595 typedef struct {
1596     unsigned int value;
1597     unsigned int consumed;
1598 } BitAccumulator;
1599 
1600 
1601 
1602 static void
ba_init(BitAccumulator * const baP)1603 ba_init(BitAccumulator * const baP) {
1604 
1605     baP->value    = 0;
1606     baP->consumed = 0;
1607 }
1608 
1609 
1610 
1611 static void
ba_add12(BitAccumulator * const baP,unsigned int const new12,FILE * const fP)1612 ba_add12(BitAccumulator * const baP,
1613          unsigned int     const new12,
1614          FILE           * const fP) {
1615 /*----------------------------------------------------------------------------
1616   Read a 12-bit string into the bit accumulator baP->value.
1617   On every other call, combine two 12-bit strings and write out three bytes.
1618 -----------------------------------------------------------------------------*/
1619     assert (baP->consumed == 12 || baP->consumed == 0);
1620 
1621     if (baP->consumed == 12){
1622         char const oldHi8 = (baP->value) >> 4;
1623         char const oldLo4 = (baP->value) & 0x0f;
1624         char const newHi4 = new12 >> 8;
1625         char const newLo8 = new12 & 0xff;
1626 
1627         fputc(oldHi8, fP);
1628         fputc((oldLo4 << 4) | newHi4 , fP);
1629         fputc(newLo8, fP);
1630         baP->value = 0; baP->consumed = 0;
1631     } else {
1632         baP->value = new12;  baP->consumed = 12;
1633     }
1634 }
1635 
1636 
1637 
1638 static void
ba_add(BitAccumulator * const baP,unsigned int const b,unsigned int const bitsPerSample,FILE * const fP)1639 ba_add(BitAccumulator * const baP,
1640        unsigned int     const b,
1641        unsigned int     const bitsPerSample,
1642        FILE           * const fP) {
1643 /*----------------------------------------------------------------------------
1644   Combine bit sequences that do not fit into a byte.
1645 
1646   Used when bitsPerSample =1, 2, 4.
1647   Logic also works for bitsPerSample = 8, 16.
1648 
1649   The accumulator, baP->value is unsigned int (usually 32 bits), but
1650   only 8 bits are used.
1651 -----------------------------------------------------------------------------*/
1652     unsigned int const bufSize = 8;
1653 
1654     assert (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4);
1655 
1656     baP->value = (baP->value << bitsPerSample) | b ;
1657     baP->consumed += bitsPerSample;
1658     if (baP->consumed == bufSize) {
1659         /* flush */
1660         fputc( baP->value, fP);
1661         baP->value = 0;
1662         baP->consumed = 0;
1663     }
1664 }
1665 
1666 
1667 
1668 static void
ba_flush(BitAccumulator * const baP,FILE * const fP)1669 ba_flush(BitAccumulator * const baP,
1670          FILE *           const fP) {
1671 /*----------------------------------------------------------------------------
1672   Flush partial bits in baP->consumed.
1673 -----------------------------------------------------------------------------*/
1674     if (baP->consumed == 12) {
1675         char const oldHi8 = (baP->value) >> 4;
1676         char const oldLo4 = (baP->value) & 0x0f;
1677         fputc(oldHi8, fP);
1678         fputc(oldLo4 << 4, fP);
1679     } else if (baP->consumed == 8)
1680         fputc(baP->value , fP);
1681     else if (baP->consumed > 0) {
1682         unsigned int const leftShift = 8 - baP->consumed;
1683         assert(baP->consumed <= 8);  /* why? */
1684         baP->value <<= leftShift;
1685         fputc(baP->value , fP);
1686     }
1687     baP->value = 0;
1688     baP->consumed = 0;
1689 }
1690 
1691 
1692 
1693 static void
outputSample(BitAccumulator * const baP,unsigned int const sampleValue,unsigned int const bitsPerSample,FILE * const fP)1694 outputSample(BitAccumulator * const baP,
1695              unsigned int     const sampleValue,
1696              unsigned int     const bitsPerSample,
1697              FILE           * const fP) {
1698 
1699     if (bitsPerSample == 8)
1700         fputc(sampleValue, fP);
1701     else if (bitsPerSample == 12)
1702         ba_add12(baP, sampleValue, fP);
1703     else
1704         ba_add(baP, sampleValue, bitsPerSample, fP);
1705 }
1706 
1707 
1708 
1709 static void
flushOutput(BitAccumulator * const baP,FILE * const fP)1710 flushOutput(BitAccumulator * const baP,
1711             FILE *           const fP) {
1712     ba_flush(baP, fP);
1713 }
1714 
1715 
1716 
1717 /*----------------------------------------------------------------------
1718   Row converters
1719 
1720   convertRowPbm is a fast routine for PBM images.
1721   It is used only when the input is PBM and the user does not specify
1722   a -bitspersample value greater than 1.  It is not used when the input
1723   image is PGM or PPM and the output resolution is brought down to one
1724   bit per pixel by -bitpersample=1 .
1725 
1726   convertRowNative and convertRowPsFilter are the general converters.
1727   They are quite similar, the differences being:
1728   (1) Native output separates the color planes:
1729   (RRR...RRR GGG...GGG BBB...BBB),
1730   whereas psFilter does not:
1731   (RGB RGB RGB RGB ......... RGB).
1732   (2) Native flushes the run-length encoder at the end of each row if
1733   grayscale, at the end of each plane if color.
1734 
1735   Both convertRowNative and convertRowPsFilter can handle PBM, though we
1736   don't use them.
1737 
1738   If studying the code, read convertRowPbm first.  convertRowNative and
1739   convertRowPsFilter are constructs that pack raster data into a form
1740   similar to a binary PBM bitrow.
1741   ----------------------------------------------------------------------*/
1742 
1743 static void
convertRowPbm(struct pam * const pamP,unsigned char * const bitrow,bool const psFilter,FILE * const fP)1744 convertRowPbm(struct pam *     const pamP,
1745               unsigned char  * const bitrow,
1746               bool             const psFilter,
1747               FILE *           const fP) {
1748 /*---------------------------------------------------------------------
1749   Feed PBM raster data directly to the output encoder.
1750   Invert bits: 0 is "white" in PBM, 0 is "black" in postscript.
1751 ----------------------------------------------------------------------*/
1752     unsigned int colChar;
1753     unsigned int const colChars = pbm_packed_bytes(pamP->width);
1754 
1755     pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format);
1756 
1757     for (colChar = 0; colChar < colChars; ++colChar)
1758         bitrow[colChar] =  ~ bitrow[colChar];
1759 
1760     /* Zero clear padding beyond right edge */
1761     pbm_cleanrowend_packed(bitrow, pamP->width);
1762     writeFile(bitrow, colChars, "PBM reader", fP);
1763 }
1764 
1765 
1766 
1767 static void
convertRowNative(struct pam * const pamP,tuple * tuplerow,unsigned int const bitsPerSample,FILE * const fP)1768 convertRowNative(struct pam *     const pamP,
1769                  tuple *                tuplerow,
1770                  unsigned int     const bitsPerSample,
1771                  FILE           * const fP) {
1772 
1773     unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample);
1774 
1775     unsigned int plane;
1776     BitAccumulator ba;
1777 
1778     ba_init(&ba);
1779 
1780     pnm_readpamrow(pamP, tuplerow);
1781     pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval);
1782 
1783     for (plane = 0; plane < pamP->depth; ++plane) {
1784         unsigned int col;
1785         for (col= 0; col < pamP->width; ++col)
1786             outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP);
1787 
1788         flushOutput(&ba, fP);
1789     }
1790 }
1791 
1792 
1793 
1794 static void
convertRowPsFilter(struct pam * const pamP,tuple * tuplerow,unsigned int const bitsPerSample,FILE * const fP)1795 convertRowPsFilter(struct pam *     const pamP,
1796                    tuple *                tuplerow,
1797                    unsigned int     const bitsPerSample,
1798                    FILE           * const fP) {
1799 
1800     unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample);
1801 
1802     unsigned int col;
1803     BitAccumulator ba;
1804 
1805     ba_init(&ba);
1806 
1807     pnm_readpamrow(pamP, tuplerow);
1808     pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval);
1809 
1810     for (col = 0; col < pamP->width; ++col) {
1811         unsigned int plane;
1812         for (plane = 0; plane < pamP->depth; ++plane)
1813             outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP);
1814     }
1815     flushOutput(&ba, fP);
1816 
1817 }
1818 
1819 
1820 
1821 static void
selectPostscriptLevel(bool const levelIsGiven,unsigned int const levelGiven,bool const color,bool const dict,bool const flate,bool const ascii85,bool const psFilter,unsigned int * const postscriptLevelP)1822 selectPostscriptLevel(bool           const levelIsGiven,
1823                       unsigned int   const levelGiven,
1824                       bool           const color,
1825                       bool           const dict,
1826                       bool           const flate,
1827                       bool           const ascii85,
1828                       bool           const psFilter,
1829                       unsigned int * const postscriptLevelP) {
1830 
1831     unsigned int const maxPermittedLevel =
1832         levelIsGiven ? levelGiven : UINT_MAX;
1833     unsigned int minPossibleLevel;
1834 
1835     /* Until we know, later in this function, that we needs certain
1836        features, we assume we can get by with classic Postscript Level 1:
1837     */
1838     minPossibleLevel = 1;
1839 
1840     /* Now we increase 'minPossibleLevel' as we notice that each of
1841        various features are required:
1842     */
1843     if (color) {
1844         minPossibleLevel = MAX(minPossibleLevel, 2);
1845         if (2 > maxPermittedLevel)
1846             pm_error("Color requires at least Postscript level 2");
1847     }
1848     if (flate) {
1849         minPossibleLevel = MAX(minPossibleLevel, 3);
1850         if (2 > maxPermittedLevel)
1851             pm_error("flate compression requires at least Postscript level 3");
1852     }
1853     if (ascii85) {
1854         minPossibleLevel = MAX(minPossibleLevel, 2);
1855         if (2 > maxPermittedLevel)
1856             pm_error("ascii85 encoding requires at least Postscript level 2");
1857     }
1858     if (psFilter) {
1859         minPossibleLevel = MAX(minPossibleLevel, 2);
1860         if (2 > maxPermittedLevel)
1861             pm_error("-psfilter requires at least Postscript level 2");
1862     }
1863     if (levelIsGiven)
1864         *postscriptLevelP = levelGiven;
1865     else
1866         *postscriptLevelP = minPossibleLevel;
1867 }
1868 
1869 
1870 
1871 static void
convertRaster(struct pam * const inpamP,unsigned int const bitsPerSample,bool const psFilter,FILE * const fP)1872 convertRaster(struct pam * const inpamP,
1873               unsigned int const bitsPerSample,
1874               bool         const psFilter,
1875               FILE *       const fP) {
1876 /*----------------------------------------------------------------------------
1877    Read the raster described by *inpamP, and write a bit stream of samples
1878    to *fP.  This stream has to be compressed and converted to text before it
1879    can be part of a Postscript program.
1880 
1881    'psFilter' means to do the conversion using built in Postscript filters, as
1882    opposed to our own filters via /readstring.
1883 
1884    'bitsPerSample' is how many bits each sample is to take in the Postscript
1885    output.
1886 -----------------------------------------------------------------------------*/
1887     if (PAM_FORMAT_TYPE(inpamP->format) == PBM_TYPE && bitsPerSample == 1)  {
1888         unsigned char * bitrow;
1889         unsigned int row;
1890 
1891         bitrow = pbm_allocrow_packed(inpamP->width);
1892 
1893         for (row = 0; row < inpamP->height; ++row)
1894             convertRowPbm(inpamP, bitrow, psFilter, fP);
1895 
1896         pbm_freerow(bitrow);
1897     } else  {
1898         tuple *tuplerow;
1899         unsigned int row;
1900 
1901         tuplerow = pnm_allocpamrow(inpamP);
1902 
1903         for (row = 0; row < inpamP->height; ++row) {
1904             if (psFilter)
1905                 convertRowPsFilter(inpamP, tuplerow, bitsPerSample, fP);
1906             else
1907                 convertRowNative(inpamP, tuplerow, bitsPerSample, fP);
1908         }
1909         pnm_freepamrow(tuplerow);
1910     }
1911 }
1912 
1913 
1914 
1915 /* FILE MANAGEMENT: File management is pretty hairy here.  A filter, which
1916    runs in its own process, needs to be able to cause its output file to
1917    close because it might be an internal pipe and the next stage needs to
1918    know output is done.  So the forking process must close its copy of the
1919    file descriptor.  BUT: if the output of the filter is not an internal
1920    pipe but this program's output, then we don't want it closed when the
1921    filter terminates because we'll need it to be open for the next image
1922    the program converts (with a whole new chain of filters).
1923 
1924    To prevent the program output file from getting closed, we pass a
1925    duplicate of it to spawnFilters() and keep the original open.
1926 */
1927 
1928 
1929 
1930 static void
convertPage(FILE * const ifP,int const turnflag,int const turnokflag,bool const psFilter,bool const rle,bool const flate,bool const ascii85,bool const setpage,bool const showpage,bool const center,float const scale,int const dpiX,int const dpiY,int const pagewid,int const pagehgt,int const imagewidth,int const imageheight,bool const equalpixels,unsigned int const bitsPerSampleReq,char const name[],bool const dict,bool const vmreclaim,bool const levelIsGiven,unsigned int const levelGiven)1931 convertPage(FILE *       const ifP,
1932             int          const turnflag,
1933             int          const turnokflag,
1934             bool         const psFilter,
1935             bool         const rle,
1936             bool         const flate,
1937             bool         const ascii85,
1938             bool         const setpage,
1939             bool         const showpage,
1940             bool         const center,
1941             float        const scale,
1942             int          const dpiX,
1943             int          const dpiY,
1944             int          const pagewid,
1945             int          const pagehgt,
1946             int          const imagewidth,
1947             int          const imageheight,
1948             bool         const equalpixels,
1949             unsigned int const bitsPerSampleReq,
1950             char         const name[],
1951             bool         const dict,
1952             bool         const vmreclaim,
1953             bool         const levelIsGiven,
1954             unsigned int const levelGiven) {
1955 
1956     struct pam inpam;
1957     float scols, srows;
1958     float llx, lly;
1959     bool turned;
1960     bool color;
1961     unsigned int postscriptLevel;
1962     unsigned int bitsPerSample;
1963     unsigned int dictSize;
1964         /* Size of Postscript dictionary we should define */
1965     OutputEncoder oe;
1966     pid_t filterPidList[MAX_FILTER_CT + 1];
1967 
1968     FILE * feedFileP;
1969         /* The file stream which is the head of the filter chain; we write to
1970            this and filtered stuff comes out the other end.
1971         */
1972     FILE * filterChainOfP;
1973 
1974     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
1975 
1976     validateCompDimension(inpam.width, 16, "Input image width");
1977 
1978     if (!STRSEQ(inpam.tuple_type, PAM_PBM_TUPLETYPE) &&
1979         !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) &&
1980         !STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE))
1981         pm_error("Unrecognized tuple type %s.  This program accepts only "
1982                  "PBM, PGM, PPM, and equivalent PAM input images",
1983                  inpam.tuple_type);
1984 
1985     color = STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE);
1986 
1987     selectPostscriptLevel(levelIsGiven, levelGiven, color,
1988                           dict, flate, ascii85, psFilter, &postscriptLevel);
1989 
1990     if (color)
1991         pm_message("generating color Postscript program.");
1992 
1993     computeDepth(inpam.maxval, postscriptLevel, psFilter, bitsPerSampleReq,
1994                  &bitsPerSample);
1995 
1996     /* In positioning/scaling the image, we treat the input image as if
1997        it has a density of 72 pixels per inch.
1998     */
1999     computeImagePosition(dpiX, dpiY, inpam.width, inpam.height,
2000                          turnflag, turnokflag, center,
2001                          pagewid, pagehgt, scale, imagewidth, imageheight,
2002                          equalpixels,
2003                          &scols, &srows, &llx, &lly, &turned);
2004 
2005     determineDictionaryRequirement(dict, psFilter, &dictSize);
2006 
2007     putInit(postscriptLevel, name, inpam.width, inpam.height,
2008             scols, srows, llx, lly, bitsPerSample,
2009             pagewid, pagehgt, color,
2010             turned, rle, flate, ascii85, setpage, psFilter, dictSize);
2011 
2012     initOutputEncoder(&oe, inpam.width, bitsPerSample,
2013                       rle, flate, ascii85, psFilter);
2014 
2015     fflush(stdout);
2016     filterChainOfP = fdopen(dup(fileno(stdout)), "w");
2017         /* spawnFilters() closes this.  See FILE MANAGEMENT above */
2018 
2019     spawnFilters(filterChainOfP, &oe, &feedFileP, filterPidList);
2020 
2021     convertRaster(&inpam, bitsPerSample, psFilter, feedFileP);
2022 
2023     fflush(feedFileP);
2024     fclose(feedFileP);
2025 
2026     waitForChildren(filterPidList);
2027 
2028     putEnd(showpage, psFilter, ascii85, dictSize, vmreclaim);
2029 }
2030 
2031 
2032 
2033 int
main(int argc,const char * argv[])2034 main(int argc, const char * argv[]) {
2035 
2036     FILE * ifP;
2037     const char * name;  /* malloc'ed */
2038     struct CmdlineInfo cmdline;
2039 
2040     pm_proginit(&argc, argv);
2041 
2042     setSignals();
2043 
2044     parseCommandLine(argc, argv, &cmdline);
2045 
2046     verbose = cmdline.verbose || cmdline.debug;
2047     debug   = cmdline.debug;
2048 
2049     if (cmdline.flate && !progIsFlateCapable())
2050         pm_error("This program cannot do flate compression.  "
2051                  "(There are other versions of the program that do, "
2052                  "though -- it's a build-time option");
2053 
2054     ifP = pm_openr(cmdline.inputFileName);
2055 
2056     if (streq(cmdline.inputFileName, "-"))
2057         name = strdup("noname");
2058     else
2059         name = basebasename(cmdline.inputFileName);
2060 
2061     /* This program manages file descriptors in a way that assumes
2062        that new files will get file descriptor numbers less than 10,
2063        so we close superfluous files now to make sure that's true.
2064     */
2065     closeAllBut(fileno(ifP), fileno(stdout), fileno(stderr));
2066 
2067     {
2068         int eof;  /* There are no more images in the input file */
2069         unsigned int imageSeq;
2070 
2071         /* I don't know if this works at all for multi-image PNM input.
2072            Before July 2000, it ignored everything after the first image,
2073            so this probably is at least as good -- it should be identical
2074            for a single-image file, which is the only kind which was legal
2075            before July 2000.
2076 
2077            Maybe there needs to be some per-file header and trailers stuff
2078            in the Postscript program, with some per-page header and trailer
2079            stuff inside.  I don't know Postscript.  - Bryan 2000.06.19.
2080         */
2081 
2082         eof = FALSE;  /* There is always at least one image */
2083         for (imageSeq = 0; !eof; ++imageSeq) {
2084             convertPage(ifP, cmdline.mustturn, cmdline.canturn,
2085                         cmdline.psfilter,
2086                         cmdline.rle, cmdline.flate, cmdline.ascii85,
2087                         cmdline.setpage, cmdline.showpage,
2088                         cmdline.center, cmdline.scale,
2089                         cmdline.dpiX, cmdline.dpiY,
2090                         cmdline.width, cmdline.height,
2091                         cmdline.imagewidth, cmdline.imageheight,
2092                         cmdline.equalpixels,
2093                         cmdline.bitspersampleSpec ? cmdline.bitspersample : 0,
2094                         name,
2095                         cmdline.dict, cmdline.vmreclaim,
2096                         cmdline.levelSpec, cmdline.level);
2097             pnm_nextimage(ifP, &eof);
2098         }
2099     }
2100     pm_strfree(name);
2101 
2102     pm_close(ifP);
2103 
2104     return 0;
2105 }
2106 
2107 
2108 
2109 /*
2110 ** Copyright (C) 1989 by Jef Poskanzer.
2111 **
2112 ** Permission to use, copy, modify, and distribute this software and its
2113 ** documentation for any purpose and without fee is hereby granted, provided
2114 ** that the above copyright notice appear in all copies and that both that
2115 ** copyright notice and this permission notice appear in supporting
2116 ** documentation.  This software is provided "as is" without express or
2117 ** implied warranty.
2118 **
2119 **
2120 ** -nocenter option added November 1993 by Wolfgang Stuerzlinger,
2121 **  wrzl@gup.uni-linz.ac.at.
2122 **
2123 ** July 2011 afu
2124 ** row converters rewritten, fast PBM-only row converter added,
2125 ** rle compression slightly modified, flate compression added
2126 ** ascii85 output end added.
2127 **
2128 */
2129