]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstops.c
74eee05547a47eafc1578f9fbdfcc938a3203904
[thirdparty/cups.git] / filter / pstops.c
1 /*
2 * "$Id: pstops.c,v 1.92 2002/12/17 16:17:27 mike Exp $"
3 *
4 * PostScript filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2002 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Main entry...
29 * check_range() - Check to see if the current page is selected for
30 * copy_bytes() - Copy bytes from the input file to stdout...
31 * do_prolog() - Send the necessary document prolog commands...
32 * do_setup() - Send the necessary document setup commands...
33 * end_nup() - End processing for N-up printing...
34 * psgets() - Get a line from a file.
35 * start_nup() - Start processing for N-up printing...
36 */
37
38 /*
39 * Include necessary headers...
40 */
41
42 #include "common.h"
43
44
45 /*
46 * Constants...
47 */
48
49 #define MAX_PAGES 10000
50
51 #define BORDER_NONE 0 /* No border or hairline border */
52 #define BORDER_THICK 1 /* Think border */
53 #define BORDER_SINGLE 2 /* Single-line hairline border */
54 #define BORDER_SINGLE2 3 /* Single-line thick border */
55 #define BORDER_DOUBLE 4 /* Double-line hairline border */
56 #define BORDER_DOUBLE2 5 /* Double-line thick border */
57
58 #define LAYOUT_LRBT 0 /* Left to right, bottom to top */
59 #define LAYOUT_LRTB 1 /* Left to right, top to bottom */
60 #define LAYOUT_RLBT 2 /* Right to left, bottom to top */
61 #define LAYOUT_RLTB 3 /* Right to left, top to bottom */
62 #define LAYOUT_BTLR 4 /* Bottom to top, left to right */
63 #define LAYOUT_TBLR 5 /* Top to bottom, left to right */
64 #define LAYOUT_BTRL 6 /* Bottom to top, right to left */
65 #define LAYOUT_TBRL 7 /* Top to bottom, right to left */
66
67 #define LAYOUT_NEGATEY 1
68 #define LAYOUT_NEGATEX 2
69 #define LAYOUT_VERTICAL 4
70
71
72 /*
73 * Globals...
74 */
75
76 int NumPages = 0; /* Number of pages in file */
77 long Pages[MAX_PAGES]; /* Offsets to each page */
78 char PageLabels[MAX_PAGES][64];
79 /* Page labels */
80 const char *PageRanges = NULL; /* Range of pages selected */
81 const char *PageSet = NULL; /* All, Even, Odd pages */
82 int Order = 0, /* 0 = normal, 1 = reverse pages */
83 Flip = 0, /* Flip/mirror pages */
84 NUp = 1, /* Number of pages on each sheet (1, 2, 4) */
85 Collate = 0, /* Collate copies? */
86 Copies = 1, /* Number of copies */
87 UseESPsp = 0, /* Use ESPshowpage? */
88 Border = BORDER_NONE, /* Border around pages */
89 Layout = LAYOUT_LRTB, /* Layout of N-up pages */
90 NormalLandscape = 0; /* Normal rotation for landscape? */
91
92
93 /*
94 * Local functions...
95 */
96
97 static int check_range(int page);
98 static void copy_bytes(FILE *fp, size_t length);
99 static void do_prolog(ppd_file_t *ppd);
100 static void do_setup(ppd_file_t *ppd, int copies, int collate,
101 int slowcollate, float g, float b);
102 static void end_nup(int number);
103 #define is_first_page(p) (NUp == 1 || (((p)+1) % NUp) == 1)
104 #define is_last_page(p) (NUp > 1 && (((p)+1) % NUp) == 0)
105 #define is_not_last_page(p) (NUp > 1 && ((p) % NUp) != 0)
106 static char *psgets(char *buf, size_t len, FILE *fp);
107 static void start_nup(int number, int show_border);
108
109
110 /*
111 * 'main()' - Main entry...
112 */
113
114 int /* O - Exit status */
115 main(int argc, /* I - Number of command-line arguments */
116 char *argv[]) /* I - Command-line arguments */
117 {
118 FILE *fp; /* Print file */
119 ppd_file_t *ppd; /* PPD file */
120 int num_options; /* Number of print options */
121 cups_option_t *options; /* Print options */
122 const char *val; /* Option value */
123 char tempfile[255]; /* Temporary file name */
124 FILE *temp; /* Temporary file */
125 int tempfd; /* Temporary file descriptor */
126 int number; /* Page number */
127 int slowcollate; /* 1 if we need to collate manually */
128 int sloworder; /* 1 if we need to order manually */
129 int slowduplex; /* 1 if we need an even number of pages */
130 char line[8192]; /* Line buffer */
131 float g; /* Gamma correction value */
132 float b; /* Brightness factor */
133 int level; /* Nesting level for embedded files */
134 int nbytes, /* Number of bytes read */
135 tbytes; /* Total bytes to read for binary data */
136 int page; /* Current page sequence number */
137 int real_page; /* "Real" page number in document */
138 int page_count; /* Page count for NUp */
139 int basepage; /* Base page number */
140 int subpage; /* Sub-page number */
141 int copy; /* Current copy */
142 int saweof; /* Did we see a %%EOF tag? */
143 int sent_espsp, /* Did we send the ESPshowpage commands? */
144 sent_prolog, /* Did we send the prolog commands? */
145 sent_setup; /* Did we send the setup commands? */
146
147
148 /*
149 * Make sure status messages are not buffered...
150 */
151
152 setbuf(stderr, NULL);
153
154 /*
155 * Check command-line...
156 */
157
158 if (argc < 6 || argc > 7)
159 {
160 fputs("ERROR: pstops job-id user title copies options [file]\n", stderr);
161 return (1);
162 }
163
164 /*
165 * If we have 7 arguments, print the file named on the command-line.
166 * Otherwise, send stdin instead...
167 */
168
169 if (argc == 6)
170 fp = stdin;
171 else
172 {
173 /*
174 * Try to open the print file...
175 */
176
177 if ((fp = fopen(argv[6], "rb")) == NULL)
178 {
179 fprintf(stderr, "ERROR: unable to open print file \"%s\" - %s\n",
180 argv[6], strerror(errno));
181 return (1);
182 }
183 }
184
185 /*
186 * Process command-line options and write the prolog...
187 */
188
189 g = 1.0;
190 b = 1.0;
191
192 Copies = atoi(argv[4]);
193
194 options = NULL;
195 num_options = cupsParseOptions(argv[5], 0, &options);
196
197 ppd = SetCommonOptions(num_options, options, 1);
198
199 if (ppd && ppd->landscape > 0)
200 NormalLandscape = 1;
201
202 if ((val = cupsGetOption("page-ranges", num_options, options)) != NULL)
203 PageRanges = val;
204
205 if ((val = cupsGetOption("page-set", num_options, options)) != NULL)
206 PageSet = val;
207
208 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
209 {
210 /*
211 * This IPP attribute is unnecessarily complicated...
212 *
213 * single-document, separate-documents-collated-copies, and
214 * single-document-new-sheet all require collated copies.
215 *
216 * separate-documents-uncollated-copies allows for uncollated copies.
217 */
218
219 Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
220 }
221
222 if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
223 strcasecmp(val, "True") == 0)
224 Collate = 1;
225
226 if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL &&
227 strcasecmp(val, "Reverse") == 0)
228 Order = 1;
229
230 if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
231 NUp = atoi(val);
232
233 if ((val = cupsGetOption("page-border", num_options, options)) != NULL)
234 {
235 if (strcasecmp(val, "none") == 0)
236 Border = BORDER_NONE;
237 else if (strcasecmp(val, "single") == 0)
238 Border = BORDER_SINGLE;
239 else if (strcasecmp(val, "single-thick") == 0)
240 Border = BORDER_SINGLE2;
241 else if (strcasecmp(val, "double") == 0)
242 Border = BORDER_DOUBLE;
243 else if (strcasecmp(val, "double-thick") == 0)
244 Border = BORDER_DOUBLE2;
245 }
246
247 if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL)
248 {
249 if (strcasecmp(val, "lrtb") == 0)
250 Layout = LAYOUT_LRTB;
251 else if (strcasecmp(val, "lrbt") == 0)
252 Layout = LAYOUT_LRBT;
253 else if (strcasecmp(val, "rltb") == 0)
254 Layout = LAYOUT_RLTB;
255 else if (strcasecmp(val, "rlbt") == 0)
256 Layout = LAYOUT_RLBT;
257 else if (strcasecmp(val, "tblr") == 0)
258 Layout = LAYOUT_TBLR;
259 else if (strcasecmp(val, "tbrl") == 0)
260 Layout = LAYOUT_TBRL;
261 else if (strcasecmp(val, "btlr") == 0)
262 Layout = LAYOUT_BTLR;
263 else if (strcasecmp(val, "btrl") == 0)
264 Layout = LAYOUT_BTRL;
265 }
266
267 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
268 g = atoi(val) * 0.001f;
269
270 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
271 b = atoi(val) * 0.01f;
272
273 if ((val = cupsGetOption("mirror", num_options, options)) != NULL &&
274 strcasecmp(val, "True") == 0)
275 Flip = 1;
276
277 /*
278 * See if we have to filter the fast or slow way...
279 */
280
281 if (ppd && ppd->manual_copies && Duplex && Copies > 1)
282 {
283 /*
284 * Force collated copies when printing a duplexed document to
285 * a non-PS printer that doesn't do hardware copy generation.
286 * Otherwise the copies will end up on the front/back side of
287 * each page. Also, set the "slowduplex" option to make sure
288 * that we output an even number of pages...
289 */
290
291 Collate = 1;
292 slowduplex = 1;
293 }
294 else
295 slowduplex = 0;
296
297 if (ppdFindOption(ppd, "Collate") == NULL && Collate && Copies > 1)
298 slowcollate = 1;
299 else
300 slowcollate = 0;
301
302 if (ppdFindOption(ppd, "OutputOrder") == NULL && Order)
303 sloworder = 1;
304 else
305 sloworder = 0;
306
307 /*
308 * If we need to filter slowly, then create a temporary file for page data...
309 *
310 * If the temp file can't be created, then we'll ignore the collating/output
311 * order options...
312 */
313
314 if (sloworder || slowcollate)
315 {
316 tempfd = cupsTempFd(tempfile, sizeof(tempfile));
317 if (tempfd < 0)
318 {
319 perror("ERROR: Unable to open temp file");
320 temp = NULL;
321 }
322 else
323 temp = fdopen(tempfd, "wb+");
324
325 if (temp == NULL)
326 slowcollate = sloworder = 0;
327 }
328 else
329 temp = NULL;
330
331 /*
332 * Write any "exit server" options that have been selected...
333 */
334
335 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
336
337 /*
338 * Write any JCL commands that are needed to print PostScript code...
339 */
340
341 ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
342
343 /*
344 * Read the first line to see if we have DSC comments...
345 */
346
347 if (psgets(line, sizeof(line), fp) == NULL)
348 {
349 fputs("ERROR: Empty print file!\n", stderr);
350 ppdClose(ppd);
351 return (1);
352 }
353
354 /*
355 * Start sending the document with any commands needed...
356 */
357
358 fputs(line, stdout);
359
360 saweof = 0;
361 sent_espsp = 0;
362 sent_prolog = 0;
363 sent_setup = 0;
364
365 if (Copies != 1 && (!Collate || !slowcollate))
366 {
367 /*
368 * Tell the document processor the copy and duplex options
369 * that are required...
370 */
371
372 printf("%%%%Requirements: numcopies(%d)%s%s\n", Copies,
373 Collate ? " collate" : "",
374 Duplex ? " duplex" : "");
375
376 /*
377 * Apple uses RBI comments for various non-PPD options...
378 */
379
380 printf("%%RBINumCopies: %d\n", Copies);
381 }
382 else
383 {
384 /*
385 * Tell the document processor the duplex option that is required...
386 */
387
388 if (Duplex)
389 puts("%%Requirements: duplex\n");
390
391 /*
392 * Apple uses RBI comments for various non-PPD options...
393 */
394
395 puts("%RBINumCopies: 1");
396 }
397
398 /*
399 * Figure out if we should use ESPshowpage or not...
400 */
401
402 val = cupsGetOption("page-label", num_options, options);
403
404 if (val != NULL || getenv("CLASSIFICATION") != NULL || NUp > 1 ||
405 Border || strstr(line, "EPS") != NULL)
406 {
407 /*
408 * Yes, use ESPshowpage...
409 */
410
411 UseESPsp = 1;
412 }
413
414 if (strncmp(line, "%!PS-Adobe-", 11) == 0 && strstr(line, "EPSF") == NULL)
415 {
416 /*
417 * OK, we have DSC comments and this isn't an EPS file; read until we
418 * find a %%Page comment...
419 */
420
421 puts("%%Pages: (atend)");
422
423 level = 0;
424
425 while (psgets(line, sizeof(line), fp) != NULL)
426 {
427 if (strncmp(line, "%%", 2) == 0)
428 fprintf(stderr, "DEBUG: %d %s", level, line);
429 else if (line[0] != '%' && line[0] && !sent_espsp && UseESPsp)
430 {
431 /*
432 * Send ESPshowpage stuff...
433 */
434
435 sent_espsp = 1;
436
437 puts("userdict/ESPshowpage/showpage load put\n"
438 "userdict/showpage{}put");
439 }
440
441 if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
442 strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
443 {
444 fputs(line, stdout);
445 level ++;
446 }
447 else if (strncmp(line, "%%EndDocument", 13) == 0 && level > 0)
448 {
449 fputs(line, stdout);
450 level --;
451 }
452 else if (strncmp(line, "%cupsRotation:", 14) == 0 && level == 0)
453 {
454 /*
455 * Reset orientation of document?
456 */
457
458 int orient = (atoi(line + 14) / 90) & 3;
459
460 if (orient != Orientation)
461 {
462 Orientation = (4 - Orientation + orient) & 3;
463 UpdatePageVars();
464 Orientation = orient;
465 }
466 }
467 else if (strncmp(line, "%%BeginProlog", 13) == 0 && level == 0)
468 {
469 /*
470 * Write the existing comment line, and then follow with patches
471 * and prolog commands...
472 */
473
474 fputs(line, stdout);
475
476 if (!sent_prolog)
477 {
478 sent_prolog = 1;
479 do_prolog(ppd);
480 }
481 }
482 else if (strncmp(line, "%%BeginSetup", 12) == 0 && level == 0)
483 {
484 /*
485 * Write the existing comment line, and then follow with document
486 * setup commands...
487 */
488
489 fputs(line, stdout);
490
491 if (!sent_setup)
492 {
493 sent_setup = 1;
494 do_setup(ppd, Copies, Collate, slowcollate, g, b);
495 }
496 }
497 else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
498 break;
499 else if (strncmp(line, "%%BeginBinary:", 14) == 0 ||
500 (strncmp(line, "%%BeginData:", 12) == 0 &&
501 strstr(line, "ASCII") == NULL && strstr(line, "Hex") == NULL))
502 {
503 /*
504 * Copy binary data...
505 */
506
507 tbytes = atoi(strchr(line, ':') + 1);
508 fputs(line, stdout);
509
510 while (tbytes > 0)
511 {
512 if (tbytes > sizeof(line))
513 nbytes = fread(line, 1, sizeof(line), fp);
514 else
515 nbytes = fread(line, 1, tbytes, fp);
516
517 if (nbytes < 1)
518 {
519 perror("ERROR: Early end-of-file while reading binary data");
520 return (1);
521 }
522
523 fwrite(line, 1, nbytes, stdout);
524 tbytes -= nbytes;
525 }
526 }
527 else if (strncmp(line, "%%Pages:", 8) != 0)
528 fputs(line, stdout);
529 }
530
531 /*
532 * Make sure we have the prolog and setup commands written...
533 */
534
535 if (!sent_prolog)
536 {
537 puts("%%BeginProlog");
538
539 sent_prolog = 1;
540 do_prolog(ppd);
541
542 puts("%%EndProlog");
543 }
544
545 if (!sent_setup)
546 {
547 puts("%%BeginSetup");
548
549 sent_setup = 1;
550 do_setup(ppd, Copies, Collate, slowcollate, g, b);
551
552 puts("%%EndSetup");
553 }
554
555 if (!sent_espsp && UseESPsp)
556 {
557 /*
558 * Send ESPshowpage stuff...
559 */
560
561 sent_espsp = 1;
562
563 puts("userdict/ESPshowpage/showpage load put\n"
564 "userdict/showpage{}put");
565 }
566
567 /*
568 * Write the page and label prologs...
569 */
570
571 if (NUp == 2 || NUp == 6)
572 {
573 /*
574 * For 2- and 6-up output, rotate the labels to match the orientation
575 * of the pages...
576 */
577
578 if (Orientation & 1)
579 WriteLabelProlog(val, PageBottom, PageWidth - PageLength + PageTop,
580 PageLength);
581 else
582 WriteLabelProlog(val, PageLeft, PageRight, PageLength);
583 }
584 else
585 WriteLabelProlog(val, PageBottom, PageTop, PageWidth);
586
587 /*
588 * Then read all of the pages, filtering as needed...
589 */
590
591 for (page = 1, real_page = 1;;)
592 {
593 if (strncmp(line, "%%", 2) == 0)
594 fprintf(stderr, "DEBUG: %d %s", level, line);
595
596 if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
597 strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
598 level ++;
599 else if (strncmp(line, "%%EndDocument", 13) == 0 && level > 0)
600 level --;
601 else if (strcmp(line, "\004") == 0)
602 break;
603 else if (strncmp(line, "%%EOF", 5) == 0 && level == 0)
604 {
605 fputs("DEBUG: Saw EOF!\n", stderr);
606 saweof = 1;
607 break;
608 }
609 else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
610 {
611 if (!check_range(real_page))
612 {
613 while (psgets(line, sizeof(line), fp) != NULL)
614 if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
615 strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
616 level ++;
617 else if (strcmp(line, "%%EndDocument") == 0 && level > 0)
618 level --;
619 else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
620 {
621 real_page ++;
622 break;
623 }
624
625 continue;
626 }
627
628 if (!sloworder && NumPages > 0)
629 end_nup(NumPages - 1);
630
631 if (slowcollate || sloworder)
632 Pages[NumPages] = ftell(temp);
633
634 if (!sloworder)
635 {
636 if (is_first_page(NumPages))
637 {
638 if (ppd == NULL || ppd->num_filters == 0)
639 fprintf(stderr, "PAGE: %d %d\n", page, Copies);
640
641 printf("%%%%Page: %d %d\n", page, page);
642 page ++;
643 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
644 }
645
646 start_nup(NumPages, 1);
647 }
648
649 NumPages ++;
650 real_page ++;
651 }
652 else if (strncmp(line, "%%BeginBinary:", 14) == 0 ||
653 (strncmp(line, "%%BeginData:", 12) == 0 &&
654 strstr(line, "ASCII") == NULL && strstr(line, "Hex") == NULL))
655 {
656 /*
657 * Copy binary data...
658 */
659
660 tbytes = atoi(strchr(line, ':') + 1);
661
662 if (!sloworder)
663 fputs(line, stdout);
664 if (slowcollate || sloworder)
665 fputs(line, temp);
666
667 while (tbytes > 0)
668 {
669 if (tbytes > sizeof(line))
670 nbytes = fread(line, 1, sizeof(line), fp);
671 else
672 nbytes = fread(line, 1, tbytes, fp);
673
674 if (nbytes < 1)
675 {
676 perror("ERROR: Early end-of-file while reading binary data");
677 return (1);
678 }
679
680 if (!sloworder)
681 fwrite(line, 1, nbytes, stdout);
682
683 if (slowcollate || sloworder)
684 fwrite(line, 1, nbytes, temp);
685
686 tbytes -= nbytes;
687 }
688 }
689 else if (strncmp(line, "%%Trailer", 9) == 0 && level == 0)
690 {
691 fputs("DEBUG: Saw Trailer!\n", stderr);
692 break;
693 }
694 else
695 {
696 if (!sloworder)
697 fputs(line, stdout);
698
699 if (slowcollate || sloworder)
700 fputs(line, temp);
701 }
702
703 if (psgets(line, sizeof(line), fp) == NULL)
704 break;
705 }
706
707 if (!sloworder)
708 {
709 end_nup(NumPages - 1);
710
711 if (is_not_last_page(NumPages))
712 {
713 start_nup(NUp - 1, 0);
714 end_nup(NUp - 1);
715 }
716
717 if (slowduplex && !(page & 1))
718 {
719 /*
720 * Make sure we have an even number of pages...
721 */
722
723 if (ppd == NULL || ppd->num_filters == 0)
724 fprintf(stderr, "PAGE: %d %d\n", page, Copies);
725
726 printf("%%%%Page: %d %d\n", page, page);
727 page ++;
728 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
729
730 start_nup(NUp - 1, 0);
731 puts("showpage");
732 end_nup(NUp - 1);
733 }
734 }
735
736 if (slowcollate || sloworder)
737 {
738 Pages[NumPages] = ftell(temp);
739
740 if (!sloworder)
741 {
742 while (Copies > 1)
743 {
744 rewind(temp);
745
746 for (number = 0; number < NumPages; number ++)
747 {
748 if (is_first_page(number))
749 {
750 if (ppd == NULL || ppd->num_filters == 0)
751 fprintf(stderr, "PAGE: %d 1\n", page);
752
753 printf("%%%%Page: %d %d\n", page, page);
754 page ++;
755 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
756 }
757
758 start_nup(number, 1);
759 copy_bytes(temp, Pages[number + 1] - Pages[number]);
760 end_nup(number);
761 }
762
763 if (is_not_last_page(NumPages))
764 {
765 start_nup(NUp - 1, 0);
766 end_nup(NUp - 1);
767 }
768
769 if (slowduplex && !(page & 1))
770 {
771 /*
772 * Make sure we have an even number of pages...
773 */
774
775 if (ppd == NULL || ppd->num_filters == 0)
776 fprintf(stderr, "PAGE: %d 1\n", page);
777
778 printf("%%%%Page: %d %d\n", page, page);
779 page ++;
780 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
781
782 start_nup(NUp - 1, 0);
783 puts("showpage");
784 end_nup(NUp - 1);
785 }
786
787 Copies --;
788 }
789 }
790 else
791 {
792 page_count = (NumPages + NUp - 1) / NUp;
793 copy = 0;
794
795 do
796 {
797 if (slowduplex && (page_count & 1))
798 {
799 basepage = page_count - 1;
800 }
801 else
802 basepage = page_count - 1 - slowduplex;
803
804 for (; basepage >= 0; basepage -= 1 + slowduplex)
805 {
806 if (ppd == NULL || ppd->num_filters == 0)
807 fprintf(stderr, "PAGE: %d %d\n", page,
808 slowcollate ? 1 : Copies);
809
810 printf("%%%%Page: %d %d\n", page, page);
811 page ++;
812
813 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
814
815 for (subpage = 0, number = basepage * NUp;
816 subpage < NUp && number < NumPages;
817 subpage ++, number ++)
818 {
819 start_nup(number, 1);
820 fseek(temp, Pages[number], SEEK_SET);
821 copy_bytes(temp, Pages[number + 1] - Pages[number]);
822 end_nup(number);
823 }
824
825 if (is_not_last_page(number))
826 {
827 start_nup(NUp - 1, 0);
828 end_nup(NUp - 1);
829 }
830
831 if (slowduplex)
832 {
833 if (number < NumPages)
834 {
835 if (ppd == NULL || ppd->num_filters == 0)
836 fprintf(stderr, "PAGE: %d %d\n", page,
837 slowcollate ? 1 : Copies);
838
839 printf("%%%%Page: %d %d\n", page, page);
840 page ++;
841
842 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
843
844 for (subpage = 0, number = (basepage + 1) * NUp;
845 subpage < NUp && number < NumPages;
846 subpage ++, number ++)
847 {
848 start_nup(number, 1);
849 fseek(temp, Pages[number], SEEK_SET);
850 copy_bytes(temp, Pages[number + 1] - Pages[number]);
851 end_nup(number);
852 }
853
854 if (is_not_last_page(number))
855 {
856 start_nup(NUp - 1, 0);
857 end_nup(NUp - 1);
858 }
859 }
860 else
861 {
862 /*
863 * Make sure we have an even number of pages...
864 */
865
866 if (ppd == NULL || ppd->num_filters == 0)
867 fprintf(stderr, "PAGE: %d %d\n", page, slowcollate ? 1 : Copies);
868
869 printf("%%%%Page: %d %d\n", page, page);
870 page ++;
871 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
872
873 start_nup(NUp - 1, 0);
874 puts("showpage");
875 end_nup(NUp - 1);
876
877 basepage = page_count - 1;
878 }
879 }
880 }
881
882 copy ++;
883 }
884 while (copy < Copies && slowcollate);
885 }
886 }
887
888 /*
889 * Copy the trailer, if any...
890 */
891
892 puts("%%Trailer");
893 printf("%%%%Pages: %d\n", page - 1);
894
895 if (UseESPsp)
896 puts("userdict/showpage/ESPshowpage load put\n");
897
898 while (psgets(line, sizeof(line), fp) != NULL)
899 {
900 if (strcmp(line, "\004") != 0 &&
901 strncmp(line, "%%Pages:", 8) != 0)
902 fputs(line, stdout);
903
904 if (strncmp(line, "%%EOF", 5) == 0)
905 {
906 fputs("DEBUG: Saw EOF!\n", stderr);
907 saweof = 1;
908 break;
909 }
910 }
911 }
912 else
913 {
914 /*
915 * No DSC comments - write any page commands and then the rest of the file...
916 */
917
918 if (slowcollate && Copies > 1)
919 printf("%%%%Pages: %d\n", Copies);
920 else
921 puts("%%Pages: 1");
922
923 if (UseESPsp)
924 puts("userdict/ESPshowpage/showpage load put\n"
925 "userdict/showpage{}put");
926
927 puts("%%BeginProlog");
928 do_prolog(ppd);
929 puts("%%EndProlog");
930
931 puts("%%BeginSetup");
932 do_setup(ppd, Copies, Collate, slowcollate, g, b);
933 puts("%%EndSetup");
934
935 if (ppd == NULL || ppd->num_filters == 0)
936 fprintf(stderr, "PAGE: 1 %d\n", slowcollate ? 1 : Copies);
937
938 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
939
940 saweof = 1;
941
942 while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0)
943 {
944 fwrite(line, 1, nbytes, stdout);
945
946 if (slowcollate)
947 fwrite(line, 1, nbytes, temp);
948 }
949
950 if (UseESPsp)
951 puts("ESPshowpage");
952
953 if (slowcollate)
954 {
955 while (Copies > 1)
956 {
957 if (ppd == NULL || ppd->num_filters == 0)
958 fputs("PAGE: 1 1\n", stderr);
959
960 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
961 rewind(temp);
962 copy_bytes(temp, 0);
963 Copies --;
964
965 if (UseESPsp)
966 puts("ESPshowpage");
967 }
968 }
969 }
970
971 /*
972 * Send %%EOF if needed...
973 */
974
975 if (!saweof)
976 puts("%%EOF");
977
978 /*
979 * End the job with the appropriate JCL command or CTRL-D otherwise.
980 */
981
982 if (ppd != NULL)
983 {
984 if (ppd->jcl_end)
985 fputs(ppd->jcl_end, stdout);
986 else if (ppd->num_filters == 0)
987 putchar(0x04);
988 }
989
990 /*
991 * Close files and remove the temporary file if needed...
992 */
993
994 if (slowcollate || sloworder)
995 {
996 fclose(temp);
997 unlink(tempfile);
998 }
999
1000 ppdClose(ppd);
1001
1002 if (fp != stdin)
1003 fclose(fp);
1004
1005 return (0);
1006 }
1007
1008
1009 /*
1010 * 'check_range()' - Check to see if the current page is selected for
1011 * printing.
1012 */
1013
1014 static int /* O - 1 if selected, 0 otherwise */
1015 check_range(int page) /* I - Page number */
1016 {
1017 const char *range; /* Pointer into range string */
1018 int lower, upper; /* Lower and upper page numbers */
1019
1020
1021 if (PageSet != NULL)
1022 {
1023 /*
1024 * See if we only print even or odd pages...
1025 */
1026
1027 if (strcasecmp(PageSet, "even") == 0 && ((page - 1) % (NUp << 1)) < NUp)
1028 return (0);
1029 if (strcasecmp(PageSet, "odd") == 0 && ((page - 1) % (NUp << 1)) >= NUp)
1030 return (0);
1031 }
1032
1033 if (PageRanges == NULL)
1034 return (1); /* No range, print all pages... */
1035
1036 for (range = PageRanges; *range != '\0';)
1037 {
1038 if (*range == '-')
1039 {
1040 lower = 1;
1041 range ++;
1042 upper = strtol(range, (char **)&range, 10);
1043 }
1044 else
1045 {
1046 lower = strtol(range, (char **)&range, 10);
1047
1048 if (*range == '-')
1049 {
1050 range ++;
1051 if (!isdigit(*range))
1052 upper = 65535;
1053 else
1054 upper = strtol(range, (char **)&range, 10);
1055 }
1056 else
1057 upper = lower;
1058 }
1059
1060 if (page >= lower && page <= upper)
1061 return (1);
1062
1063 if (*range == ',')
1064 range ++;
1065 else
1066 break;
1067 }
1068
1069 return (0);
1070 }
1071
1072
1073 /*
1074 * 'copy_bytes()' - Copy bytes from the input file to stdout...
1075 */
1076
1077 static void
1078 copy_bytes(FILE *fp, /* I - File to read from */
1079 size_t length) /* I - Length of page data */
1080 {
1081 char buffer[8192]; /* Data buffer */
1082 size_t nbytes, /* Number of bytes read */
1083 nleft; /* Number of bytes left/remaining */
1084
1085
1086 nleft = length;
1087
1088 while (nleft > 0 || length == 0)
1089 {
1090 if (nleft > sizeof(buffer) || length == 0)
1091 nbytes = sizeof(buffer);
1092 else
1093 nbytes = nleft;
1094
1095 if ((nbytes = fread(buffer, 1, nbytes, fp)) < 1)
1096 return;
1097
1098 nleft -= nbytes;
1099
1100 fwrite(buffer, 1, nbytes, stdout);
1101 }
1102 }
1103
1104
1105 /*
1106 * 'do_prolog()' - Send the necessary document prolog commands...
1107 */
1108
1109 static void
1110 do_prolog(ppd_file_t *ppd) /* I - PPD file */
1111 {
1112 /*
1113 * Send the document prolog commands...
1114 */
1115
1116 if (ppd != NULL && ppd->patches != NULL)
1117 {
1118 puts("%%BeginFeature: *JobPatchFile 1");
1119 puts(ppd->patches);
1120 puts("%%EndFeature");
1121 }
1122
1123 ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
1124 }
1125
1126
1127 /*
1128 * 'do_setup()' - Send the necessary document setup commands...
1129 */
1130
1131 static void
1132 do_setup(ppd_file_t *ppd, /* I - PPD file */
1133 int copies, /* I - Number of copies */
1134 int collate, /* I - Collate output? */
1135 int slowcollate, /* I - Slow collate */
1136 float g, /* I - Gamma value */
1137 float b) /* I - Brightness value */
1138 {
1139 /*
1140 * Send all the printer-specific setup commands...
1141 */
1142
1143 ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
1144 ppdEmit(ppd, stdout, PPD_ORDER_ANY);
1145
1146 /*
1147 * Set the number of copies for the job...
1148 */
1149
1150 if (copies != 1 && (!collate || !slowcollate))
1151 {
1152 printf("%%RBIBeginNonPPDFeature: *NumCopies %d\n", copies);
1153 printf("%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse{1 dict begin"
1154 "/NumCopies exch def currentdict end "
1155 "setpagedevice}{userdict/#copies 3 -1 roll put}ifelse\n", copies);
1156 printf("%%RBIEndNonPPDFeature\n");
1157 }
1158
1159 /*
1160 * Changes to the transfer function must be made AFTER any
1161 * setpagedevice code...
1162 */
1163
1164 if (g != 1.0 || b != 1.0)
1165 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
1166 "ifelse %.3f mul } bind settransfer\n", g, b);
1167
1168 /*
1169 * Make sure we have rectclip and rectstroke procedures of some sort...
1170 */
1171
1172 WriteCommon();
1173 }
1174
1175
1176 /*
1177 * 'end_nup()' - End processing for N-up printing...
1178 */
1179
1180 static void
1181 end_nup(int number) /* I - Page number */
1182 {
1183 puts("");
1184
1185 if (Flip || Orientation || NUp > 1)
1186 puts("userdict /ESPsave get restore");
1187
1188 switch (NUp)
1189 {
1190 case 1 :
1191 if (UseESPsp)
1192 {
1193 WriteLabels(Orientation);
1194 puts("ESPshowpage");
1195 }
1196 break;
1197
1198 case 2 :
1199 case 6 :
1200 if (is_last_page(number) && UseESPsp)
1201 {
1202 if (Orientation & 1)
1203 {
1204 /*
1205 * Rotate the labels back to portrait...
1206 */
1207
1208 WriteLabels(Orientation - 1);
1209 }
1210 else if (Orientation == 0)
1211 {
1212 /*
1213 * Rotate the labels to landscape...
1214 */
1215
1216 WriteLabels(NormalLandscape ? 1 : 3);
1217 }
1218 else
1219 {
1220 /*
1221 * Rotate the labels to landscape...
1222 */
1223
1224 WriteLabels(NormalLandscape ? 3 : 1);
1225 }
1226
1227 puts("ESPshowpage");
1228 }
1229 break;
1230
1231 default :
1232 if (is_last_page(number) && UseESPsp)
1233 {
1234 WriteLabels(Orientation);
1235 puts("ESPshowpage");
1236 }
1237 break;
1238 }
1239
1240 fflush(stdout);
1241 }
1242
1243
1244 /*
1245 * 'psgets()' - Get a line from a file.
1246 *
1247 * Note:
1248 *
1249 * This function differs from the gets() function in that it
1250 * handles any combination of CR, LF, or CR LF to end input
1251 * lines.
1252 */
1253
1254 static char * /* O - String or NULL if EOF */
1255 psgets(char *buf, /* I - Buffer to read into */
1256 size_t len, /* I - Length of buffer */
1257 FILE *fp) /* I - File to read from */
1258 {
1259 char *bufptr; /* Pointer into buffer */
1260 int ch; /* Character from file */
1261
1262
1263 len --;
1264 bufptr = buf;
1265 ch = EOF;
1266
1267 while ((bufptr - buf) < len)
1268 {
1269 if ((ch = getc(fp)) == EOF)
1270 break;
1271
1272 if (ch == 0x0d)
1273 {
1274 /*
1275 * Got a CR; see if there is a LF as well...
1276 */
1277
1278 ch = getc(fp);
1279 if (ch != EOF && ch != 0x0a)
1280 ungetc(ch, fp); /* Nope, save it for later... */
1281
1282 ch = 0x0a;
1283 break;
1284 }
1285 else if (ch == 0x0a)
1286 break;
1287 else
1288 *bufptr++ = ch;
1289 }
1290
1291 /*
1292 * Add a trailing newline if it is there...
1293 */
1294
1295 if (ch == '\n')
1296 *bufptr++ = '\n';
1297
1298 /*
1299 * Nul-terminate the string and return it (or NULL for EOF).
1300 */
1301
1302 *bufptr = '\0';
1303
1304 if (ch == EOF && bufptr == buf)
1305 return (NULL);
1306 else
1307 return (buf);
1308 }
1309
1310
1311 /*
1312 * 'start_nup()' - Start processing for N-up printing...
1313 */
1314
1315 static void
1316 start_nup(int number, /* I - Page number */
1317 int show_border) /* I - Show the page border? */
1318 {
1319 int pos; /* Position on page */
1320 int x, y; /* Relative position of subpage */
1321 float w, l, /* Width and length of subpage */
1322 tx, ty; /* Translation values for subpage */
1323 float pw, pl; /* Printable width and length of full page */
1324
1325
1326 if (Flip || Orientation || NUp > 1)
1327 puts("userdict/ESPsave save put");
1328
1329 if (Flip)
1330 printf("%.1f 0.0 translate -1 1 scale\n", PageWidth);
1331
1332 pos = number % NUp;
1333 pw = PageRight - PageLeft;
1334 pl = PageTop - PageBottom;
1335
1336 fprintf(stderr, "DEBUG: pw = %.1f, pl = %.1f\n", pw, pl);
1337 fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", PageLeft, PageRight);
1338 fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", PageTop, PageBottom);
1339 fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", PageWidth, PageLength);
1340
1341 switch (Orientation)
1342 {
1343 case 1 : /* Landscape */
1344 printf("%.1f 0.0 translate 90 rotate\n", PageLength);
1345 break;
1346 case 2 : /* Reverse Portrait */
1347 printf("%.1f %.1f translate 180 rotate\n", PageWidth, PageLength);
1348 break;
1349 case 3 : /* Reverse Landscape */
1350 printf("0.0 %.1f translate -90 rotate\n", PageWidth);
1351 break;
1352 }
1353
1354 if (Duplex && NUp > 1 && ((number / NUp) & 1))
1355 printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
1356 else if (NUp > 1)
1357 printf("%.1f %.1f translate\n", PageLeft, PageBottom);
1358
1359 switch (NUp)
1360 {
1361 default :
1362 w = PageWidth;
1363 l = PageLength;
1364 break;
1365
1366 case 2 :
1367 if (Orientation & 1)
1368 {
1369 x = pos & 1;
1370
1371 if (Layout & LAYOUT_NEGATEY)
1372 x = 1 - x;
1373
1374 w = pl;
1375 l = w * PageLength / PageWidth;
1376
1377 if (l > (pw * 0.5))
1378 {
1379 l = pw * 0.5;
1380 w = l * PageWidth / PageLength;
1381 }
1382
1383 tx = 0.5 * (pw * 0.5 - l);
1384 ty = 0.5 * (pl - w);
1385
1386 if (NormalLandscape)
1387 printf("0.0 %.1f translate -90 rotate\n", pl);
1388 else
1389 printf("%.1f 0.0 translate 90 rotate\n", pw);
1390
1391 printf("%.1f %.1f translate %.3f %.3f scale\n",
1392 ty, tx + l * x, w / PageWidth, l / PageLength);
1393 }
1394 else
1395 {
1396 x = pos & 1;
1397
1398 if (Layout & LAYOUT_NEGATEX)
1399 x = 1 - x;
1400
1401 l = pw;
1402 w = l * PageWidth / PageLength;
1403
1404 if (w > (pl * 0.5))
1405 {
1406 w = pl * 0.5;
1407 l = w * PageLength / PageWidth;
1408 }
1409
1410 tx = 0.5 * (pl * 0.5 - w);
1411 ty = 0.5 * (pw - l);
1412
1413 if (NormalLandscape)
1414 printf("%.1f 0.0 translate 90 rotate\n", pw);
1415 else
1416 printf("0.0 %.1f translate -90 rotate\n", pl);
1417
1418 printf("%.1f %.1f translate %.3f %.3f scale\n",
1419 tx + w * x, ty, w / PageWidth, l / PageLength);
1420 }
1421 break;
1422
1423 case 4 :
1424 if (Layout & LAYOUT_VERTICAL)
1425 {
1426 x = (pos / 2) & 1;
1427 y = pos & 1;
1428 }
1429 else
1430 {
1431 x = pos & 1;
1432 y = (pos / 2) & 1;
1433 }
1434
1435 if (Layout & LAYOUT_NEGATEX)
1436 x = 1 - x;
1437
1438 if (Layout & LAYOUT_NEGATEY)
1439 y = 1 - y;
1440
1441 w = pw * 0.5;
1442 l = w * PageLength / PageWidth;
1443
1444 if (l > (pl * 0.5))
1445 {
1446 l = pl * 0.5;
1447 w = l * PageWidth / PageLength;
1448 }
1449
1450 tx = 0.5 * (pw * 0.5 - w);
1451 ty = 0.5 * (pl * 0.5 - l);
1452
1453 printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
1454 w / PageWidth, l / PageLength);
1455 break;
1456
1457 case 6 :
1458 if (Orientation & 1)
1459 {
1460 if (Layout & LAYOUT_VERTICAL)
1461 {
1462 x = pos / 3;
1463 y = pos % 3;
1464
1465 if (Layout & LAYOUT_NEGATEX)
1466 x = 1 - x;
1467
1468 if (Layout & LAYOUT_NEGATEY)
1469 y = 2 - y;
1470 }
1471 else
1472 {
1473 x = pos & 1;
1474 y = pos / 2;
1475
1476 if (Layout & LAYOUT_NEGATEX)
1477 x = 1 - x;
1478
1479 if (Layout & LAYOUT_NEGATEY)
1480 y = 2 - y;
1481 }
1482
1483 w = pl * 0.5;
1484 l = w * PageLength / PageWidth;
1485
1486 if (l > (pw * 0.333))
1487 {
1488 l = pw * 0.333;
1489 w = l * PageWidth / PageLength;
1490 }
1491
1492 tx = 0.5 * (pl - 2 * w);
1493 ty = 0.5 * (pw - 3 * l);
1494
1495 if (NormalLandscape)
1496 printf("0.0 %.1f translate -90 rotate\n", pl);
1497 else
1498 printf("%.1f 0.0 translate 90 rotate\n", pw);
1499
1500 printf("%.1f %.1f translate %.3f %.3f scale\n",
1501 tx + x * w, ty + y * l, w / PageWidth, l / PageLength);
1502 }
1503 else
1504 {
1505 if (Layout & LAYOUT_VERTICAL)
1506 {
1507 x = pos / 2;
1508 y = pos & 1;
1509
1510 if (Layout & LAYOUT_NEGATEX)
1511 x = 2 - x;
1512
1513 if (Layout & LAYOUT_NEGATEY)
1514 y = 1 - y;
1515 }
1516 else
1517 {
1518 x = pos % 3;
1519 y = pos / 3;
1520
1521 if (Layout & LAYOUT_NEGATEX)
1522 x = 2 - x;
1523
1524 if (Layout & LAYOUT_NEGATEY)
1525 y = 1 - y;
1526 }
1527
1528 l = pw * 0.5;
1529 w = l * PageWidth / PageLength;
1530
1531 if (w > (pl * 0.333))
1532 {
1533 w = pl * 0.333;
1534 l = w * PageLength / PageWidth;
1535 }
1536
1537 tx = 0.5 * (pl - 3 * w);
1538 ty = 0.5 * (pw - 2 * l);
1539
1540 if (NormalLandscape)
1541 printf("%.1f 0.0 translate 90 rotate\n", pw);
1542 else
1543 printf("0.0 %.1f translate -90 rotate\n", pl);
1544
1545 printf("%.1f %.1f translate %.3f %.3f scale\n",
1546 tx + w * x, ty + l * y, w / PageWidth, l / PageLength);
1547 }
1548 break;
1549
1550 case 9 :
1551 if (Layout & LAYOUT_VERTICAL)
1552 {
1553 x = (pos / 3) % 3;
1554 y = pos % 3;
1555 }
1556 else
1557 {
1558 x = pos % 3;
1559 y = (pos / 3) % 3;
1560 }
1561
1562 if (Layout & LAYOUT_NEGATEX)
1563 x = 2 - x;
1564
1565 if (Layout & LAYOUT_NEGATEY)
1566 y = 2 - y;
1567
1568 w = pw * 0.333;
1569 l = w * PageLength / PageWidth;
1570
1571 if (l > (pl * 0.333))
1572 {
1573 l = pl * 0.333;
1574 w = l * PageWidth / PageLength;
1575 }
1576
1577 tx = 0.5 * (pw * 0.333 - w);
1578 ty = 0.5 * (pl * 0.333 - l);
1579
1580 printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
1581 w / PageWidth, l / PageLength);
1582 break;
1583
1584 case 16 :
1585 if (Layout & LAYOUT_VERTICAL)
1586 {
1587 x = (pos / 4) & 3;
1588 y = pos & 3;
1589 }
1590 else
1591 {
1592 x = pos & 3;
1593 y = (pos / 4) & 3;
1594 }
1595
1596 if (Layout & LAYOUT_NEGATEX)
1597 x = 3 - x;
1598
1599 if (Layout & LAYOUT_NEGATEY)
1600 y = 3 - y;
1601
1602 w = pw * 0.25;
1603 l = w * PageLength / PageWidth;
1604
1605 if (l > (pl * 0.25))
1606 {
1607 l = pl * 0.25;
1608 w = l * PageWidth / PageLength;
1609 }
1610
1611 tx = 0.5 * (pw * 0.25 - w);
1612 ty = 0.5 * (pl * 0.25 - l);
1613
1614 printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
1615 w / PageWidth, l / PageLength);
1616 break;
1617 }
1618
1619 /*
1620 * Draw borders as necessary...
1621 */
1622
1623 if (Border && show_border)
1624 {
1625 int rects; /* Number of border rectangles */
1626 float fscale, /* Scaling value for points */
1627 margin; /* Current margin for borders */
1628
1629
1630 rects = (Border & BORDER_DOUBLE) ? 2 : 1;
1631 fscale = PageWidth / w;
1632 margin = 2.25 * fscale;
1633
1634 /*
1635 * Set the line width and color...
1636 */
1637
1638 puts("gsave");
1639 printf("%.3f setlinewidth 0 setgray newpath\n",
1640 (Border & BORDER_THICK) ? 0.5 * fscale : 0.24 * fscale);
1641
1642 /*
1643 * Draw border boxes...
1644 */
1645
1646 for (; rects > 0; rects --, margin += 2 * fscale)
1647 if (NUp > 1)
1648 printf("%.1f %.1f %.1f %.1f ESPrs\n",
1649 margin,
1650 margin,
1651 PageWidth - 2 * margin,
1652 PageLength - 2 * margin);
1653 else
1654 printf("%.1f %.1f %.1f %.1f ESPrs\n",
1655 PageLeft + margin,
1656 PageBottom + margin,
1657 PageRight - PageLeft - 2 * margin,
1658 PageTop - PageBottom - 2 * margin);
1659
1660 /*
1661 * Restore pen settings...
1662 */
1663
1664 puts("grestore");
1665 }
1666
1667 if (NUp > 1)
1668 {
1669 /*
1670 * Clip the page that follows to the bounding box of the page...
1671 */
1672
1673 printf("0 0 %.1f %.1f ESPrc\n", PageWidth, PageLength);
1674 }
1675 }
1676
1677
1678 /*
1679 * End of "$Id: pstops.c,v 1.92 2002/12/17 16:17:27 mike Exp $".
1680 */