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, ¬urn, 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, ¢er, 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