]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstops.c
Add Classification directive and page-label attribute support.
[thirdparty/cups.git] / filter / pstops.c
1 /*
2 * "$Id: pstops.c,v 1.53 2001/03/14 13:45:33 mike Exp $"
3 *
4 * PostScript filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2001 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 * Contents:
25 *
26 * main() - Main entry...
27 * check_range() - Check to see if the current page is selected for
28 * copy_bytes() - Copy bytes from the input file to stdout...
29 * end_nup() - End processing for N-up printing...
30 * psgets() - Get a line from a file.
31 * start_nup() - Start processing for N-up printing...
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "common.h"
39
40
41 /*
42 * Constants...
43 */
44
45 #define MAX_PAGES 10000
46
47
48 /*
49 * Globals...
50 */
51
52 int NumPages = 0; /* Number of pages in file */
53 long Pages[MAX_PAGES]; /* Offsets to each page */
54 char PageLabels[MAX_PAGES][64];
55 /* Page labels */
56 const char *PageRanges = NULL; /* Range of pages selected */
57 const char *PageSet = NULL; /* All, Even, Odd pages */
58 int Order = 0, /* 0 = normal, 1 = reverse pages */
59 Flip = 0, /* Flip/mirror pages */
60 NUp = 1, /* Number of pages on each sheet (1, 2, 4) */
61 Collate = 0, /* Collate copies? */
62 Copies = 1; /* Number of copies */
63
64
65 /*
66 * Local functions...
67 */
68
69 static int check_range(int page);
70 static void copy_bytes(FILE *fp, size_t length);
71 static void end_nup(int number);
72 static char *psgets(char *buf, size_t len, FILE *fp);
73 static void start_nup(int number);
74
75
76 /*
77 * 'main()' - Main entry...
78 */
79
80 int /* O - Exit status */
81 main(int argc, /* I - Number of command-line arguments */
82 char *argv[]) /* I - Command-line arguments */
83 {
84 FILE *fp; /* Print file */
85 ppd_file_t *ppd; /* PPD file */
86 int num_options; /* Number of print options */
87 cups_option_t *options; /* Print options */
88 const char *val; /* Option value */
89 char tempfile[255]; /* Temporary file name */
90 FILE *temp; /* Temporary file */
91 int tempfd; /* Temporary file descriptor */
92 int number; /* Page number */
93 int slowcollate; /* 1 if we need to collate manually */
94 int sloworder; /* 1 if we need to order manually */
95 char line[8192]; /* Line buffer */
96 float g; /* Gamma correction value */
97 float b; /* Brightness factor */
98 int level; /* Nesting level for embedded files */
99 int nbytes, /* Number of bytes read */
100 tbytes; /* Total bytes to read for binary data */
101 int page; /* Current page sequence number */
102 int page_count; /* Page count for NUp */
103 int subpage; /* Sub-page number */
104 int copy; /* Current copy */
105 int saweof; /* Did we see a %%EOF tag? */
106
107
108 /*
109 * Make sure status messages are not buffered...
110 */
111
112 setbuf(stderr, NULL);
113
114 /*
115 * Check command-line...
116 */
117
118 if (argc < 6 || argc > 7)
119 {
120 fputs("ERROR: pstops job-id user title copies options [file]\n", stderr);
121 return (1);
122 }
123
124 /*
125 * If we have 7 arguments, print the file named on the command-line.
126 * Otherwise, send stdin instead...
127 */
128
129 if (argc == 6)
130 fp = stdin;
131 else
132 {
133 /*
134 * Try to open the print file...
135 */
136
137 if ((fp = fopen(argv[6], "rb")) == NULL)
138 {
139 perror("ERROR: unable to open print file - ");
140 return (1);
141 }
142 }
143
144 /*
145 * Process command-line options and write the prolog...
146 */
147
148 g = 1.0;
149 b = 1.0;
150
151 Copies = atoi(argv[4]);
152
153 options = NULL;
154 num_options = cupsParseOptions(argv[5], 0, &options);
155
156 ppd = SetCommonOptions(num_options, options, 1);
157
158 if ((val = cupsGetOption("page-ranges", num_options, options)) != NULL)
159 PageRanges = val;
160
161 if ((val = cupsGetOption("page-set", num_options, options)) != NULL)
162 PageSet = val;
163
164 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
165 {
166 /*
167 * This IPP attribute is unnecessarily complicated...
168 *
169 * single-document, separate-documents-collated-copies, and
170 * single-document-new-sheet all require collated copies.
171 *
172 * separate-documents-uncollated-copies allows for uncollated copies.
173 */
174
175 Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
176 }
177
178 if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
179 strcasecmp(val, "True") == 0)
180 Collate = 1;
181
182 if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL &&
183 strcasecmp(val, "Reverse") == 0)
184 Order = 1;
185
186 if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
187 NUp = atoi(val);
188
189 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
190 g = atoi(val) * 0.001f;
191
192 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
193 b = atoi(val) * 0.01f;
194
195 /*
196 * See if we have to filter the fast or slow way...
197 */
198
199 if (ppdFindOption(ppd, "Collate") == NULL && Collate && Copies > 1)
200 slowcollate = 1;
201 else
202 slowcollate = 0;
203
204 if (ppdFindOption(ppd, "OutputOrder") == NULL && Order)
205 sloworder = 1;
206 else
207 sloworder = 0;
208
209 /*
210 * If we need to filter slowly, then create a temporary file for page data...
211 *
212 * If the temp file can't be created, then we'll ignore the collating/output
213 * order options...
214 */
215
216 if (sloworder || slowcollate)
217 {
218 tempfd = cupsTempFd(tempfile, sizeof(tempfile));
219 temp = fdopen(tempfd, "wb+");
220
221 if (temp == NULL)
222 slowcollate = sloworder = 0;
223 }
224 else
225 temp = NULL;
226
227 /*
228 * Write any "exit server" options that have been selected...
229 */
230
231 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
232
233 /*
234 * Write any JCL commands that are needed to print PostScript code...
235 */
236
237 ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
238
239 /*
240 * Read the first line to see if we have DSC comments...
241 */
242
243 if (psgets(line, sizeof(line), fp) == NULL)
244 {
245 fputs("ERROR: Empty print file!\n", stderr);
246 ppdClose(ppd);
247 return (1);
248 }
249
250 /*
251 * Start sending the document with any commands needed...
252 */
253
254 puts(line);
255
256 saweof = 0;
257
258 if (ppd != NULL && ppd->patches != NULL)
259 puts(ppd->patches);
260
261 ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
262 ppdEmit(ppd, stdout, PPD_ORDER_ANY);
263 ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
264
265 puts("userdict begin\n"
266 "/ESPshowpage /showpage load def\n"
267 "/showpage { } def\n"
268 "end");
269
270 if (g != 1.0 || b != 1.0)
271 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
272 "ifelse %.3f mul } bind settransfer\n", g, b);
273
274 WriteLabelProlog(cupsGetOption("page-label", num_options, options));
275
276 if (Copies > 1 && (!Collate || !slowcollate))
277 {
278 if (ppd == NULL || ppd->language_level == 1)
279 printf("/#copies %d def\n", Copies);
280 else
281 printf("<</NumCopies %d>>setpagedevice\n", Copies);
282 }
283
284 if (strncmp(line, "%!PS-Adobe-", 11) == 0)
285 {
286 /*
287 * OK, we have DSC comments; read until we find a %%Page comment...
288 */
289
290 level = 0;
291
292 while (psgets(line, sizeof(line), fp) != NULL)
293 if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
294 strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
295 level ++;
296 else if (strcmp(line, "%%EndDocument") == 0 && level > 0)
297 level --;
298 else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
299 break;
300 else if (strncmp(line, "%%BeginBinary:", 14) == 0 ||
301 (strncmp(line, "%%BeginData:", 12) == 0 &&
302 strstr(line, "Binary") != NULL))
303 {
304 /*
305 * Copy binary data...
306 */
307
308 tbytes = atoi(strchr(line, ':') + 1);
309 while (tbytes > 0)
310 {
311 if (tbytes > sizeof(line))
312 nbytes = fread(line, 1, sizeof(line), fp);
313 else
314 nbytes = fread(line, 1, tbytes, fp);
315
316 fwrite(line, 1, nbytes, stdout);
317 tbytes -= nbytes;
318 }
319 }
320 else
321 fputs(line, stdout);
322
323 /*
324 * Then read all of the pages, filtering as needed...
325 */
326
327 for (page = 1;;)
328 {
329 if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
330 strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
331 level ++;
332 else if (strcmp(line, "%%EndDocument") == 0 && level > 0)
333 level --;
334 else if (strcmp(line, "%%EOF") == 0 && level == 0)
335 saweof = 1;
336 else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
337 {
338 if (sscanf(line, "%*s%*s%d", &number) == 1)
339 {
340 if (!check_range(number))
341 {
342 while (psgets(line, sizeof(line), fp) != NULL)
343 if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
344 strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
345 level ++;
346 else if (strcmp(line, "%%EndDocument") == 0 && level > 0)
347 level --;
348 else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
349 break;
350
351 continue;
352 }
353
354 if (!sloworder && NumPages > 0)
355 end_nup(NumPages - 1);
356
357 if (slowcollate || sloworder)
358 Pages[NumPages] = ftell(temp);
359
360 if (!sloworder)
361 {
362 if ((NumPages & (NUp - 1)) == 0)
363 {
364 if (ppd == NULL || ppd->num_filters == 0)
365 fprintf(stderr, "PAGE: %d %d\n", page, Copies);
366
367 printf("%%%%Page: %d %d\n", page, page);
368 page ++;
369 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
370 }
371
372 start_nup(NumPages);
373 }
374
375 NumPages ++;
376 }
377 }
378 else if (strncmp(line, "%%BeginBinary:", 14) == 0 ||
379 (strncmp(line, "%%BeginData:", 12) == 0 &&
380 strstr(line, "Binary") != NULL))
381 {
382 /*
383 * Copy binary data...
384 */
385
386 tbytes = atoi(strchr(line, ':') + 1);
387 while (tbytes > 0)
388 {
389 if (tbytes > sizeof(line))
390 nbytes = fread(line, 1, sizeof(line), fp);
391 else
392 nbytes = fread(line, 1, tbytes, fp);
393
394 if (!sloworder)
395 fwrite(line, 1, nbytes, stdout);
396
397 if (slowcollate || sloworder)
398 fwrite(line, 1, nbytes, stdout);
399
400 tbytes -= nbytes;
401 }
402 }
403 else if (strcmp(line, "%%Trailer") == 0 && level == 0)
404 break;
405 else
406 {
407 if (!sloworder)
408 fputs(line, stdout);
409
410 if (slowcollate || sloworder)
411 fputs(line, temp);
412 }
413
414 if (psgets(line, sizeof(line), fp) == NULL)
415 break;
416 }
417
418 if (!sloworder)
419 {
420 end_nup(NumPages - 1);
421
422 if (NumPages & (NUp - 1))
423 {
424 start_nup(NUp - 1);
425 end_nup(NUp - 1);
426 }
427 }
428
429 if (slowcollate || sloworder)
430 {
431 Pages[NumPages] = ftell(temp);
432 page = 1;
433
434 if (!sloworder)
435 {
436 while (Copies > 0)
437 {
438 rewind(temp);
439
440 for (number = 0; number < NumPages; number ++)
441 {
442 if ((number & (NUp - 1)) == 0)
443 {
444 if (ppd == NULL || ppd->num_filters == 0)
445 fprintf(stderr, "PAGE: %d 1\n", page);
446
447 printf("%%%%Page: %d %d\n", page, page);
448 page ++;
449 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
450 }
451
452 start_nup(number);
453 copy_bytes(temp, Pages[number + 1] - Pages[number]);
454 end_nup(number);
455 }
456
457 if (NumPages & (NUp - 1))
458 {
459 start_nup(NUp - 1);
460 end_nup(NUp - 1);
461 }
462
463 Copies --;
464 }
465 }
466 else
467 {
468 page_count = (NumPages + NUp - 1) / NUp;
469 copy = 0;
470
471 do
472 {
473 for (page = page_count - 1; page >= 0; page --)
474 {
475 if (ppd == NULL || ppd->num_filters == 0)
476 fprintf(stderr, "PAGE: %d %d\n", page + 1,
477 slowcollate ? 1 : Copies);
478
479 if (slowcollate)
480 printf("%%%%Page: %d %d\n", page + 1,
481 page_count - page + copy * page_count);
482 else
483 printf("%%%%Page: %d %d\n", page + 1, page_count - page);
484
485 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
486
487 for (subpage = 0, number = page * NUp;
488 subpage < NUp && number < NumPages;
489 subpage ++, number ++)
490 {
491 start_nup(number);
492 fseek(temp, Pages[number], SEEK_SET);
493 copy_bytes(temp, Pages[number + 1] - Pages[number]);
494 end_nup(number);
495 }
496
497 if (number & (NUp - 1))
498 {
499 start_nup(NUp - 1);
500 end_nup(NUp - 1);
501 }
502 }
503
504 copy ++;
505 }
506 while (copy < Copies && slowcollate);
507 }
508 }
509
510 /*
511 * Copy the trailer, if any...
512 */
513
514 while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0)
515 fwrite(line, 1, nbytes, stdout);
516 }
517 else
518 {
519 /*
520 * No DSC comments - write any page commands and then the rest of the file...
521 */
522
523 if (ppd == NULL || ppd->num_filters == 0)
524 fprintf(stderr, "PAGE: 1 %d\n", slowcollate ? 1 : Copies);
525
526 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
527
528 while (psgets(line, sizeof(line), fp) != NULL)
529 {
530 fputs(line, stdout);
531
532 if (slowcollate)
533 fputs(line, temp);
534 }
535
536 if (slowcollate)
537 {
538 while (Copies > 1)
539 {
540 if (ppd == NULL || ppd->num_filters == 0)
541 fputs("PAGE: 1 1\n", stderr);
542
543 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
544 rewind(temp);
545 copy_bytes(temp, 0);
546 Copies --;
547 }
548 }
549 }
550
551 /*
552 * Send %%EOF if needed...
553 */
554
555 if (!saweof)
556 puts("%%EOF");
557
558 /*
559 * End the job with the appropriate JCL command or CTRL-D otherwise.
560 */
561
562 if (ppd != NULL && ppd->jcl_end)
563 fputs(ppd->jcl_end, stdout);
564 else
565 putchar(0x04);
566
567 /*
568 * Close files and remove the temporary file if needed...
569 */
570
571 if (slowcollate || sloworder)
572 {
573 fclose(temp);
574 unlink(tempfile);
575 }
576
577 ppdClose(ppd);
578
579 if (fp != stdin)
580 fclose(fp);
581
582 return (0);
583 }
584
585
586 /*
587 * 'check_range()' - Check to see if the current page is selected for
588 * printing.
589 */
590
591 static int /* O - 1 if selected, 0 otherwise */
592 check_range(int page) /* I - Page number */
593 {
594 const char *range; /* Pointer into range string */
595 int lower, upper; /* Lower and upper page numbers */
596
597
598 if (PageSet != NULL)
599 {
600 /*
601 * See if we only print even or odd pages...
602 */
603
604 if (strcasecmp(PageSet, "even") == 0 && (page & 1))
605 return (0);
606 if (strcasecmp(PageSet, "odd") == 0 && !(page & 1))
607 return (0);
608 }
609
610 if (PageRanges == NULL)
611 return (1); /* No range, print all pages... */
612
613 for (range = PageRanges; *range != '\0';)
614 {
615 if (*range == '-')
616 {
617 lower = 1;
618 range ++;
619 upper = strtol(range, (char **)&range, 10);
620 }
621 else
622 {
623 lower = strtol(range, (char **)&range, 10);
624
625 if (*range == '-')
626 {
627 range ++;
628 if (!isdigit(*range))
629 upper = 65535;
630 else
631 upper = strtol(range, (char **)&range, 10);
632 }
633 else
634 upper = lower;
635 }
636
637 if (page >= lower && page <= upper)
638 return (1);
639
640 if (*range == ',')
641 range ++;
642 else
643 break;
644 }
645
646 return (0);
647 }
648
649
650 /*
651 * 'copy_bytes()' - Copy bytes from the input file to stdout...
652 */
653
654 static void
655 copy_bytes(FILE *fp, /* I - File to read from */
656 size_t length) /* I - Length of page data */
657 {
658 char buffer[8192]; /* Data buffer */
659 size_t nbytes, /* Number of bytes read */
660 nleft; /* Number of bytes left/remaining */
661
662
663 nleft = length;
664
665 while (nleft > 0 || length == 0)
666 {
667 if (nleft > sizeof(buffer))
668 nbytes = sizeof(buffer);
669 else
670 nbytes = nleft;
671
672 if ((nbytes = fread(buffer, 1, nbytes, fp)) < 1)
673 return;
674
675 nleft -= nbytes;
676
677 fwrite(buffer, 1, nbytes, stdout);
678 }
679 }
680
681
682 /*
683 * 'end_nup()' - End processing for N-up printing...
684 */
685
686 static void
687 end_nup(int number) /* I - Page number */
688 {
689 if (Flip || Orientation || NUp > 1)
690 puts("ESPsave restore");
691
692 switch (NUp)
693 {
694 case 1 :
695 WriteLabels();
696 puts("ESPshowpage");
697 break;
698
699 case 2 :
700 if ((number & 1) == 1)
701 {
702 WriteLabels();
703 puts("ESPshowpage");
704 }
705 break;
706
707 case 4 :
708 if ((number & 3) == 3)
709 {
710 WriteLabels();
711 puts("ESPshowpage");
712 }
713 break;
714 }
715 }
716
717
718 /*
719 * 'psgets()' - Get a line from a file.
720 *
721 * Note:
722 *
723 * This function differs from the gets() function in that it
724 * handles any combination of CR, LF, or CR LF to end input
725 * lines.
726 */
727
728 static char * /* O - String or NULL if EOF */
729 psgets(char *buf, /* I - Buffer to read into */
730 size_t len, /* I - Length of buffer */
731 FILE *fp) /* I - File to read from */
732 {
733 char *bufptr; /* Pointer into buffer */
734 int ch; /* Character from file */
735
736
737 len --;
738 bufptr = buf;
739 ch = EOF;
740
741 while ((bufptr - buf) < len)
742 {
743 if ((ch = getc(fp)) == EOF)
744 break;
745
746 if (ch == 0x0d)
747 {
748 /*
749 * Got a CR; see if there is a LF as well...
750 */
751
752 ch = getc(fp);
753 if (ch != EOF && ch != 0x0a)
754 ungetc(ch, fp); /* Nope, save it for later... */
755
756 ch = 0x0a;
757 break;
758 }
759 else if (ch == 0x0a)
760 break;
761 else
762 *bufptr++ = ch;
763 }
764
765 /*
766 * Add a trailing newline if it is there...
767 */
768
769 if (ch == '\n')
770 *bufptr++ = '\n';
771
772 /*
773 * Nul-terminate the string and return it (or NULL for EOF).
774 */
775
776 *bufptr = '\0';
777
778 if (ch == EOF && bufptr == buf)
779 return (NULL);
780 else
781 return (buf);
782 }
783
784
785 /*
786 * 'start_nup()' - Start processing for N-up printing...
787 */
788
789 static void
790 start_nup(int number) /* I - Page number */
791 {
792 int x, y; /* Relative position of subpage */
793 float w, l, /* Width and length of subpage */
794 tx, ty; /* Translation values for subpage */
795 float pw, pl; /* Printable width and length of full page */
796
797
798 if (Flip || Orientation || NUp > 1)
799 puts("/ESPsave save def");
800
801 if (Flip)
802 printf("%.1f 0.0 translate -1 1 scale\n", PageWidth);
803
804 pw = PageRight - PageLeft;
805 pl = PageTop - PageBottom;
806
807 fprintf(stderr, "DEBUG: pw = %.1f, pl = %.1f\n", pw, pl);
808 fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", PageLeft, PageRight);
809 fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", PageTop, PageBottom);
810 fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", PageWidth, PageLength);
811
812 switch (Orientation)
813 {
814 case 1 : /* Landscape */
815 printf("%.1f 0.0 translate 90 rotate\n", PageLength);
816 break;
817 case 2 : /* Reverse Portrait */
818 printf("%.1f %.1f translate 180 rotate\n", PageWidth, PageLength);
819 break;
820 case 3 : /* Reverse Landscape */
821 printf("0.0 %.1f translate -90 rotate\n", PageWidth);
822 break;
823 }
824
825 switch (NUp)
826 {
827 case 2 :
828 x = number & 1;
829
830 if (Orientation & 1)
831 {
832 x = 1 - x;
833 w = pl;
834 l = w * PageLength / PageWidth;
835
836 if (l > (pw * 0.5))
837 {
838 l = pw * 0.5;
839 w = l * PageWidth / PageLength;
840 }
841
842 tx = pw * 0.5 - l;
843 ty = (pl - w) * 0.5;
844 }
845 else
846 {
847 l = pw;
848 w = l * PageWidth / PageLength;
849
850 if (w > (pl * 0.5))
851 {
852 w = pl * 0.5;
853 l = w * PageLength / PageWidth;
854 }
855
856 tx = pl * 0.5 - w;
857 ty = (pw - l) * 0.5;
858 }
859
860 if (Duplex && (number & 2))
861 printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
862 else
863 printf("%.1f %.1f translate\n", PageLeft, PageBottom);
864
865 if (Orientation & 1)
866 {
867 printf("0.0 %.1f translate -90 rotate\n", pl);
868 printf("%.1f %.1f translate %.3f %.3f scale\n",
869 ty, tx + l * x, w / PageWidth, l / PageLength);
870 }
871 else
872 {
873 printf("%.1f 0.0 translate 90 rotate\n", pw);
874 printf("%.1f %.1f translate %.3f %.3f scale\n",
875 tx + w * x, ty, w / PageWidth, l / PageLength);
876 }
877
878 printf("newpath\n"
879 "0.0 0.0 moveto\n"
880 "%.1f 0.0 lineto\n"
881 "%.1f %.1f lineto\n"
882 "0.0 %.1f lineto\n"
883 "closepath clip newpath\n",
884 PageWidth, PageWidth, PageLength, PageLength);
885 break;
886
887 case 4 :
888 x = number & 1;
889 y = 1 - ((number & 2) != 0);
890
891 w = pw * 0.5;
892 l = w * PageLength / PageWidth;
893
894 if (l > (pl * 0.5))
895 {
896 l = pl * 0.5;
897 w = l * PageWidth / PageLength;
898 }
899
900 if (Duplex && (number & 4))
901 printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
902 else
903 printf("%.1f %.1f translate\n", PageLeft, PageBottom);
904
905 printf("%.1f %.1f translate %.3f %.3f scale\n", x * w, y * l,
906 w / PageWidth, l / PageLength);
907 printf("newpath\n"
908 "0.0 0.0 moveto\n"
909 "%.1f 0.0 lineto\n"
910 "%.1f %.1f lineto\n"
911 "0.0 %.1f lineto\n"
912 "closepath clip newpath\n",
913 PageWidth, PageWidth, PageLength, PageLength);
914 break;
915 }
916 }
917
918
919 /*
920 * End of "$Id: pstops.c,v 1.53 2001/03/14 13:45:33 mike Exp $".
921 */