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