]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstops.c
2 * "$Id: pstops.c,v 1.54.2.2 2001/12/26 16:52:39 mike Exp $"
4 * PostScript filter for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-2001 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-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
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...
35 * Include necessary headers...
45 #define MAX_PAGES 10000
52 int NumPages
= 0; /* Number of pages in file */
53 long Pages
[MAX_PAGES
]; /* Offsets to each page */
54 char PageLabels
[MAX_PAGES
][64];
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 UseESPsp
= 0; /* Use ESPshowpage? */
70 static int check_range(int page
);
71 static void copy_bytes(FILE *fp
, size_t length
);
72 static void end_nup(int number
);
73 static char *psgets(char *buf
, size_t len
, FILE *fp
);
74 static void start_nup(int number
);
78 * 'main()' - Main entry...
81 int /* O - Exit status */
82 main(int argc
, /* I - Number of command-line arguments */
83 char *argv
[]) /* I - Command-line arguments */
85 FILE *fp
; /* Print file */
86 ppd_file_t
*ppd
; /* PPD file */
87 int num_options
; /* Number of print options */
88 cups_option_t
*options
; /* Print options */
89 const char *val
; /* Option value */
90 char tempfile
[255]; /* Temporary file name */
91 FILE *temp
; /* Temporary file */
92 int tempfd
; /* Temporary file descriptor */
93 int number
; /* Page number */
94 int slowcollate
; /* 1 if we need to collate manually */
95 int sloworder
; /* 1 if we need to order manually */
96 char line
[8192]; /* Line buffer */
97 float g
; /* Gamma correction value */
98 float b
; /* Brightness factor */
99 int level
; /* Nesting level for embedded files */
100 int nbytes
, /* Number of bytes read */
101 tbytes
; /* Total bytes to read for binary data */
102 int page
; /* Current page sequence number */
103 int real_page
; /* "Real" page number in document */
104 int page_count
; /* Page count for NUp */
105 int subpage
; /* Sub-page number */
106 int copy
; /* Current copy */
107 int saweof
; /* Did we see a %%EOF tag? */
111 * Make sure status messages are not buffered...
114 setbuf(stderr
, NULL
);
117 * Check command-line...
120 if (argc
< 6 || argc
> 7)
122 fputs("ERROR: pstops job-id user title copies options [file]\n", stderr
);
127 * If we have 7 arguments, print the file named on the command-line.
128 * Otherwise, send stdin instead...
136 * Try to open the print file...
139 if ((fp
= fopen(argv
[6], "rb")) == NULL
)
141 perror("ERROR: unable to open print file - ");
147 * Process command-line options and write the prolog...
153 Copies
= atoi(argv
[4]);
156 num_options
= cupsParseOptions(argv
[5], 0, &options
);
158 ppd
= SetCommonOptions(num_options
, options
, 1);
160 if ((val
= cupsGetOption("page-ranges", num_options
, options
)) != NULL
)
163 if ((val
= cupsGetOption("page-set", num_options
, options
)) != NULL
)
166 if ((val
= cupsGetOption("multiple-document-handling", num_options
, options
)) != NULL
)
169 * This IPP attribute is unnecessarily complicated...
171 * single-document, separate-documents-collated-copies, and
172 * single-document-new-sheet all require collated copies.
174 * separate-documents-uncollated-copies allows for uncollated copies.
177 Collate
= strcasecmp(val
, "separate-documents-uncollated-copies") != 0;
180 if ((val
= cupsGetOption("Collate", num_options
, options
)) != NULL
&&
181 strcasecmp(val
, "True") == 0)
184 if ((val
= cupsGetOption("OutputOrder", num_options
, options
)) != NULL
&&
185 strcasecmp(val
, "Reverse") == 0)
188 if ((val
= cupsGetOption("number-up", num_options
, options
)) != NULL
)
191 if ((val
= cupsGetOption("gamma", num_options
, options
)) != NULL
)
192 g
= atoi(val
) * 0.001f
;
194 if ((val
= cupsGetOption("brightness", num_options
, options
)) != NULL
)
195 b
= atoi(val
) * 0.01f
;
198 * See if we have to filter the fast or slow way...
201 if (ppdFindOption(ppd
, "Collate") == NULL
&& Collate
&& Copies
> 1)
206 if (ppdFindOption(ppd
, "OutputOrder") == NULL
&& Order
)
212 * If we need to filter slowly, then create a temporary file for page data...
214 * If the temp file can't be created, then we'll ignore the collating/output
218 if (sloworder
|| slowcollate
)
220 tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
));
221 temp
= fdopen(tempfd
, "wb+");
224 slowcollate
= sloworder
= 0;
230 * Write any "exit server" options that have been selected...
233 ppdEmit(ppd
, stdout
, PPD_ORDER_EXIT
);
236 * Write any JCL commands that are needed to print PostScript code...
239 ppdEmitJCL(ppd
, stdout
, atoi(argv
[1]), argv
[2], argv
[3]);
242 * Read the first line to see if we have DSC comments...
245 if (psgets(line
, sizeof(line
), fp
) == NULL
)
247 fputs("ERROR: Empty print file!\n", stderr
);
253 * See if this is an EPS file...
256 UseESPsp
= strstr(line
, "EPS") != NULL
;
259 * Start sending the document with any commands needed...
266 if (ppd
!= NULL
&& ppd
->patches
!= NULL
)
269 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
270 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
271 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
273 if (g
!= 1.0 || b
!= 1.0)
274 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
275 "ifelse %.3f mul } bind settransfer\n", g
, b
);
278 * Figure out if we should use ESPshowpage or not...
281 val
= cupsGetOption("page-label", num_options
, options
);
283 if (val
!= NULL
|| getenv("CLASSIFICATION") != NULL
|| NUp
> 1)
286 * Yes, use ESPshowpage...
292 WriteLabelProlog(val
);
295 puts("userdict begin\n"
296 "/ESPshowpage /showpage load def\n"
297 "/showpage { } def\n"
300 if (Copies
> 1 && (!Collate
|| !slowcollate
))
303 printf("%%%%Requirements: numcopies(%d) collate\n", Copies
);
305 printf("%%%%Requirements: numcopies(%d)\n", Copies
);
307 if (LanguageLevel
== 1)
308 printf("/#copies %d def\n", Copies
);
310 printf("<</NumCopies %d>>setpagedevice\n", Copies
);
313 if (strncmp(line
, "%!PS-Adobe-", 11) == 0 && atof(line
+ 11) >= 3.0)
316 * OK, we have DSC comments; read until we find a %%Page comment...
321 while (psgets(line
, sizeof(line
), fp
) != NULL
)
322 if (strncmp(line
, "%%BeginDocument:", 16) == 0 ||
323 strncmp(line
, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
325 else if (strncmp(line
, "%%EndDocument", 13) == 0 && level
> 0)
327 else if (strncmp(line
, "%%Page:", 7) == 0 && level
== 0)
329 else if (strncmp(line
, "%%BeginBinary:", 14) == 0 ||
330 (strncmp(line
, "%%BeginData:", 12) == 0 &&
331 strstr(line
, "Binary") != NULL
))
334 * Copy binary data...
337 tbytes
= atoi(strchr(line
, ':') + 1);
340 if (tbytes
> sizeof(line
))
341 nbytes
= fread(line
, 1, sizeof(line
), fp
);
343 nbytes
= fread(line
, 1, tbytes
, fp
);
345 fwrite(line
, 1, nbytes
, stdout
);
353 * Then read all of the pages, filtering as needed...
356 for (page
= 1, real_page
= 1;;)
358 if (strncmp(line
, "%%BeginDocument:", 16) == 0 ||
359 strncmp(line
, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
361 else if (strncmp(line
, "%%EndDocument", 13) == 0 && level
> 0)
363 else if (strcmp(line
, "\004") == 0)
365 else if (strncmp(line
, "%%EOF", 5) == 0 && level
== 0)
367 fputs("DEBUG: Saw EOF!\n", stderr
);
371 else if (strncmp(line
, "%%Page:", 7) == 0 && level
== 0)
373 if (!check_range(real_page
))
375 while (psgets(line
, sizeof(line
), fp
) != NULL
)
376 if (strncmp(line
, "%%BeginDocument:", 16) == 0 ||
377 strncmp(line
, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
379 else if (strcmp(line
, "%%EndDocument") == 0 && level
> 0)
381 else if (strncmp(line
, "%%Page:", 7) == 0 && level
== 0)
390 if (!sloworder
&& NumPages
> 0)
391 end_nup(NumPages
- 1);
393 if (slowcollate
|| sloworder
)
394 Pages
[NumPages
] = ftell(temp
);
398 if ((NumPages
& (NUp
- 1)) == 0)
400 if (ppd
== NULL
|| ppd
->num_filters
== 0)
401 fprintf(stderr
, "PAGE: %d %d\n", page
, Copies
);
403 printf("%%%%Page: %d %d\n", page
, page
);
405 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
414 else if (strncmp(line
, "%%BeginBinary:", 14) == 0 ||
415 (strncmp(line
, "%%BeginData:", 12) == 0 &&
416 strstr(line
, "Binary") != NULL
))
419 * Copy binary data...
422 tbytes
= atoi(strchr(line
, ':') + 1);
425 if (tbytes
> sizeof(line
))
426 nbytes
= fread(line
, 1, sizeof(line
), fp
);
428 nbytes
= fread(line
, 1, tbytes
, fp
);
431 fwrite(line
, 1, nbytes
, stdout
);
433 if (slowcollate
|| sloworder
)
434 fwrite(line
, 1, nbytes
, stdout
);
439 else if (strncmp(line
, "%%Trailer", 9) == 0 && level
== 0)
441 fputs("DEBUG: Saw Trailer!\n", stderr
);
449 if (slowcollate
|| sloworder
)
453 if (psgets(line
, sizeof(line
), fp
) == NULL
)
459 end_nup(NumPages
- 1);
461 if (NumPages
& (NUp
- 1))
468 if (slowcollate
|| sloworder
)
470 Pages
[NumPages
] = ftell(temp
);
479 for (number
= 0; number
< NumPages
; number
++)
481 if ((number
& (NUp
- 1)) == 0)
483 if (ppd
== NULL
|| ppd
->num_filters
== 0)
484 fprintf(stderr
, "PAGE: %d 1\n", page
);
486 printf("%%%%Page: %d %d\n", page
, page
);
488 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
492 copy_bytes(temp
, Pages
[number
+ 1] - Pages
[number
]);
496 if (NumPages
& (NUp
- 1))
507 page_count
= (NumPages
+ NUp
- 1) / NUp
;
512 for (page
= page_count
- 1; page
>= 0; page
--)
514 if (ppd
== NULL
|| ppd
->num_filters
== 0)
515 fprintf(stderr
, "PAGE: %d %d\n", page
+ 1,
516 slowcollate
? 1 : Copies
);
519 printf("%%%%Page: %d %d\n", page
+ 1,
520 page_count
- page
+ copy
* page_count
);
522 printf("%%%%Page: %d %d\n", page
+ 1, page_count
- page
);
524 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
526 for (subpage
= 0, number
= page
* NUp
;
527 subpage
< NUp
&& number
< NumPages
;
528 subpage
++, number
++)
531 fseek(temp
, Pages
[number
], SEEK_SET
);
532 copy_bytes(temp
, Pages
[number
+ 1] - Pages
[number
]);
536 if (number
& (NUp
- 1))
545 while (copy
< Copies
&& slowcollate
);
550 * Copy the trailer, if any...
553 while (psgets(line
, sizeof(line
), fp
) != NULL
)
555 if (strcmp(line
, "\004") != 0)
558 if (strncmp(line
, "%%EOF", 5) == 0)
560 fputs("DEBUG: Saw EOF!\n", stderr
);
569 * No DSC comments - write any page commands and then the rest of the file...
572 if (ppd
== NULL
|| ppd
->num_filters
== 0)
573 fprintf(stderr
, "PAGE: 1 %d\n", slowcollate
? 1 : Copies
);
575 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
577 while (psgets(line
, sizeof(line
), fp
) != NULL
)
592 if (ppd
== NULL
|| ppd
->num_filters
== 0)
593 fputs("PAGE: 1 1\n", stderr
);
595 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
607 * Send %%EOF if needed...
614 * End the job with the appropriate JCL command or CTRL-D otherwise.
617 if (ppd
!= NULL
&& ppd
->jcl_end
)
618 fputs(ppd
->jcl_end
, stdout
);
619 else if (ppd
!= NULL
&& ppd
->num_filters
== 0)
623 * Close files and remove the temporary file if needed...
626 if (slowcollate
|| sloworder
)
642 * 'check_range()' - Check to see if the current page is selected for
646 static int /* O - 1 if selected, 0 otherwise */
647 check_range(int page
) /* I - Page number */
649 const char *range
; /* Pointer into range string */
650 int lower
, upper
; /* Lower and upper page numbers */
656 * See if we only print even or odd pages...
659 if (strcasecmp(PageSet
, "even") == 0 && (page
& 1))
661 if (strcasecmp(PageSet
, "odd") == 0 && !(page
& 1))
665 if (PageRanges
== NULL
)
666 return (1); /* No range, print all pages... */
668 for (range
= PageRanges
; *range
!= '\0';)
674 upper
= strtol(range
, (char **)&range
, 10);
678 lower
= strtol(range
, (char **)&range
, 10);
683 if (!isdigit(*range
))
686 upper
= strtol(range
, (char **)&range
, 10);
692 if (page
>= lower
&& page
<= upper
)
706 * 'copy_bytes()' - Copy bytes from the input file to stdout...
710 copy_bytes(FILE *fp
, /* I - File to read from */
711 size_t length
) /* I - Length of page data */
713 char buffer
[8192]; /* Data buffer */
714 size_t nbytes
, /* Number of bytes read */
715 nleft
; /* Number of bytes left/remaining */
720 while (nleft
> 0 || length
== 0)
722 if (nleft
> sizeof(buffer
))
723 nbytes
= sizeof(buffer
);
727 if ((nbytes
= fread(buffer
, 1, nbytes
, fp
)) < 1)
732 fwrite(buffer
, 1, nbytes
, stdout
);
738 * 'end_nup()' - End processing for N-up printing...
742 end_nup(int number
) /* I - Page number */
744 if (Flip
|| Orientation
|| NUp
> 1)
745 puts("ESPsave restore");
758 if ((number
& 1) == 1 && UseESPsp
)
766 if ((number
& 3) == 3 && UseESPsp
)
777 * 'psgets()' - Get a line from a file.
781 * This function differs from the gets() function in that it
782 * handles any combination of CR, LF, or CR LF to end input
786 static char * /* O - String or NULL if EOF */
787 psgets(char *buf
, /* I - Buffer to read into */
788 size_t len
, /* I - Length of buffer */
789 FILE *fp
) /* I - File to read from */
791 char *bufptr
; /* Pointer into buffer */
792 int ch
; /* Character from file */
799 while ((bufptr
- buf
) < len
)
801 if ((ch
= getc(fp
)) == EOF
)
807 * Got a CR; see if there is a LF as well...
811 if (ch
!= EOF
&& ch
!= 0x0a)
812 ungetc(ch
, fp
); /* Nope, save it for later... */
824 * Add a trailing newline if it is there...
831 * Nul-terminate the string and return it (or NULL for EOF).
836 if (ch
== EOF
&& bufptr
== buf
)
844 * 'start_nup()' - Start processing for N-up printing...
848 start_nup(int number
) /* I - Page number */
850 int x
, y
; /* Relative position of subpage */
851 float w
, l
, /* Width and length of subpage */
852 tx
, ty
; /* Translation values for subpage */
853 float pw
, pl
; /* Printable width and length of full page */
856 if (Flip
|| Orientation
|| NUp
> 1)
857 puts("/ESPsave save def");
860 printf("%.1f 0.0 translate -1 1 scale\n", PageWidth
);
862 pw
= PageRight
- PageLeft
;
863 pl
= PageTop
- PageBottom
;
865 fprintf(stderr
, "DEBUG: pw = %.1f, pl = %.1f\n", pw
, pl
);
866 fprintf(stderr
, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", PageLeft
, PageRight
);
867 fprintf(stderr
, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", PageTop
, PageBottom
);
868 fprintf(stderr
, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", PageWidth
, PageLength
);
872 case 1 : /* Landscape */
873 printf("%.1f 0.0 translate 90 rotate\n", PageLength
);
875 case 2 : /* Reverse Portrait */
876 printf("%.1f %.1f translate 180 rotate\n", PageWidth
, PageLength
);
878 case 3 : /* Reverse Landscape */
879 printf("0.0 %.1f translate -90 rotate\n", PageWidth
);
892 l
= w
* PageLength
/ PageWidth
;
897 w
= l
* PageWidth
/ PageLength
;
906 w
= l
* PageWidth
/ PageLength
;
911 l
= w
* PageLength
/ PageWidth
;
918 if (Duplex
&& (number
& 2))
919 printf("%.1f %.1f translate\n", PageWidth
- PageRight
, PageBottom
);
921 printf("%.1f %.1f translate\n", PageLeft
, PageBottom
);
925 printf("0.0 %.1f translate -90 rotate\n", pl
);
926 printf("%.1f %.1f translate %.3f %.3f scale\n",
927 ty
, tx
+ l
* x
, w
/ PageWidth
, l
/ PageLength
);
931 printf("%.1f 0.0 translate 90 rotate\n", pw
);
932 printf("%.1f %.1f translate %.3f %.3f scale\n",
933 tx
+ w
* x
, ty
, w
/ PageWidth
, l
/ PageLength
);
941 "closepath clip newpath\n",
942 PageWidth
, PageWidth
, PageLength
, PageLength
);
947 y
= 1 - ((number
& 2) != 0);
950 l
= w
* PageLength
/ PageWidth
;
955 w
= l
* PageWidth
/ PageLength
;
958 if (Duplex
&& (number
& 4))
959 printf("%.1f %.1f translate\n", PageWidth
- PageRight
, PageBottom
);
961 printf("%.1f %.1f translate\n", PageLeft
, PageBottom
);
963 printf("%.1f %.1f translate %.3f %.3f scale\n", x
* w
, y
* l
,
964 w
/ PageWidth
, l
/ PageLength
);
970 "closepath clip newpath\n",
971 PageWidth
, PageWidth
, PageLength
, PageLength
);
978 * End of "$Id: pstops.c,v 1.54.2.2 2001/12/26 16:52:39 mike Exp $".