]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstops.c
2 * "$Id: pstops.c,v 1.17 1999/05/18 21:21:46 mike Exp $"
4 * PostScript filter for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-1999 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 char *PageRanges
= NULL
; /* Range of pages selected */
57 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 */
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
);
77 * 'main()' - Main entry...
80 int /* O - Exit status */
81 main(int argc
, /* I - Number of command-line arguments */
82 char *argv
[]) /* I - Command-line arguments */
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 char *val
; /* Option value */
89 char tempfile
[255]; /* Temporary file name */
90 FILE *temp
; /* Temporary file */
91 int number
; /* Page number */
92 int slowcollate
; /* 1 if we need to collate manually */
93 int sloworder
; /* 1 if we need to order manually */
94 char line
[8192]; /* Line buffer */
95 float g
; /* Gamma correction value */
96 float b
; /* Brightness factor */
99 if (argc
< 6 || argc
> 7)
101 fputs("ERROR: pstops job-id user title copies options [file]\n", stderr
);
106 * If we have 7 arguments, print the file named on the command-line.
107 * Otherwise, send stdin instead...
115 * Try to open the print file...
118 if ((fp
= fopen(argv
[6], "rb")) == NULL
)
120 perror("ERROR: unable to open print file - ");
126 * Process command-line options and write the prolog...
132 ppd
= ppdOpenFile(getenv("PPD"));
135 num_options
= cupsParseOptions(argv
[5], 0, &options
);
137 ppd
= SetCommonOptions(num_options
, options
, 1);
139 ppdMarkDefaults(ppd
);
140 cupsMarkOptions(ppd
, num_options
, options
);
142 if ((val
= cupsGetOption("page-ranges", num_options
, options
)) != NULL
)
145 if ((val
= cupsGetOption("page-set", num_options
, options
)) != NULL
)
148 if ((val
= cupsGetOption("copies", num_options
, options
)) != NULL
)
151 if ((val
= cupsGetOption("multiple-document-handling", num_options
, options
)) != NULL
)
154 * This IPP attribute is unnecessarily complicated...
156 * single-document, separate-documents-collated-copies, and
157 * single-document-new-sheet all require collated copies.
159 * separate-documents-collated-copies allows for uncollated copies.
162 Collate
= strcmp(val
, "separate-documents-collated-copies") != 0;
165 if ((val
= cupsGetOption("Collate", num_options
, options
)) != NULL
&&
166 strcmp(val
, "True") == 0)
169 if ((val
= cupsGetOption("OutputOrder", num_options
, options
)) != NULL
&&
170 strcmp(val
, "Reverse") == 0)
173 if ((val
= cupsGetOption("number-up", num_options
, options
)) != NULL
)
176 if ((val
= cupsGetOption("gamma", num_options
, options
)) != NULL
)
177 g
= atoi(val
) * 0.001f
;
179 if ((val
= cupsGetOption("brightness", num_options
, options
)) != NULL
)
180 b
= atoi(val
) * 0.01f
;
183 * See if we have to filter the fast or slow way...
186 if (ppdFindOption(ppd
, "Collate") == NULL
&& Collate
&& Copies
> 1)
191 if (ppdFindOption(ppd
, "OutputOrder") == NULL
&& Order
)
197 * If we need to filter slowly, then create a temporary file for page data...
199 * If the temp file can't be created, then we'll ignore the collating/output
203 if (sloworder
|| slowcollate
)
205 temp
= fopen(tmpnam(tempfile
), "wb+");
208 slowcollate
= sloworder
= 0;
212 * Write any "exit server" options that have been selected...
215 ppdEmit(ppd
, stdout
, PPD_ORDER_EXIT
);
218 * Write any JCL commands that are needed to print PostScript code...
221 if (ppd
!= NULL
&& ppd
->jcl_begin
&& ppd
->jcl_ps
)
223 fputs(ppd
->jcl_begin
, stdout
);
224 ppdEmit(ppd
, stdout
, PPD_ORDER_JCL
);
225 fputs(ppd
->jcl_ps
, stdout
);
229 * Read the first line to see if we have DSC comments...
232 if (psgets(line
, sizeof(line
), fp
) == NULL
)
234 fputs("ERROR: Empty print file!\n", stderr
);
240 * Start sending the document with any commands needed...
245 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
246 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
247 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
250 puts("userdict begin\n"
251 "/ESPshowpage /showpage load def\n"
252 "/showpage { } def\n"
255 if (g
!= 1.0 || b
!= 1.0)
256 printf("{ neg 1 add %.3f exp neg 1 add %.3f mul } bind settransfer\n", g
, b
);
258 if (Copies
> 1 && (!Collate
|| !slowcollate
))
259 printf("/#copies %d def\n", Copies
);
261 if (strncmp(line
, "%!PS-Adobe-", 11) == 0)
264 * OK, we have DSC comments; read until we find a %%Page comment...
267 while (psgets(line
, sizeof(line
), fp
) != NULL
)
268 if (strncmp(line
, "%%Page:", 7) == 0)
274 * Then read all of the pages, filtering as needed...
279 if (strncmp(line
, "%%Page:", 7) == 0)
281 if (sscanf(line
, "%*s%*s%d", &number
) == 1)
283 if (!check_range(number
))
285 while (psgets(line
, sizeof(line
), fp
) != NULL
)
286 if (strncmp(line
, "%%Page:", 7) == 0)
291 if (!sloworder
&& NumPages
> 0)
292 end_nup(NumPages
- 1);
294 if (slowcollate
|| sloworder
)
295 Pages
[NumPages
] = ftell(temp
);
301 if (ppd
== NULL
|| ppd
->num_filters
== 0)
302 fprintf(stderr
, "PAGE: %d %d\n", NumPages
, Copies
);
304 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
305 start_nup(NumPages
- 1);
314 if (slowcollate
|| sloworder
)
321 if (psgets(line
, sizeof(line
), fp
) == NULL
)
326 end_nup((NumPages
+ NUp
- 1) & (NUp
- 1));
328 if (slowcollate
|| sloworder
)
330 Pages
[NumPages
] = ftell(temp
);
338 for (number
= 0; number
< NumPages
; number
++)
340 if (ppd
== NULL
|| ppd
->num_filters
== 0)
341 fprintf(stderr
, "PAGE: %d 1\n", number
+ 1);
343 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
345 copy_bytes(temp
, Pages
[number
+ 1] - Pages
[number
]);
356 for (number
= NumPages
- 1; number
>= 0; number
--)
358 if (ppd
== NULL
|| ppd
->num_filters
== 0)
359 fprintf(stderr
, "PAGE: %d %d\n", NumPages
- number
,
360 slowcollate
? 1 : Copies
);
362 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
363 start_nup(NumPages
- 1 - number
);
364 fseek(temp
, Pages
[number
], SEEK_SET
);
365 copy_bytes(temp
, Pages
[number
+ 1] - Pages
[number
]);
366 end_nup(NumPages
- 1 - number
);
371 while (Copies
> 0 || !slowcollate
);
378 * No DSC comments - write any page commands and then the rest of the file...
381 if (ppd
== NULL
|| ppd
->num_filters
== 0)
382 fprintf(stderr
, "PAGE: 1 %d\n", slowcollate
? 1 : Copies
);
384 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
386 while (psgets(line
, sizeof(line
), fp
) != NULL
)
401 if (ppd
== NULL
|| ppd
->num_filters
== 0)
402 fputs("PAGE: 1 1\n", stderr
);
404 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
412 * End the job with the appropriate JCL command or CTRL-D otherwise.
415 if (ppd
!= NULL
&& ppd
->jcl_end
)
416 fputs(ppd
->jcl_end
, stdout
);
421 * Close files and remove the temporary file if needed...
424 if (slowcollate
|| sloworder
)
440 * 'check_range()' - Check to see if the current page is selected for
444 static int /* O - 1 if selected, 0 otherwise */
445 check_range(int page
) /* I - Page number */
447 char *range
; /* Pointer into range string */
448 int lower
, upper
; /* Lower and upper page numbers */
454 * See if we only print even or odd pages...
457 if (strcmp(PageSet
, "even") == 0 && (page
& 1))
459 if (strcmp(PageSet
, "odd") == 0 && !(page
& 1))
463 if (PageRanges
== NULL
)
464 return (1); /* No range, print all pages... */
466 for (range
= PageRanges
; *range
!= '\0';)
472 upper
= strtol(range
, &range
, 10);
476 lower
= strtol(range
, &range
, 10);
481 if (!isdigit(*range
))
484 upper
= strtol(range
, &range
, 10);
490 if (page
>= lower
&& page
<= upper
)
504 * 'copy_bytes()' - Copy bytes from the input file to stdout...
508 copy_bytes(FILE *fp
, /* I - File to read from */
509 size_t length
) /* I - Length of page data */
511 char buffer
[8192]; /* Data buffer */
512 size_t nbytes
, /* Number of bytes read */
513 nleft
; /* Number of bytes left/remaining */
518 while (nleft
> 0 || length
== 0)
520 if ((nbytes
= fread(buffer
, 1, sizeof(buffer
), fp
)) < 1)
525 fwrite(buffer
, 1, nbytes
, stdout
);
531 * 'end_nup()' - End processing for N-up printing...
535 end_nup(int number
) /* I - Page number */
542 if ((number
& 1) == 1)
547 if ((number
& 3) == 3)
555 * 'psgets()' - Get a line from a file.
559 * This function differs from the gets() function in that it
560 * handles any combination of CR, LF, or CR LF to end input
564 static char * /* O - String or NULL if EOF */
565 psgets(char *buf
, /* I - Buffer to read into */
566 size_t len
, /* I - Length of buffer */
567 FILE *fp
) /* I - File to read from */
569 char *bufptr
; /* Pointer into buffer */
570 int ch
; /* Character from file */
576 while ((bufptr
- buf
) < len
)
578 if ((ch
= getc(fp
)) == EOF
)
584 * Got a CR; see if there is a LF as well...
588 if (ch
!= EOF
&& ch
!= 0x0a)
589 ungetc(ch
, fp
); /* Nope, save it for later... */
600 * Nul-terminate the string and return it (or NULL for EOF).
605 if (ch
== EOF
&& bufptr
== buf
)
613 * 'start_nup()' - Start processing for N-up printing...
617 start_nup(int number
) /* I - Page number */
619 int x
, y
; /* Relative position of subpage */
620 float w
, l
, /* Width and length of subpage */
621 tx
, ty
; /* Translation values for subpage */
627 printf("%.0f 0 translate -1 1 scale\n", PageWidth
);
631 case 1 : /* Landscape */
632 printf("%.0f 0 translate 90 rotate\n", PageLength
);
634 case 2 : /* Reverse Portrait */
635 printf("%.0f %.0f translate 180 rotate\n", PageWidth
, PageLength
);
637 case 3 : /* Reverse Landscape */
638 printf("0 %.0f translate -90 rotate\n", PageWidth
);
651 l
= w
* PageLength
/ PageWidth
;
653 if (l
> (PageWidth
* 0.5))
656 w
= l
* PageWidth
/ PageLength
;
659 tx
= PageWidth
* 0.5 - l
;
660 ty
= (PageLength
- w
) * 0.5;
665 w
= l
* PageWidth
/ PageLength
;
667 if (w
> (PageLength
* 0.5))
669 w
= PageLength
* 0.5;
670 l
= w
* PageLength
/ PageWidth
;
673 tx
= PageLength
* 0.5 - w
;
674 ty
= (PageWidth
- l
) * 0.5;
679 printf("0 %.0f translate -90 rotate\n", PageLength
);
680 printf("%.0f %.0f translate %.3f %.3f scale\n",
681 ty
, tx
+ l
* x
, w
/ PageWidth
, l
/ PageLength
);
685 printf("%.0f 0 translate 90 rotate\n", PageWidth
);
686 printf("%.0f %.0f translate %.3f %.3f scale\n",
687 tx
+ w
* x
, ty
, w
/ PageWidth
, l
/ PageLength
);
695 "closepath clip newpath\n",
696 PageWidth
, PageWidth
, PageLength
, PageLength
);
701 y
= 1 - ((number
& 2) != 0);
703 l
= PageLength
* 0.5;
705 printf("%.0f %.0f translate 0.5 0.5 scale\n", x
* w
, y
* l
);
711 "closepath clip newpath\n",
712 PageWidth
, PageWidth
, PageLength
, PageLength
);
719 * End of "$Id: pstops.c,v 1.17 1999/05/18 21:21:46 mike Exp $".