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