]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstops.c
2 * "$Id: pstops.c 4672 2005-09-18 04:25:46Z mike $"
4 * PostScript filter for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-2005 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
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...
42 * Include necessary headers...
52 #define MAX_PAGES 10000
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 */
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 */
70 #define LAYOUT_NEGATEY 1 /* The bits for the layout */
71 #define LAYOUT_NEGATEX 2 /* definitions above... */
72 #define LAYOUT_VERTICAL 4
74 #define PROT_STANDARD 0 /* Adobe standard protocol */
75 #define PROT_BCP 1 /* Adobe BCP protocol */
76 #define PROT_TBCP 2 /* Adobe TBCP protocol */
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 */
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
);
121 * 'main()' - Main entry...
124 int /* O - Exit status */
125 main(int argc
, /* I - Number of command-line arguments */
126 char *argv
[]) /* I - Command-line arguments */
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? */
161 * Make sure status messages are not buffered...
164 setbuf(stderr
, NULL
);
167 * Check command-line...
170 if (argc
< 6 || argc
> 7)
172 fputs("ERROR: pstops job-id user title copies options [file]\n", stderr
);
177 * If we have 7 arguments, print the file named on the command-line.
178 * Otherwise, send stdin instead...
186 * Try to open the print file...
189 if ((fp
= fopen(argv
[6], "rb")) == NULL
)
191 fprintf(stderr
, "ERROR: unable to open print file \"%s\" - %s\n",
192 argv
[6], strerror(errno
));
198 * Process command-line options and write the prolog...
204 Copies
= atoi(argv
[4]);
207 num_options
= cupsParseOptions(argv
[5], 0, &options
);
209 ppd
= SetCommonOptions(num_options
, options
, 1);
211 if (ppd
&& ppd
->landscape
> 0)
214 if ((val
= cupsGetOption("page-ranges", num_options
, options
)) != NULL
)
217 if ((val
= cupsGetOption("page-set", num_options
, options
)) != NULL
)
220 if ((val
= cupsGetOption("multiple-document-handling", num_options
, options
)) != NULL
)
223 * This IPP attribute is unnecessarily complicated...
225 * single-document, separate-documents-collated-copies, and
226 * single-document-new-sheet all require collated copies.
228 * separate-documents-uncollated-copies allows for uncollated copies.
231 Collate
= strcasecmp(val
, "separate-documents-uncollated-copies") != 0;
234 if ((val
= cupsGetOption("Collate", num_options
, options
)) != NULL
&&
235 (!strcasecmp(val
, "true") ||!strcasecmp(val
, "on") ||
236 !strcasecmp(val
, "yes")))
239 if ((val
= cupsGetOption("OutputOrder", num_options
, options
)) != NULL
&&
240 !strcasecmp(val
, "Reverse"))
243 if ((val
= cupsGetOption("number-up", num_options
, options
)) != NULL
)
246 if ((val
= cupsGetOption("page-border", num_options
, options
)) != NULL
)
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
;
260 if ((val
= cupsGetOption("number-up-layout", num_options
, options
)) != NULL
)
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
;
280 if ((val
= cupsGetOption("gamma", num_options
, options
)) != NULL
)
281 g
= atoi(val
) * 0.001f
;
283 if ((val
= cupsGetOption("brightness", num_options
, options
)) != NULL
)
284 b
= atoi(val
) * 0.01f
;
286 if ((val
= cupsGetOption("mirror", num_options
, options
)) != NULL
&&
287 (!strcasecmp(val
, "true") ||!strcasecmp(val
, "on") ||
288 !strcasecmp(val
, "yes")))
292 * See if we have to filter the fast or slow way...
295 if (ppd
&& ppd
->manual_copies
&& Duplex
&& Copies
> 1)
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...
311 if (ppdFindOption(ppd
, "Collate") == NULL
&& Collate
&& Copies
> 1)
316 if (ppdFindOption(ppd
, "OutputOrder") == NULL
&& Order
)
322 * If we need to filter slowly, then create a temporary file for page data...
324 * If the temp file can't be created, then we'll ignore the collating/output
328 if (sloworder
|| slowcollate
)
330 tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
));
333 perror("ERROR: Unable to open temp file");
337 temp
= fdopen(tempfd
, "wb+");
340 slowcollate
= sloworder
= 0;
346 * See if we should use a binary transmission protocol...
349 if ((attr
= ppdFindAttr(ppd
, "cupsProtocol", NULL
)) != NULL
&&
352 if (!strcasecmp(attr
->value
, "TBCP"))
353 Protocol
= PROT_TBCP
;
354 else if (!strcasecmp(attr
->value
, "BCP"))
363 * Write any "exit server" options that have been selected...
366 ppdEmit(ppd
, stdout
, PPD_ORDER_EXIT
);
369 * Write any JCL commands that are needed to print PostScript code...
372 ppdEmitJCL(ppd
, stdout
, atoi(argv
[1]), argv
[2], argv
[3]);
375 * Read the first line to see if we have DSC comments...
379 if (psgets(line
, &len
, fp
) == NULL
)
381 fputs("ERROR: Empty print file!\n", stderr
);
387 * Handle leading PJL fun...
390 while (!strncmp(line
, "\033%-12345X", 9) || !strncmp(line
, "@PJL ", 5))
393 * Yup, we have leading PJL fun, so skip it until we hit the line
394 * with "ENTER LANGUAGE"...
397 fputs("DEBUG: Skipping PJL header...\n", stderr
);
399 while (strstr(line
, "ENTER LANGUAGE") == NULL
)
402 if (psgets(line
, &len
, fp
) == NULL
)
407 if (psgets(line
, &len
, fp
) == NULL
)
412 * Switch to TBCP mode as needed...
415 if (Protocol
== PROT_TBCP
)
416 fputs("\001M", stdout
);
419 * Start sending the document with any commands needed...
422 fwrite(line
, 1, len
, stdout
);
429 if (Copies
!= 1 && (!Collate
|| !slowcollate
))
432 * Tell the document processor the copy and duplex options
433 * that are required...
436 printf("%%%%Requirements: numcopies(%d)%s%s\n", Copies
,
437 Collate
? " collate" : "",
438 Duplex
? " duplex" : "");
441 * Apple uses RBI comments for various non-PPD options...
444 printf("%%RBINumCopies: %d\n", Copies
);
449 * Tell the document processor the duplex option that is required...
453 puts("%%Requirements: duplex");
456 * Apple uses RBI comments for various non-PPD options...
459 puts("%RBINumCopies: 1");
463 * Figure out if we should use ESPshowpage or not...
466 val
= cupsGetOption("page-label", num_options
, options
);
468 if (val
!= NULL
|| getenv("CLASSIFICATION") != NULL
|| NUp
> 1 ||
469 Border
|| strstr(line
, "EPS") != NULL
)
472 * Yes, use ESPshowpage...
478 fprintf(stderr
, "DEBUG: slowcollate=%d, slowduplex=%d, sloworder=%d\n",
479 slowcollate
, slowduplex
, sloworder
);
481 if (!strncmp(line
, "%!PS-Adobe-", 11) && !strstr(line
, "EPSF"))
484 * OK, we have DSC comments and this isn't an EPS file; read until we
485 * find a %%Page comment...
488 puts("%%Pages: (atend)");
495 if (psgets(line
, &len
, fp
) == NULL
)
498 if (!strncmp(line
, "%%", 2))
499 fprintf(stderr
, "DEBUG: %d %s", level
, line
);
500 else if (line
[0] != '%' && line
[0] && !sent_espsp
&& UseESPsp
)
503 * Send ESPshowpage stuff...
508 puts("userdict/ESPshowpage/showpage load put\n"
509 "userdict/showpage{}put");
512 if (!strncmp(line
, "%%BeginDocument:", 16) ||
513 !strncmp(line
, "%%BeginDocument ", 16) || /* Adobe Acrobat BUG */
514 !strncmp(line
, "%ADO_BeginApplication", 21))
519 else if ((!strncmp(line
, "%%EndDocument", 13) ||
520 !strncmp(line
, "%ADO_EndApplication", 19)) && level
> 0)
525 else if (!strncmp(line
, "%cupsRotation:", 14) && level
== 0)
528 * Reset orientation of document?
531 int orient
= (atoi(line
+ 14) / 90) & 3;
533 if (orient
!= Orientation
)
535 Orientation
= (4 - Orientation
+ orient
) & 3;
537 Orientation
= orient
;
540 else if (!strncmp(line
, "%%BeginProlog", 13) && level
== 0)
543 * Write the existing comment line, and then follow with patches
544 * and prolog commands...
555 else if (!strncmp(line
, "%%BeginSetup", 12) && level
== 0)
558 * Write the existing comment line, and then follow with document
573 do_setup(ppd
, Copies
, Collate
, slowcollate
, g
, b
);
576 else if (!strncmp(line
, "%%Page:", 7) && level
== 0)
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")))
585 * Copy binary data...
588 tbytes
= atoi(strchr(line
, ':') + 1);
593 if (tbytes
> sizeof(line
))
594 nbytes
= fread(line
, 1, sizeof(line
), fp
);
596 nbytes
= fread(line
, 1, tbytes
, fp
);
600 perror("ERROR: Early end-of-file while reading binary data");
604 pswrite(line
, nbytes
, stdout
);
608 else if (strncmp(line
, "%%Pages:", 8) != 0)
609 pswrite(line
, len
, stdout
);
613 * Make sure we have the prolog and setup commands written...
618 puts("%%BeginProlog");
628 puts("%%BeginSetup");
631 do_setup(ppd
, Copies
, Collate
, slowcollate
, g
, b
);
636 if (!sent_espsp
&& UseESPsp
)
639 * Send ESPshowpage stuff...
644 puts("userdict/ESPshowpage/showpage load put\n"
645 "userdict/showpage{}put");
649 * Write the page and label prologs...
652 if (NUp
== 2 || NUp
== 6)
655 * For 2- and 6-up output, rotate the labels to match the orientation
660 WriteLabelProlog(val
, PageBottom
, PageWidth
- PageLength
+ PageTop
,
663 WriteLabelProlog(val
, PageLeft
, PageRight
, PageLength
);
666 WriteLabelProlog(val
, PageBottom
, PageTop
, PageWidth
);
669 * Then read all of the pages, filtering as needed...
672 for (page
= 1, real_page
= 1;;)
674 if (!strncmp(line
, "%%", 2))
675 fprintf(stderr
, "DEBUG: %d %s", level
, line
);
677 if (!strncmp(line
, "%%BeginDocument:", 16) ||
678 !strncmp(line
, "%%BeginDocument ", 16)) /* Adobe Acrobat BUG */
680 else if (!strncmp(line
, "%%EndDocument", 13) && level
> 0)
682 else if (!strcmp(line
, "\004") && len
== 1)
684 else if (!strncmp(line
, "%%EOF", 5) && level
== 0)
686 fputs("DEBUG: Saw EOF!\n", stderr
);
690 else if (!strncmp(line
, "%%Page:", 7) && level
== 0)
692 if (!check_range(real_page
))
697 if (psgets(line
, &len
, fp
) == NULL
)
700 if (!strncmp(line
, "%%", 2))
701 fprintf(stderr
, "DEBUG: %d %s", level
, line
);
703 if (!strncmp(line
, "%%BeginDocument:", 16) ||
704 !strncmp(line
, "%%BeginDocument ", 16)) /* Adobe Acrobat BUG */
706 else if (!strncmp(line
, "%%EndDocument", 13) && level
> 0)
708 else if (!strncmp(line
, "%%Page:", 7) && level
== 0)
713 else if (!strncmp(line
, "%%BeginBinary:", 14) ||
714 (!strncmp(line
, "%%BeginData:", 12) &&
715 !strstr(line
, "ASCII") && !strstr(line
, "Hex")))
718 * Skip binary data...
721 tbytes
= atoi(strchr(line
, ':') + 1);
725 if (tbytes
> sizeof(line
))
726 nbytes
= fread(line
, 1, sizeof(line
), fp
);
728 nbytes
= fread(line
, 1, tbytes
, fp
);
732 perror("ERROR: Early end-of-file while reading binary data");
744 if (!sloworder
&& NumPages
> 0)
745 end_nup(NumPages
- 1);
747 if (slowcollate
|| sloworder
)
748 Pages
[NumPages
] = ftell(temp
);
752 if (is_first_page(NumPages
))
754 if (ppd
== NULL
|| ppd
->num_filters
== 0)
755 fprintf(stderr
, "PAGE: %d %d\n", page
, slowcollate
? 1 : Copies
);
757 printf("%%%%Page: %d %d\n", page
, page
);
759 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
762 start_nup(NumPages
, 1);
768 else if (!strncmp(line
, "%%BeginBinary:", 14) ||
769 (!strncmp(line
, "%%BeginData:", 12) &&
770 !strstr(line
, "ASCII") && !strstr(line
, "Hex")))
773 * Copy binary data...
776 tbytes
= atoi(strchr(line
, ':') + 1);
780 if (slowcollate
|| sloworder
)
785 if (tbytes
> sizeof(line
))
786 nbytes
= fread(line
, 1, sizeof(line
), fp
);
788 nbytes
= fread(line
, 1, tbytes
, fp
);
792 perror("ERROR: Early end-of-file while reading binary data");
797 pswrite(line
, nbytes
, stdout
);
799 if (slowcollate
|| sloworder
)
800 fwrite(line
, 1, nbytes
, temp
);
805 else if (!strncmp(line
, "%%IncludeFeature:", 17))
808 * Embed printer commands as needed...
811 if (level
== 0 && NUp
== 1)
813 include_feature(ppd
, line
, stdout
);
815 if (slowcollate
|| sloworder
)
816 include_feature(ppd
, line
, temp
);
819 else if (!strncmp(line
, "%%BeginFeature:", 15) && NUp
> 1)
822 * Strip page options for N-up > 1...
828 if (psgets(line
, &len
, fp
) == NULL
)
831 while (strncmp(line
, "%%EndFeature", 12));
833 else if (!strncmp(line
, "%%Trailer", 9) && level
== 0)
835 fputs("DEBUG: Saw Trailer!\n", stderr
);
841 pswrite(line
, len
, stdout
);
843 if (slowcollate
|| sloworder
)
844 fwrite(line
, 1, len
, temp
);
848 if (psgets(line
, &len
, fp
) == NULL
)
854 end_nup(NumPages
- 1);
856 if (is_not_last_page(NumPages
))
858 start_nup(NUp
- 1, 0);
862 if (Duplex
&& !(page
& 1))
865 * Make sure we have an even number of pages...
868 if (ppd
== NULL
|| ppd
->num_filters
== 0)
869 fprintf(stderr
, "PAGE: %d %d\n", page
, slowcollate
? 1 : Copies
);
871 printf("%%%%Page: %d %d\n", page
, page
);
873 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
875 start_nup(NUp
- 1, 0);
881 if (slowcollate
|| sloworder
)
883 Pages
[NumPages
] = ftell(temp
);
891 for (number
= 0; number
< NumPages
; number
++)
893 if (is_first_page(number
))
895 if (ppd
== NULL
|| ppd
->num_filters
== 0)
896 fprintf(stderr
, "PAGE: %d 1\n", page
);
898 printf("%%%%Page: %d %d\n", page
, page
);
900 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
903 start_nup(number
, 1);
904 copy_bytes(temp
, Pages
[number
+ 1] - Pages
[number
]);
908 if (is_not_last_page(NumPages
))
910 start_nup(NUp
- 1, 0);
914 if (Duplex
&& !(page
& 1))
917 * Make sure we have an even number of pages...
920 if (ppd
== NULL
|| ppd
->num_filters
== 0)
921 fprintf(stderr
, "PAGE: %d 1\n", page
);
923 printf("%%%%Page: %d %d\n", page
, page
);
925 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
927 start_nup(NUp
- 1, 0);
937 page_count
= (NumPages
+ NUp
- 1) / NUp
;
940 fprintf(stderr
, "DEBUG: page_count=%d\n", page_count
);
944 if (Duplex
&& (page_count
& 1))
945 basepage
= page_count
;
947 basepage
= page_count
- 1;
949 for (; basepage
>= 0; basepage
--)
951 if (ppd
== NULL
|| ppd
->num_filters
== 0)
952 fprintf(stderr
, "PAGE: %d %d\n", page
,
953 slowcollate
? 1 : Copies
);
955 printf("%%%%Page: %d %d\n", page
, page
);
958 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
960 if (basepage
>= page_count
)
962 start_nup(NUp
- 1, 0);
968 for (subpage
= 0, number
= basepage
* NUp
;
969 subpage
< NUp
&& number
< NumPages
;
970 subpage
++, number
++)
972 start_nup(number
, 1);
973 fseek(temp
, Pages
[number
], SEEK_SET
);
974 copy_bytes(temp
, Pages
[number
+ 1] - Pages
[number
]);
978 if (is_not_last_page(number
))
980 start_nup(NUp
- 1, 0);
988 while (copy
< Copies
&& slowcollate
);
993 * Copy the trailer, if any...
997 printf("%%%%Pages: %d\n", page
- 1);
1000 puts("userdict/showpage/ESPshowpage load put\n");
1005 if (psgets(line
, &len
, fp
) == NULL
)
1008 if (!(!strcmp(line
, "\004") && len
== 1) &&
1009 strncmp(line
, "%%Pages:", 8) != 0)
1010 pswrite(line
, len
, stdout
);
1012 if (!strncmp(line
, "%%EOF", 5))
1014 fputs("DEBUG: Saw EOF!\n", stderr
);
1023 * No DSC comments - write any page commands and then the rest of the file...
1026 if (slowcollate
&& Copies
> 1)
1027 printf("%%%%Pages: %d\n", Copies
);
1032 puts("userdict/ESPshowpage/showpage load put\n"
1033 "userdict/showpage{}put");
1035 puts("%%BeginProlog");
1036 WriteLabelProlog(val
, PageBottom
, PageTop
, PageWidth
);
1038 puts("%%EndProlog");
1040 puts("%%BeginSetup");
1041 do_setup(ppd
, Copies
, Collate
, slowcollate
, g
, b
);
1044 if (ppd
== NULL
|| ppd
->num_filters
== 0)
1045 fprintf(stderr
, "PAGE: 1 %d\n", slowcollate
? 1 : Copies
);
1047 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
1051 while ((nbytes
= fread(line
, 1, sizeof(line
), fp
)) > 0)
1053 pswrite(line
, nbytes
, stdout
);
1056 fwrite(line
, 1, nbytes
, temp
);
1061 WriteLabels(Orientation
);
1062 puts("ESPshowpage");
1069 if (ppd
== NULL
|| ppd
->num_filters
== 0)
1070 fputs("PAGE: 1 1\n", stderr
);
1072 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
1074 copy_bytes(temp
, 0);
1079 WriteLabels(Orientation
);
1080 puts("ESPshowpage");
1087 * Send %%EOF if needed...
1094 * End the job with the appropriate JCL command or CTRL-D otherwise.
1097 ppdEmitJCLEnd(ppd
, stdout
);
1100 * Close files and remove the temporary file if needed...
1103 if (slowcollate
|| sloworder
)
1119 * 'check_range()' - Check to see if the current page is selected for
1123 static int /* O - 1 if selected, 0 otherwise */
1124 check_range(int page
) /* I - Page number */
1126 const char *range
; /* Pointer into range string */
1127 int lower
, upper
; /* Lower and upper page numbers */
1130 if (PageSet
!= NULL
)
1133 * See if we only print even or odd pages...
1136 if (!strcasecmp(PageSet
, "even") && ((page
- 1) % (NUp
<< 1)) < NUp
)
1138 if (!strcasecmp(PageSet
, "odd") && ((page
- 1) % (NUp
<< 1)) >= NUp
)
1142 if (PageRanges
== NULL
)
1143 return (1); /* No range, print all pages... */
1145 for (range
= PageRanges
; *range
!= '\0';)
1151 upper
= strtol(range
, (char **)&range
, 10);
1155 lower
= strtol(range
, (char **)&range
, 10);
1160 if (!isdigit(*range
& 255))
1163 upper
= strtol(range
, (char **)&range
, 10);
1169 if (page
>= lower
&& page
<= upper
)
1183 * 'copy_bytes()' - Copy bytes from the input file to stdout...
1187 copy_bytes(FILE *fp
, /* I - File to read from */
1188 size_t length
) /* I - Length of page data */
1190 char buffer
[8192]; /* Data buffer */
1191 size_t nbytes
, /* Number of bytes read */
1192 nleft
; /* Number of bytes left/remaining */
1197 while (nleft
> 0 || length
== 0)
1199 if (nleft
> sizeof(buffer
) || length
== 0)
1200 nbytes
= sizeof(buffer
);
1204 if ((nbytes
= fread(buffer
, 1, nbytes
, fp
)) < 1)
1209 pswrite(buffer
, nbytes
, stdout
);
1215 * 'do_prolog()' - Send the necessary document prolog commands...
1219 do_prolog(ppd_file_t
*ppd
) /* I - PPD file */
1222 * Send the document prolog commands...
1225 if (ppd
!= NULL
&& ppd
->patches
!= NULL
)
1227 puts("%%BeginFeature: *JobPatchFile 1");
1229 puts("%%EndFeature");
1232 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
1237 * 'do_setup()' - Send the necessary document setup commands...
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 */
1249 * Send all the printer-specific setup commands...
1252 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
1253 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
1256 * Set the number of copies for the job...
1259 if (copies
!= 1 && (!collate
|| !slowcollate
))
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");
1269 * If we are doing N-up printing, disable setpagedevice...
1273 puts("userdict/setpagedevice{pop}bind put");
1276 * Changes to the transfer function must be made AFTER any
1277 * setpagedevice code...
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
);
1285 * Make sure we have rectclip and rectstroke procedures of some sort...
1293 * 'end_nup()' - End processing for N-up printing...
1297 end_nup(int number
) /* I - Page number */
1301 if (Flip
|| Orientation
|| NUp
> 1)
1302 puts("userdict /ESPsave get restore");
1309 WriteLabels(Orientation
);
1310 puts("ESPshowpage");
1316 if (is_last_page(number
) && UseESPsp
)
1318 if (Orientation
& 1)
1321 * Rotate the labels back to portrait...
1324 WriteLabels(Orientation
- 1);
1326 else if (Orientation
== 0)
1329 * Rotate the labels to landscape...
1332 WriteLabels(NormalLandscape
? 1 : 3);
1337 * Rotate the labels to landscape...
1340 WriteLabels(NormalLandscape
? 3 : 1);
1343 puts("ESPshowpage");
1348 if (is_last_page(number
) && UseESPsp
)
1350 WriteLabels(Orientation
);
1351 puts("ESPshowpage");
1361 * 'include_feature()' - Include a printer option/feature command.
1365 include_feature(ppd_file_t
*ppd
, /* I - PPD file */
1366 const char *line
, /* I - DSC line */
1367 FILE *out
) /* I - Output file */
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 */
1376 * Get the "%%IncludeFeature: *Keyword OptionKeyword" values...
1379 if (sscanf(line
+ 17, "%254s%254s", name
, value
) != 2)
1381 fprintf(stderr
, "ERROR: Bad line: \"%s\"!\n", line
);
1386 * Find the option and choice...
1389 if ((option
= ppdFindOption(ppd
, name
+ 1)) == NULL
)
1391 fprintf(stderr
, "WARNING: Unknown option \"%s\"!\n", name
+ 1);
1395 if (option
->section
== PPD_ORDER_EXIT
||
1396 option
->section
== PPD_ORDER_JCL
)
1398 fprintf(stderr
, "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n",
1403 if ((choice
= ppdFindChoice(option
, value
)) == NULL
)
1405 fprintf(stderr
, "WARNING: Unknown choice \"%s\" for option \"%s\"!\n",
1411 * Emit the option...
1415 fprintf(out
, "%%%%BeginFeature: %s %s\n", name
, value
);
1416 if (choice
->code
&& choice
->code
[0])
1418 fputs(choice
->code
, out
);
1420 if (choice
->code
[strlen(choice
->code
) - 1] != '\n')
1423 fputs("%%EndFeature\n", out
);
1424 fputs("} stopped cleartomark\n", out
);
1429 * 'psbcp()' - Enable the binary communications protocol on the printer.
1433 psbcp(ppd_file_t
*ppd
) /* I - PPD file */
1436 fputs(ppd
->jcl_begin
, stdout
);
1438 fputs(ppd
->jcl_ps
, stdout
);
1440 if (ppd
->language_level
== 1)
1443 * Use setsoftwareiomode for BCP mode...
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
);
1460 * Use setdevparams for BCP mode...
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
);
1477 fputs(ppd
->jcl_end
, stdout
);
1478 else if (ppd
->num_filters
== 0)
1484 * 'psgets()' - Get a line from a file.
1488 * This function differs from the gets() function in that it
1489 * handles any combination of CR, LF, or CR LF to end input
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 */
1498 char *bufptr
; /* Pointer into buffer */
1499 int ch
; /* Character from file */
1500 size_t len
; /* Max length of string */
1507 while ((bufptr
- buf
) < len
)
1509 if ((ch
= getc(fp
)) == EOF
)
1515 * Got a CR; see if there is a LF as well...
1520 if (ch
!= EOF
&& ch
!= '\n')
1522 ungetc(ch
, fp
); /* Nope, save it for later... */
1529 else if (ch
== '\n')
1536 * Add a trailing newline if it is there...
1539 if (ch
== '\n' || ch
== '\r')
1541 if ((bufptr
- buf
) < len
)
1548 * Nul-terminate the string and return it (or NULL for EOF).
1552 *bytes
= bufptr
- buf
;
1554 if (ch
== EOF
&& bufptr
== buf
)
1562 * 'pswrite()' - Write data from a file.
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 */
1570 size_t count
; /* Remaining bytes */
1575 case PROT_STANDARD
:
1576 return (fwrite(buf
, 1, bytes
, fp
));
1579 for (count
= bytes
; count
> 0; count
--, buf
++)
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-\ */
1591 putchar(*buf
^ 0x40);
1601 for (count
= bytes
; count
> 0; count
--, buf
++)
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-\ */
1614 putchar(*buf
^ 0x40);
1624 return (fwrite(buf
, 1, bytes
, fp
));
1629 * 'start_nup()' - Start processing for N-up printing...
1633 start_nup(int number
, /* I - Page number */
1634 int show_border
) /* I - Show the page border? */
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 */
1643 if (Flip
|| Orientation
|| NUp
> 1)
1644 puts("userdict/ESPsave save put");
1647 printf("%.1f 0.0 translate -1 1 scale\n", PageWidth
);
1650 pw
= PageRight
- PageLeft
;
1651 pl
= PageTop
- PageBottom
;
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
);
1658 switch (Orientation
)
1660 case 1 : /* Landscape */
1661 printf("%.1f 0.0 translate 90 rotate\n", PageLength
);
1663 case 2 : /* Reverse Portrait */
1664 printf("%.1f %.1f translate 180 rotate\n", PageWidth
, PageLength
);
1666 case 3 : /* Reverse Landscape */
1667 printf("0.0 %.1f translate -90 rotate\n", PageWidth
);
1671 if (Duplex
&& NUp
> 1 && ((number
/ NUp
) & 1))
1672 printf("%.1f %.1f translate\n", PageWidth
- PageRight
, PageBottom
);
1674 printf("%.1f %.1f translate\n", PageLeft
, PageBottom
);
1684 if (Orientation
& 1)
1688 if (Layout
& LAYOUT_NEGATEY
)
1692 l
= w
* PageLength
/ PageWidth
;
1697 w
= l
* PageWidth
/ PageLength
;
1700 tx
= 0.5 * (pw
* 0.5 - l
);
1701 ty
= 0.5 * (pl
- w
);
1703 if (NormalLandscape
)
1704 printf("0.0 %.1f translate -90 rotate\n", pl
);
1706 printf("%.1f 0.0 translate 90 rotate\n", pw
);
1708 printf("%.1f %.1f translate %.3f %.3f scale\n",
1709 ty
, tx
+ l
* x
, w
/ PageWidth
, l
/ PageLength
);
1715 if (Layout
& LAYOUT_NEGATEX
)
1719 w
= l
* PageWidth
/ PageLength
;
1724 l
= w
* PageLength
/ PageWidth
;
1727 tx
= 0.5 * (pl
* 0.5 - w
);
1728 ty
= 0.5 * (pw
- l
);
1730 if (NormalLandscape
)
1731 printf("%.1f 0.0 translate 90 rotate\n", pw
);
1733 printf("0.0 %.1f translate -90 rotate\n", pl
);
1735 printf("%.1f %.1f translate %.3f %.3f scale\n",
1736 tx
+ w
* x
, ty
, w
/ PageWidth
, l
/ PageLength
);
1741 if (Layout
& LAYOUT_VERTICAL
)
1752 if (Layout
& LAYOUT_NEGATEX
)
1755 if (Layout
& LAYOUT_NEGATEY
)
1759 l
= w
* PageLength
/ PageWidth
;
1764 w
= l
* PageWidth
/ PageLength
;
1767 tx
= 0.5 * (pw
* 0.5 - w
);
1768 ty
= 0.5 * (pl
* 0.5 - l
);
1770 printf("%.1f %.1f translate %.3f %.3f scale\n", tx
+ x
* w
, ty
+ y
* l
,
1771 w
/ PageWidth
, l
/ PageLength
);
1775 if (Orientation
& 1)
1777 if (Layout
& LAYOUT_VERTICAL
)
1782 if (Layout
& LAYOUT_NEGATEX
)
1785 if (Layout
& LAYOUT_NEGATEY
)
1793 if (Layout
& LAYOUT_NEGATEX
)
1796 if (Layout
& LAYOUT_NEGATEY
)
1801 l
= w
* PageLength
/ PageWidth
;
1803 if (l
> (pw
* 0.333))
1806 w
= l
* PageWidth
/ PageLength
;
1809 tx
= 0.5 * (pl
- 2 * w
);
1810 ty
= 0.5 * (pw
- 3 * l
);
1812 if (NormalLandscape
)
1813 printf("0.0 %.1f translate -90 rotate\n", pl
);
1815 printf("%.1f 0.0 translate 90 rotate\n", pw
);
1817 printf("%.1f %.1f translate %.3f %.3f scale\n",
1818 tx
+ x
* w
, ty
+ y
* l
, w
/ PageWidth
, l
/ PageLength
);
1822 if (Layout
& LAYOUT_VERTICAL
)
1827 if (Layout
& LAYOUT_NEGATEX
)
1830 if (Layout
& LAYOUT_NEGATEY
)
1838 if (Layout
& LAYOUT_NEGATEX
)
1841 if (Layout
& LAYOUT_NEGATEY
)
1846 w
= l
* PageWidth
/ PageLength
;
1848 if (w
> (pl
* 0.333))
1851 l
= w
* PageLength
/ PageWidth
;
1854 tx
= 0.5 * (pl
- 3 * w
);
1855 ty
= 0.5 * (pw
- 2 * l
);
1857 if (NormalLandscape
)
1858 printf("%.1f 0.0 translate 90 rotate\n", pw
);
1860 printf("0.0 %.1f translate -90 rotate\n", pl
);
1862 printf("%.1f %.1f translate %.3f %.3f scale\n",
1863 tx
+ w
* x
, ty
+ l
* y
, w
/ PageWidth
, l
/ PageLength
);
1868 if (Layout
& LAYOUT_VERTICAL
)
1879 if (Layout
& LAYOUT_NEGATEX
)
1882 if (Layout
& LAYOUT_NEGATEY
)
1886 l
= w
* PageLength
/ PageWidth
;
1888 if (l
> (pl
* 0.333))
1891 w
= l
* PageWidth
/ PageLength
;
1894 tx
= 0.5 * (pw
* 0.333 - w
);
1895 ty
= 0.5 * (pl
* 0.333 - l
);
1897 printf("%.1f %.1f translate %.3f %.3f scale\n", tx
+ x
* w
, ty
+ y
* l
,
1898 w
/ PageWidth
, l
/ PageLength
);
1902 if (Layout
& LAYOUT_VERTICAL
)
1913 if (Layout
& LAYOUT_NEGATEX
)
1916 if (Layout
& LAYOUT_NEGATEY
)
1920 l
= w
* PageLength
/ PageWidth
;
1922 if (l
> (pl
* 0.25))
1925 w
= l
* PageWidth
/ PageLength
;
1928 tx
= 0.5 * (pw
* 0.25 - w
);
1929 ty
= 0.5 * (pl
* 0.25 - l
);
1931 printf("%.1f %.1f translate %.3f %.3f scale\n", tx
+ x
* w
, ty
+ y
* l
,
1932 w
/ PageWidth
, l
/ PageLength
);
1937 * Draw borders as necessary...
1940 if (Border
&& show_border
)
1942 int rects
; /* Number of border rectangles */
1943 float fscale
, /* Scaling value for points */
1944 margin
; /* Current margin for borders */
1947 rects
= (Border
& BORDER_DOUBLE
) ? 2 : 1;
1948 fscale
= PageWidth
/ w
;
1949 margin
= 2.25 * fscale
;
1952 * Set the line width and color...
1956 printf("%.3f setlinewidth 0 setgray newpath\n",
1957 (Border
& BORDER_THICK
) ? 0.5 * fscale
: 0.24 * fscale
);
1960 * Draw border boxes...
1963 for (; rects
> 0; rects
--, margin
+= 2 * fscale
)
1965 printf("%.1f %.1f %.1f %.1f ESPrs\n",
1968 PageWidth
- 2 * margin
,
1969 PageLength
- 2 * margin
);
1971 printf("%.1f %.1f %.1f %.1f ESPrs\n",
1973 PageBottom
+ margin
,
1974 PageRight
- PageLeft
- 2 * margin
,
1975 PageTop
- PageBottom
- 2 * margin
);
1978 * Restore pen settings...
1987 * Clip the page that follows to the bounding box of the page...
1990 printf("0 0 %.1f %.1f ESPrc\n", PageWidth
, PageLength
);
1996 * End of "$Id: pstops.c 4672 2005-09-18 04:25:46Z mike $".