]>
Commit | Line | Data |
---|---|---|
516ba4c9 | 1 | /* |
c9d3f842 | 2 | * "$Id$" |
516ba4c9 | 3 | * |
ed19bd98 | 4 | * Image file to PostScript filter for the Common UNIX Printing System (CUPS). |
516ba4c9 | 5 | * |
c9d3f842 | 6 | * Copyright 1993-2005 by Easy Software Products. |
516ba4c9 | 7 | * |
ed19bd98 | 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: | |
516ba4c9 | 14 | * |
ed19bd98 | 15 | * Attn: CUPS Licensing Information |
16 | * Easy Software Products | |
17 | * 44141 Airport View Drive, Suite 204 | |
c9d3f842 | 18 | * Hollywood, Maryland 20636 USA |
af526a52 | 19 | * |
9639c4de | 20 | * Voice: (301) 373-9600 |
ed19bd98 | 21 | * EMail: cups-info@cups.org |
22 | * WWW: http://www.cups.org | |
d850a9e1 | 23 | * |
dab1a4d8 | 24 | * This file is subject to the Apple OS-Developed Software exception. |
25 | * | |
ed19bd98 | 26 | * Contents: |
516ba4c9 | 27 | * |
ed19bd98 | 28 | * main() - Main entry... |
29 | * ps_hex() - Print binary data as a series of hexadecimal numbers. | |
30 | * ps_ascii85() - Print binary data as a series of base-85 numbers. | |
516ba4c9 | 31 | */ |
32 | ||
33 | /* | |
34 | * Include necessary headers... | |
35 | */ | |
36 | ||
ed19bd98 | 37 | #include "common.h" |
516ba4c9 | 38 | #include "image.h" |
ed19bd98 | 39 | #include <math.h> |
516ba4c9 | 40 | |
41 | ||
42 | /* | |
43 | * Globals... | |
44 | */ | |
45 | ||
ed19bd98 | 46 | int Flip = 0, /* Flip/mirror pages */ |
c5da5726 | 47 | XPosition = 0, /* Horizontal position on page */ |
48 | YPosition = 0, /* Vertical position on page */ | |
ed19bd98 | 49 | Collate = 0, /* Collate copies? */ |
50 | Copies = 1; /* Number of copies */ | |
516ba4c9 | 51 | |
52 | ||
53 | /* | |
54 | * Local functions... | |
55 | */ | |
56 | ||
b5cb0608 | 57 | static void ps_hex(ib_t *, int, int); |
ed19bd98 | 58 | static void ps_ascii85(ib_t *, int, int); |
516ba4c9 | 59 | |
60 | ||
61 | /* | |
62 | * 'main()' - Main entry... | |
63 | */ | |
64 | ||
ed19bd98 | 65 | int /* O - Exit status */ |
516ba4c9 | 66 | main(int argc, /* I - Number of command-line arguments */ |
67 | char *argv[]) /* I - Command-line arguments */ | |
68 | { | |
ed19bd98 | 69 | image_t *img; /* Image to print */ |
70 | float xprint, /* Printable area */ | |
71 | yprint, | |
72 | xinches, /* Total size in inches */ | |
73 | yinches; | |
74 | float xsize, /* Total size in points */ | |
48c4ffef | 75 | ysize, |
76 | xsize2, | |
77 | ysize2; | |
332197a2 | 78 | float aspect; /* Aspect ratio */ |
ed19bd98 | 79 | int xpages, /* # x pages */ |
80 | ypages, /* # y pages */ | |
81 | xpage, /* Current x page */ | |
82 | ypage, /* Current y page */ | |
de8a4f54 | 83 | page; /* Current page number */ |
ed19bd98 | 84 | int x0, y0, /* Corners of the page in image coords */ |
85 | x1, y1; | |
86 | ib_t *row; /* Current row */ | |
87 | int y; /* Current Y coordinate in image */ | |
88 | int colorspace; /* Output colorspace */ | |
89 | int out_offset, /* Offset into output buffer */ | |
90 | out_length; /* Length of output buffer */ | |
91 | ppd_file_t *ppd; /* PPD file */ | |
b5cb0608 | 92 | ppd_choice_t *choice; /* PPD option choice */ |
ed19bd98 | 93 | int num_options; /* Number of print options */ |
94 | cups_option_t *options; /* Print options */ | |
568d2c2f | 95 | const char *val; /* Option value */ |
ed19bd98 | 96 | int slowcollate; /* Collate copies the slow way */ |
97 | float g; /* Gamma correction value */ | |
98 | float b; /* Brightness factor */ | |
99 | float zoom; /* Zoom facter */ | |
332197a2 | 100 | int xppi, yppi; /* Pixels-per-inch */ |
ed19bd98 | 101 | int hue, sat; /* Hue and saturation adjustment */ |
19ec0c2c | 102 | int realcopies; /* Real copies being printed */ |
c5da5726 | 103 | float left, top; /* Left and top of image */ |
7ce9aa3d | 104 | char filename[1024]; /* Name of file to print */ |
b5cb0608 | 105 | time_t curtime; /* Current time */ |
106 | struct tm *curtm; /* Current date */ | |
107 | char curdate[255]; /* Current date string */ | |
ed19bd98 | 108 | |
109 | ||
7ce9aa3d | 110 | /* |
cc787dc1 | 111 | * Make sure status messages are not buffered... |
112 | */ | |
113 | ||
114 | setbuf(stderr, NULL); | |
115 | ||
116 | /* | |
117 | * Check command-line... | |
7ce9aa3d | 118 | */ |
119 | ||
120 | if (argc < 6 || argc > 7) | |
ed19bd98 | 121 | { |
7ce9aa3d | 122 | fputs("ERROR: imagetops job-id user title copies options [file]\n", stderr); |
ed19bd98 | 123 | return (1); |
124 | } | |
516ba4c9 | 125 | |
7ce9aa3d | 126 | fprintf(stderr, "INFO: %s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2], |
127 | argv[3], argv[4], argv[5], argv[6] ? argv[6] : "(null)"); | |
128 | ||
129 | /* | |
130 | * Copy stdin as needed... | |
131 | */ | |
132 | ||
133 | if (argc == 6) | |
134 | { | |
1b5bf964 | 135 | int fd; /* File to write to */ |
7ce9aa3d | 136 | char buffer[8192]; /* Buffer to read into */ |
137 | int bytes; /* # of bytes to read */ | |
138 | ||
139 | ||
1b5bf964 | 140 | if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) |
7ce9aa3d | 141 | { |
142 | perror("ERROR: Unable to copy image file"); | |
143 | return (1); | |
144 | } | |
145 | ||
1b5bf964 | 146 | fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n", |
7ce9aa3d | 147 | filename); |
148 | ||
149 | while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) | |
1b5bf964 | 150 | write(fd, buffer, bytes); |
151 | ||
152 | close(fd); | |
7ce9aa3d | 153 | } |
154 | else | |
def978d5 | 155 | strlcpy(filename, argv[6], sizeof(filename)); |
7ce9aa3d | 156 | |
516ba4c9 | 157 | /* |
ed19bd98 | 158 | * Process command-line options and write the prolog... |
516ba4c9 | 159 | */ |
160 | ||
ed19bd98 | 161 | zoom = 0.0; |
332197a2 | 162 | xppi = 0; |
163 | yppi = 0; | |
ed19bd98 | 164 | hue = 0; |
165 | sat = 100; | |
f0d2f1a4 | 166 | g = 1.0; |
ed19bd98 | 167 | b = 1.0; |
516ba4c9 | 168 | |
ae818f4d | 169 | Copies = atoi(argv[4]); |
170 | ||
ed19bd98 | 171 | options = NULL; |
172 | num_options = cupsParseOptions(argv[5], 0, &options); | |
516ba4c9 | 173 | |
de8a4f54 | 174 | ppd = SetCommonOptions(num_options, options, 0); |
516ba4c9 | 175 | |
ed19bd98 | 176 | if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) |
516ba4c9 | 177 | { |
ed19bd98 | 178 | /* |
179 | * This IPP attribute is unnecessarily complicated... | |
180 | * | |
181 | * single-document, separate-documents-collated-copies, and | |
182 | * single-document-new-sheet all require collated copies. | |
183 | * | |
3e41e580 | 184 | * separate-documents-uncollated-copies allows for uncollated copies. |
ed19bd98 | 185 | */ |
516ba4c9 | 186 | |
3e41e580 | 187 | Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0; |
ed19bd98 | 188 | } |
516ba4c9 | 189 | |
ed19bd98 | 190 | if ((val = cupsGetOption("Collate", num_options, options)) != NULL && |
a7b3e92e | 191 | strcasecmp(val, "True") == 0) |
ed19bd98 | 192 | Collate = 1; |
516ba4c9 | 193 | |
ed19bd98 | 194 | if ((val = cupsGetOption("gamma", num_options, options)) != NULL) |
195 | g = atoi(val) * 0.001f; | |
516ba4c9 | 196 | |
ed19bd98 | 197 | if ((val = cupsGetOption("brightness", num_options, options)) != NULL) |
198 | b = atoi(val) * 0.01f; | |
516ba4c9 | 199 | |
ed19bd98 | 200 | if ((val = cupsGetOption("scaling", num_options, options)) != NULL) |
201 | zoom = atoi(val) * 0.01; | |
516ba4c9 | 202 | |
ed19bd98 | 203 | if ((val = cupsGetOption("ppi", num_options, options)) != NULL) |
332197a2 | 204 | if (sscanf(val, "%dx%d", &xppi, &yppi) < 2) |
205 | yppi = xppi; | |
516ba4c9 | 206 | |
c5da5726 | 207 | if ((val = cupsGetOption("position", num_options, options)) != NULL) |
208 | { | |
209 | if (strcasecmp(val, "center") == 0) | |
210 | { | |
211 | XPosition = 0; | |
212 | YPosition = 0; | |
213 | } | |
214 | else if (strcasecmp(val, "top") == 0) | |
215 | { | |
216 | XPosition = 0; | |
217 | YPosition = 1; | |
218 | } | |
219 | else if (strcasecmp(val, "left") == 0) | |
220 | { | |
221 | XPosition = -1; | |
222 | YPosition = 0; | |
223 | } | |
224 | else if (strcasecmp(val, "right") == 0) | |
225 | { | |
226 | XPosition = 1; | |
227 | YPosition = 0; | |
228 | } | |
229 | else if (strcasecmp(val, "top-left") == 0) | |
230 | { | |
231 | XPosition = -1; | |
232 | YPosition = 1; | |
233 | } | |
234 | else if (strcasecmp(val, "top-right") == 0) | |
235 | { | |
236 | XPosition = 1; | |
237 | YPosition = 1; | |
238 | } | |
239 | else if (strcasecmp(val, "bottom") == 0) | |
240 | { | |
241 | XPosition = 0; | |
242 | YPosition = -1; | |
243 | } | |
244 | else if (strcasecmp(val, "bottom-left") == 0) | |
245 | { | |
246 | XPosition = -1; | |
247 | YPosition = -1; | |
248 | } | |
249 | else if (strcasecmp(val, "bottom-right") == 0) | |
250 | { | |
251 | XPosition = 1; | |
252 | YPosition = -1; | |
253 | } | |
254 | } | |
255 | ||
ed19bd98 | 256 | if ((val = cupsGetOption("saturation", num_options, options)) != NULL) |
257 | sat = atoi(val); | |
258 | ||
259 | if ((val = cupsGetOption("hue", num_options, options)) != NULL) | |
260 | hue = atoi(val); | |
516ba4c9 | 261 | |
a05e4307 | 262 | if ((val = cupsGetOption("mirror", num_options, options)) != NULL && |
263 | strcasecmp(val, "True") == 0) | |
264 | Flip = 1; | |
265 | ||
516ba4c9 | 266 | /* |
267 | * Open the input image to print... | |
268 | */ | |
269 | ||
350807be | 270 | colorspace = ColorDevice ? IMAGE_RGB_CMYK : IMAGE_WHITE; |
516ba4c9 | 271 | |
7ce9aa3d | 272 | img = ImageOpen(filename, colorspace, IMAGE_WHITE, sat, hue, NULL); |
273 | ||
274 | if (argc == 6) | |
275 | unlink(filename); | |
276 | ||
277 | if (img == NULL) | |
ed19bd98 | 278 | { |
279 | fputs("ERROR: Unable to open image file for printing!\n", stderr); | |
280 | ppdClose(ppd); | |
281 | return (1); | |
282 | } | |
516ba4c9 | 283 | |
ed19bd98 | 284 | colorspace = img->colorspace; |
516ba4c9 | 285 | |
286 | /* | |
287 | * Scale as necessary... | |
288 | */ | |
289 | ||
332197a2 | 290 | if (zoom == 0.0 && xppi == 0) |
291 | { | |
292 | xppi = img->xppi; | |
293 | yppi = img->yppi; | |
294 | } | |
295 | ||
296 | if (yppi == 0) | |
297 | yppi = xppi; | |
298 | ||
34089ee8 | 299 | fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n", |
300 | xppi, yppi, zoom); | |
e6d607f1 | 301 | |
332197a2 | 302 | if (xppi > 0) |
516ba4c9 | 303 | { |
304 | /* | |
305 | * Scale the image as neccesary to match the desired pixels-per-inch. | |
306 | */ | |
307 | ||
95a58aca | 308 | if (Orientation & 1) |
309 | { | |
310 | xprint = (PageTop - PageBottom) / 72.0; | |
311 | yprint = (PageRight - PageLeft) / 72.0; | |
312 | } | |
313 | else | |
314 | { | |
315 | xprint = (PageRight - PageLeft) / 72.0; | |
316 | yprint = (PageTop - PageBottom) / 72.0; | |
317 | } | |
318 | ||
319 | fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", | |
320 | xprint, yprint); | |
321 | ||
332197a2 | 322 | xinches = (float)img->xsize / (float)xppi; |
323 | yinches = (float)img->ysize / (float)yppi; | |
48c4ffef | 324 | |
e6d607f1 | 325 | fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n", |
326 | xinches, yinches); | |
327 | ||
753453e4 | 328 | if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL) |
329 | { | |
330 | xinches = xinches * atoi(val) / 100; | |
331 | yinches = yinches * atoi(val) / 100; | |
332 | } | |
333 | ||
a28d12c5 | 334 | if (cupsGetOption("orientation-requested", num_options, options) == NULL && |
b16dd9cb | 335 | cupsGetOption("landscape", num_options, options) == NULL) |
48c4ffef | 336 | { |
337 | /* | |
b16dd9cb | 338 | * Rotate the image if it will fit landscape but not portrait... |
48c4ffef | 339 | */ |
340 | ||
e6d607f1 | 341 | fputs("DEBUG: Auto orientation...\n", stderr); |
342 | ||
b16dd9cb | 343 | if ((xinches > xprint || yinches > yprint) && |
344 | xinches <= yprint && yinches <= xprint) | |
345 | { | |
346 | /* | |
347 | * Rotate the image as needed... | |
348 | */ | |
349 | ||
e6d607f1 | 350 | fputs("DEBUG: Using landscape orientation...\n", stderr); |
351 | ||
b16dd9cb | 352 | Orientation = (Orientation + 1) & 3; |
353 | xsize = yprint; | |
354 | yprint = xprint; | |
355 | xprint = xsize; | |
b16dd9cb | 356 | } |
48c4ffef | 357 | } |
516ba4c9 | 358 | } |
359 | else | |
360 | { | |
361 | /* | |
362 | * Scale percentage of page size... | |
363 | */ | |
364 | ||
95a58aca | 365 | xprint = (PageRight - PageLeft) / 72.0; |
366 | yprint = (PageTop - PageBottom) / 72.0; | |
332197a2 | 367 | aspect = (float)img->yppi / (float)img->xppi; |
368 | ||
95a58aca | 369 | fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", |
370 | xprint, yprint); | |
371 | ||
332197a2 | 372 | fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n", |
373 | img->xppi, img->yppi, aspect); | |
374 | ||
ed19bd98 | 375 | xsize = xprint * zoom; |
332197a2 | 376 | ysize = xsize * img->ysize / img->xsize / aspect; |
0169953d | 377 | |
ed19bd98 | 378 | if (ysize > (yprint * zoom)) |
516ba4c9 | 379 | { |
ed19bd98 | 380 | ysize = yprint * zoom; |
332197a2 | 381 | xsize = ysize * img->xsize * aspect / img->ysize; |
516ba4c9 | 382 | } |
0169953d | 383 | |
48c4ffef | 384 | xsize2 = yprint * zoom; |
332197a2 | 385 | ysize2 = xsize2 * img->ysize / img->xsize / aspect; |
48c4ffef | 386 | |
387 | if (ysize2 > (xprint * zoom)) | |
388 | { | |
389 | ysize2 = xprint * zoom; | |
332197a2 | 390 | xsize2 = ysize2 * img->xsize * aspect / img->ysize; |
48c4ffef | 391 | } |
392 | ||
e6d607f1 | 393 | fprintf(stderr, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize, ysize); |
394 | fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2); | |
332197a2 | 395 | |
a28d12c5 | 396 | if (cupsGetOption("orientation-requested", num_options, options) == NULL && |
b16dd9cb | 397 | cupsGetOption("landscape", num_options, options) == NULL) |
48c4ffef | 398 | { |
399 | /* | |
b16dd9cb | 400 | * Choose the rotation with the largest area, but prefer |
401 | * portrait if they are equal... | |
48c4ffef | 402 | */ |
403 | ||
e6d607f1 | 404 | fputs("DEBUG: Auto orientation...\n", stderr); |
405 | ||
b16dd9cb | 406 | if ((xsize * ysize) < (xsize2 * xsize2)) |
407 | { | |
408 | /* | |
409 | * Do landscape orientation... | |
410 | */ | |
411 | ||
e6d607f1 | 412 | fputs("DEBUG: Using landscape orientation...\n", stderr); |
413 | ||
b16dd9cb | 414 | Orientation = 1; |
415 | xinches = xsize2; | |
416 | yinches = ysize2; | |
417 | xprint = (PageTop - PageBottom) / 72.0; | |
418 | yprint = (PageRight - PageLeft) / 72.0; | |
b16dd9cb | 419 | } |
420 | else | |
421 | { | |
422 | /* | |
423 | * Do portrait orientation... | |
424 | */ | |
425 | ||
e6d607f1 | 426 | fputs("DEBUG: Using portrait orientation...\n", stderr); |
427 | ||
b16dd9cb | 428 | Orientation = 0; |
429 | xinches = xsize; | |
430 | yinches = ysize; | |
431 | } | |
432 | } | |
433 | else if (Orientation & 1) | |
434 | { | |
e6d607f1 | 435 | fputs("DEBUG: Using landscape orientation...\n", stderr); |
436 | ||
48c4ffef | 437 | xinches = xsize2; |
438 | yinches = ysize2; | |
439 | xprint = (PageTop - PageBottom) / 72.0; | |
440 | yprint = (PageRight - PageLeft) / 72.0; | |
48c4ffef | 441 | } |
b6ea8f29 | 442 | else |
443 | { | |
e6d607f1 | 444 | fputs("DEBUG: Using portrait orientation...\n", stderr); |
445 | ||
b6ea8f29 | 446 | xinches = xsize; |
447 | yinches = ysize; | |
448 | xprint = (PageRight - PageLeft) / 72.0; | |
449 | yprint = (PageTop - PageBottom) / 72.0; | |
450 | } | |
ed19bd98 | 451 | } |
516ba4c9 | 452 | |
b5cb0608 | 453 | /* |
454 | * Compute the number of pages to print and the size of the image on each | |
455 | * page... | |
456 | */ | |
457 | ||
ed19bd98 | 458 | xpages = ceil(xinches / xprint); |
459 | ypages = ceil(yinches / yprint); | |
0169953d | 460 | |
b5cb0608 | 461 | xprint = xinches / xpages; |
462 | yprint = yinches / ypages; | |
463 | ||
95a58aca | 464 | fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n", |
465 | xpages, xprint, ypages, yprint); | |
466 | ||
b5cb0608 | 467 | /* |
468 | * Update the page size for custom sizes... | |
469 | */ | |
470 | ||
471 | if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL && | |
472 | strcasecmp(choice->choice, "Custom") == 0) | |
473 | { | |
474 | float width, /* New width in points */ | |
475 | length; /* New length in points */ | |
476 | char s[255]; /* New custom page size... */ | |
477 | ||
478 | ||
df585e0d | 479 | /* |
480 | * Use the correct width and length for the current orientation... | |
481 | */ | |
482 | ||
483 | if (Orientation & 1) | |
484 | { | |
485 | width = yprint * 72.0; | |
486 | length = xprint * 72.0; | |
487 | } | |
488 | else | |
489 | { | |
490 | width = xprint * 72.0; | |
491 | length = yprint * 72.0; | |
492 | } | |
493 | ||
b5cb0608 | 494 | /* |
495 | * Add margins to page size... | |
496 | */ | |
497 | ||
df585e0d | 498 | width += ppd->custom_margins[0] + ppd->custom_margins[2]; |
499 | length += ppd->custom_margins[1] + ppd->custom_margins[3]; | |
b5cb0608 | 500 | |
501 | /* | |
502 | * Enforce minimums... | |
503 | */ | |
504 | ||
505 | if (width < ppd->custom_min[0]) | |
506 | width = ppd->custom_min[0]; | |
507 | ||
508 | if (length < ppd->custom_min[1]) | |
509 | length = ppd->custom_min[1]; | |
510 | ||
95a58aca | 511 | fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n", |
512 | width / 72.0, length / 72.0); | |
513 | ||
b5cb0608 | 514 | /* |
515 | * Set the new custom size... | |
516 | */ | |
517 | ||
518 | sprintf(s, "Custom.%.0fx%.0f", width, length); | |
519 | ppdMarkOption(ppd, "PageSize", s); | |
520 | ||
521 | /* | |
522 | * Update page variables... | |
523 | */ | |
524 | ||
525 | PageWidth = width; | |
526 | PageLength = length; | |
527 | PageLeft = ppd->custom_margins[0]; | |
528 | PageRight = width - ppd->custom_margins[2]; | |
529 | PageBottom = ppd->custom_margins[1]; | |
530 | PageTop = length - ppd->custom_margins[3]; | |
b5cb0608 | 531 | } |
532 | ||
ed19bd98 | 533 | /* |
534 | * See if we need to collate, and if so how we need to do it... | |
535 | */ | |
516ba4c9 | 536 | |
ed19bd98 | 537 | if (xpages == 1 && ypages == 1) |
538 | Collate = 0; | |
516ba4c9 | 539 | |
ed19bd98 | 540 | slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL; |
516ba4c9 | 541 | |
b5cb0608 | 542 | if (Copies > 1 && !slowcollate) |
543 | { | |
544 | realcopies = Copies; | |
545 | Copies = 1; | |
546 | } | |
547 | else | |
548 | realcopies = 1; | |
549 | ||
ed19bd98 | 550 | /* |
551 | * Write any "exit server" options that have been selected... | |
552 | */ | |
516ba4c9 | 553 | |
ed19bd98 | 554 | ppdEmit(ppd, stdout, PPD_ORDER_EXIT); |
516ba4c9 | 555 | |
ed19bd98 | 556 | /* |
557 | * Write any JCL commands that are needed to print PostScript code... | |
558 | */ | |
559 | ||
ee6a18b5 | 560 | ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]); |
516ba4c9 | 561 | |
562 | /* | |
ed19bd98 | 563 | * Start sending the document with any commands needed... |
516ba4c9 | 564 | */ |
565 | ||
b5cb0608 | 566 | curtime = time(NULL); |
567 | curtm = localtime(&curtime); | |
568 | ||
569 | puts("%!PS-Adobe-3.0"); | |
570 | printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom, | |
571 | PageRight, PageTop); | |
572 | printf("%%%%LanguageLevel: %d\n", LanguageLevel); | |
573 | printf("%%%%Pages: %d\n", xpages * ypages * Copies); | |
574 | puts("%%DocumentData: Clean7Bit"); | |
575 | puts("%%DocumentNeededResources: font Helvetica-Bold"); | |
576 | puts("%%Creator: imagetops/" CUPS_SVERSION); | |
03f61bf3 | 577 | strftime(curdate, sizeof(curdate), "%c", curtm); |
b5cb0608 | 578 | printf("%%%%CreationDate: %s\n", curdate); |
579 | printf("%%%%Title: %s\n", argv[3]); | |
580 | printf("%%%%For: %s\n", argv[2]); | |
581 | if (Orientation & 1) | |
582 | puts("%%Orientation: Landscape"); | |
904eef76 | 583 | else |
584 | puts("%%Orientation: Portrait"); | |
b5cb0608 | 585 | puts("%%EndComments"); |
586 | puts("%%BeginProlog"); | |
ed19bd98 | 587 | |
37b19c12 | 588 | if (ppd != NULL && ppd->patches != NULL) |
589 | puts(ppd->patches); | |
590 | ||
ed19bd98 | 591 | ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT); |
592 | ppdEmit(ppd, stdout, PPD_ORDER_ANY); | |
593 | ppdEmit(ppd, stdout, PPD_ORDER_PROLOG); | |
516ba4c9 | 594 | |
ed19bd98 | 595 | if (g != 1.0 || b != 1.0) |
37b19c12 | 596 | printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } " |
597 | "ifelse %.3f mul } bind settransfer\n", g, b); | |
ed19bd98 | 598 | |
de8a4f54 | 599 | WriteCommon(); |
df585e0d | 600 | switch (Orientation) |
601 | { | |
602 | case 0 : | |
603 | WriteLabelProlog(cupsGetOption("page-label", num_options, options), | |
604 | PageBottom, PageTop, PageWidth); | |
605 | break; | |
606 | ||
607 | case 1 : | |
608 | WriteLabelProlog(cupsGetOption("page-label", num_options, options), | |
609 | PageLeft, PageRight, PageLength); | |
610 | break; | |
611 | ||
612 | case 2 : | |
613 | WriteLabelProlog(cupsGetOption("page-label", num_options, options), | |
614 | PageLength - PageTop, PageLength - PageBottom, | |
615 | PageWidth); | |
616 | break; | |
617 | ||
618 | case 3 : | |
619 | WriteLabelProlog(cupsGetOption("page-label", num_options, options), | |
620 | PageWidth - PageRight, PageWidth - PageLeft, | |
621 | PageLength); | |
622 | break; | |
623 | } | |
d11458ff | 624 | |
b5cb0608 | 625 | if (realcopies > 1) |
516ba4c9 | 626 | { |
83f08393 | 627 | if (ppd == NULL || ppd->language_level == 1) |
b5cb0608 | 628 | printf("/#copies %d def\n", realcopies); |
83f08393 | 629 | else |
b5cb0608 | 630 | printf("<</NumCopies %d>>setpagedevice\n", realcopies); |
ed19bd98 | 631 | } |
b5cb0608 | 632 | |
633 | puts("%%EndProlog"); | |
516ba4c9 | 634 | |
635 | /* | |
636 | * Output the pages... | |
637 | */ | |
638 | ||
b5cb0608 | 639 | row = malloc(img->xsize * abs(colorspace) + 3); |
0169953d | 640 | |
de8a4f54 | 641 | fprintf(stderr, "DEBUG: XPosition=%d, YPosition=%d, Orientation=%d\n", |
642 | XPosition, YPosition, Orientation); | |
643 | fprintf(stderr, "DEBUG: xprint=%.0f, yprint=%.0f\n", xprint, yprint); | |
644 | fprintf(stderr, "DEBUG: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f\n", | |
645 | PageLeft, PageRight, PageWidth); | |
646 | fprintf(stderr, "DEBUG: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f\n", | |
647 | PageBottom, PageTop, PageLength); | |
648 | ||
df585e0d | 649 | switch (Orientation) |
650 | { | |
4a0fc5ef | 651 | default : |
df585e0d | 652 | switch (XPosition) |
653 | { | |
654 | case -1 : | |
655 | left = PageLeft; | |
656 | break; | |
657 | default : | |
658 | left = (PageRight + PageLeft - xprint * 72) / 2; | |
659 | break; | |
660 | case 1 : | |
661 | left = PageRight - xprint * 72; | |
662 | break; | |
663 | } | |
664 | ||
665 | switch (YPosition) | |
666 | { | |
667 | case -1 : | |
668 | top = PageBottom + yprint * 72; | |
669 | break; | |
670 | default : | |
671 | top = (PageTop + PageBottom + yprint * 72) / 2; | |
672 | break; | |
673 | case 1 : | |
674 | top = PageTop; | |
675 | break; | |
676 | } | |
677 | break; | |
678 | ||
679 | case 1 : | |
680 | switch (XPosition) | |
681 | { | |
682 | case -1 : | |
683 | left = PageBottom; | |
684 | break; | |
685 | default : | |
686 | left = (PageTop + PageBottom - xprint * 72) / 2; | |
687 | break; | |
688 | case 1 : | |
689 | left = PageTop - xprint * 72; | |
690 | break; | |
691 | } | |
692 | ||
693 | switch (YPosition) | |
694 | { | |
695 | case -1 : | |
696 | top = PageLeft + yprint * 72; | |
697 | break; | |
698 | default : | |
699 | top = (PageRight + PageLeft + yprint * 72) / 2; | |
700 | break; | |
701 | case 1 : | |
702 | top = PageRight; | |
703 | break; | |
704 | } | |
705 | break; | |
706 | ||
707 | case 2 : | |
708 | switch (XPosition) | |
709 | { | |
710 | case 1 : | |
711 | left = PageLeft; | |
712 | break; | |
713 | default : | |
714 | left = (PageRight + PageLeft - xprint * 72) / 2; | |
715 | break; | |
716 | case -1 : | |
717 | left = PageRight - xprint * 72; | |
718 | break; | |
719 | } | |
720 | ||
721 | switch (YPosition) | |
722 | { | |
723 | case 1 : | |
724 | top = PageBottom + yprint * 72; | |
725 | break; | |
726 | default : | |
727 | top = (PageTop + PageBottom + yprint * 72) / 2; | |
728 | break; | |
729 | case -1 : | |
730 | top = PageTop; | |
731 | break; | |
732 | } | |
733 | break; | |
734 | ||
735 | case 3 : | |
736 | switch (XPosition) | |
737 | { | |
738 | case 1 : | |
739 | left = PageBottom; | |
740 | break; | |
741 | default : | |
742 | left = (PageTop + PageBottom - xprint * 72) / 2; | |
743 | break; | |
744 | case -1 : | |
745 | left = PageTop - xprint * 72; | |
746 | break; | |
747 | } | |
748 | ||
749 | switch (YPosition) | |
750 | { | |
751 | case 1 : | |
752 | top = PageLeft + yprint * 72; | |
753 | break; | |
754 | default : | |
755 | top = (PageRight + PageLeft + yprint * 72) / 2; | |
756 | break; | |
757 | case -1 : | |
758 | top = PageRight; | |
759 | break; | |
760 | } | |
761 | break; | |
762 | } | |
763 | ||
764 | fprintf(stderr, "DEBUG: left=%.2f, top=%.2f\n", left, top); | |
765 | ||
ed19bd98 | 766 | for (page = 1; Copies > 0; Copies --) |
767 | for (xpage = 0; xpage < xpages; xpage ++) | |
768 | for (ypage = 0; ypage < ypages; ypage ++, page ++) | |
769 | { | |
b5cb0608 | 770 | if (ppd && ppd->num_filters == 0) |
771 | fprintf(stderr, "PAGE: %d %d\n", page, realcopies); | |
772 | ||
773 | fprintf(stderr, "INFO: Printing page %d...\n", page); | |
774 | ||
775 | printf("%%%%Page: %d %d\n", page, page); | |
516ba4c9 | 776 | |
ed19bd98 | 777 | ppdEmit(ppd, stdout, PPD_ORDER_PAGE); |
516ba4c9 | 778 | |
ed19bd98 | 779 | puts("gsave"); |
516ba4c9 | 780 | |
ed19bd98 | 781 | if (Flip) |
782 | printf("%.0f 0 translate -1 1 scale\n", PageWidth); | |
783 | ||
784 | switch (Orientation) | |
785 | { | |
786 | case 1 : /* Landscape */ | |
df585e0d | 787 | printf("%.0f 0 translate 90 rotate\n", PageWidth); |
ed19bd98 | 788 | break; |
789 | case 2 : /* Reverse Portrait */ | |
790 | printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); | |
791 | break; | |
792 | case 3 : /* Reverse Landscape */ | |
df585e0d | 793 | printf("0 %.0f translate -90 rotate\n", PageLength); |
ed19bd98 | 794 | break; |
795 | } | |
516ba4c9 | 796 | |
df585e0d | 797 | puts("gsave"); |
798 | ||
5398375f | 799 | x0 = img->xsize * xpage / xpages; |
800 | x1 = img->xsize * (xpage + 1) / xpages - 1; | |
801 | y0 = img->ysize * ypage / ypages; | |
802 | y1 = img->ysize * (ypage + 1) / ypages - 1; | |
516ba4c9 | 803 | |
c5da5726 | 804 | printf("%.1f %.1f translate\n", left, top); |
805 | ||
ed19bd98 | 806 | printf("%.3f %.3f scale\n\n", |
807 | xprint * 72.0 / (x1 - x0 + 1), | |
808 | yprint * 72.0 / (y1 - y0 + 1)); | |
516ba4c9 | 809 | |
ed19bd98 | 810 | if (LanguageLevel == 1) |
af526a52 | 811 | { |
ed19bd98 | 812 | printf("/picture %d string def\n", (x1 - x0 + 1) * abs(colorspace)); |
813 | printf("%d %d 8[1 0 0 -1 0 1]", (x1 - x0 + 1), (y1 - y0 + 1)); | |
814 | ||
815 | if (colorspace == IMAGE_WHITE) | |
816 | puts("{currentfile picture readhexstring pop} image"); | |
af526a52 | 817 | else |
350807be | 818 | printf("{currentfile picture readhexstring pop} false %d colorimage\n", |
819 | abs(colorspace)); | |
ed19bd98 | 820 | |
821 | for (y = y0; y <= y1; y ++) | |
822 | { | |
823 | ImageGetRow(img, x0, y, x1 - x0 + 1, row); | |
b5cb0608 | 824 | ps_hex(row, (x1 - x0 + 1) * abs(colorspace), y == y1); |
ed19bd98 | 825 | } |
af526a52 | 826 | } |
827 | else | |
828 | { | |
350807be | 829 | switch (colorspace) |
830 | { | |
831 | case IMAGE_WHITE : | |
832 | puts("/DeviceGray setcolorspace"); | |
833 | break; | |
834 | case IMAGE_RGB : | |
835 | puts("/DeviceRGB setcolorspace"); | |
836 | break; | |
837 | case IMAGE_CMYK : | |
838 | puts("/DeviceCMYK setcolorspace"); | |
839 | break; | |
840 | } | |
af526a52 | 841 | |
ed19bd98 | 842 | printf("<<" |
843 | "/ImageType 1" | |
844 | "/Width %d" | |
845 | "/Height %d" | |
846 | "/BitsPerComponent 8", | |
847 | x1 - x0 + 1, y1 - y0 + 1); | |
af526a52 | 848 | |
350807be | 849 | switch (colorspace) |
850 | { | |
851 | case IMAGE_WHITE : | |
852 | fputs("/Decode[0 1]", stdout); | |
853 | break; | |
854 | case IMAGE_RGB : | |
855 | fputs("/Decode[0 1 0 1 0 1]", stdout); | |
856 | break; | |
857 | case IMAGE_CMYK : | |
858 | fputs("/Decode[0 1 0 1 0 1 0 1]", stdout); | |
859 | break; | |
860 | } | |
af526a52 | 861 | |
ed19bd98 | 862 | fputs("/DataSource currentfile /ASCII85Decode filter", stdout); |
af526a52 | 863 | |
ed19bd98 | 864 | if (((x1 - x0 + 1) / xprint) < 100.0) |
865 | fputs("/Interpolate true", stdout); | |
5398375f | 866 | |
ed19bd98 | 867 | puts("/ImageMatrix[1 0 0 -1 0 1]>>image"); |
af526a52 | 868 | |
ed19bd98 | 869 | for (y = y0, out_offset = 0; y <= y1; y ++) |
870 | { | |
871 | ImageGetRow(img, x0, y, x1 - x0 + 1, row + out_offset); | |
af526a52 | 872 | |
ed19bd98 | 873 | out_length = (x1 - x0 + 1) * abs(colorspace) + out_offset; |
874 | out_offset = out_length & 3; | |
516ba4c9 | 875 | |
ed19bd98 | 876 | ps_ascii85(row, out_length, y == y1); |
516ba4c9 | 877 | |
ed19bd98 | 878 | if (out_offset > 0) |
879 | memcpy(row, row + out_length - out_offset, out_offset); | |
880 | } | |
881 | } | |
516ba4c9 | 882 | |
ed19bd98 | 883 | puts("grestore"); |
df585e0d | 884 | WriteLabels(0); |
885 | puts("grestore"); | |
ed19bd98 | 886 | puts("showpage"); |
887 | } | |
516ba4c9 | 888 | |
b5cb0608 | 889 | puts("%%EOF"); |
890 | ||
ed19bd98 | 891 | /* |
892 | * End the job with the appropriate JCL command or CTRL-D otherwise. | |
893 | */ | |
516ba4c9 | 894 | |
625ced05 | 895 | ppdEmitJCLEnd(ppd, stdout); |
516ba4c9 | 896 | |
ed19bd98 | 897 | /* |
898 | * Close files... | |
899 | */ | |
516ba4c9 | 900 | |
901 | ImageClose(img); | |
ed19bd98 | 902 | ppdClose(ppd); |
516ba4c9 | 903 | |
ed19bd98 | 904 | return (0); |
516ba4c9 | 905 | } |
906 | ||
907 | ||
908 | /* | |
909 | * 'ps_hex()' - Print binary data as a series of hexadecimal numbers. | |
910 | */ | |
911 | ||
912 | static void | |
b5cb0608 | 913 | ps_hex(ib_t *data, /* I - Data to print */ |
914 | int length, /* I - Number of bytes to print */ | |
915 | int last_line) /* I - Last line of raster data? */ | |
516ba4c9 | 916 | { |
b5cb0608 | 917 | static int col = 0; /* Current column */ |
516ba4c9 | 918 | static char *hex = "0123456789ABCDEF"; |
b5cb0608 | 919 | /* Hex digits */ |
516ba4c9 | 920 | |
921 | ||
922 | while (length > 0) | |
923 | { | |
924 | /* | |
ed19bd98 | 925 | * Put the hex chars out to the file; note that we don't use printf() |
516ba4c9 | 926 | * for speed reasons... |
927 | */ | |
928 | ||
ed19bd98 | 929 | putchar(hex[*data >> 4]); |
930 | putchar(hex[*data & 15]); | |
516ba4c9 | 931 | |
932 | data ++; | |
933 | length --; | |
af526a52 | 934 | |
b5cb0608 | 935 | col += 2; |
936 | if (col > 78) | |
937 | { | |
ed19bd98 | 938 | putchar('\n'); |
b5cb0608 | 939 | col = 0; |
940 | } | |
ed19bd98 | 941 | } |
516ba4c9 | 942 | |
b5cb0608 | 943 | if (last_line && col) |
944 | { | |
945 | putchar('\n'); | |
946 | col = 0; | |
947 | } | |
516ba4c9 | 948 | } |
949 | ||
950 | ||
951 | /* | |
952 | * 'ps_ascii85()' - Print binary data as a series of base-85 numbers. | |
953 | */ | |
954 | ||
955 | static void | |
ed19bd98 | 956 | ps_ascii85(ib_t *data, /* I - Data to print */ |
516ba4c9 | 957 | int length, /* I - Number of bytes to print */ |
958 | int last_line) /* I - Last line of raster data? */ | |
959 | { | |
960 | unsigned b; /* Binary data word */ | |
961 | unsigned char c[5]; /* ASCII85 encoded chars */ | |
b5cb0608 | 962 | static int col = 0; /* Current column */ |
516ba4c9 | 963 | |
964 | ||
516ba4c9 | 965 | while (length > 3) |
966 | { | |
967 | b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; | |
968 | ||
969 | if (b == 0) | |
b5cb0608 | 970 | { |
ed19bd98 | 971 | putchar('z'); |
b5cb0608 | 972 | col ++; |
973 | } | |
516ba4c9 | 974 | else |
975 | { | |
976 | c[4] = (b % 85) + '!'; | |
977 | b /= 85; | |
978 | c[3] = (b % 85) + '!'; | |
979 | b /= 85; | |
980 | c[2] = (b % 85) + '!'; | |
981 | b /= 85; | |
982 | c[1] = (b % 85) + '!'; | |
983 | b /= 85; | |
984 | c[0] = b + '!'; | |
985 | ||
ed19bd98 | 986 | fwrite(c, 5, 1, stdout); |
b5cb0608 | 987 | col += 5; |
ed19bd98 | 988 | } |
516ba4c9 | 989 | |
990 | data += 4; | |
991 | length -= 4; | |
b5cb0608 | 992 | |
993 | if (col >= 75) | |
994 | { | |
995 | putchar('\n'); | |
996 | col = 0; | |
997 | } | |
ed19bd98 | 998 | } |
516ba4c9 | 999 | |
1000 | if (last_line) | |
1001 | { | |
1002 | if (length > 0) | |
1003 | { | |
4364903a | 1004 | memset(data + length, 0, 4 - length); |
1005 | b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; | |
516ba4c9 | 1006 | |
1007 | c[4] = (b % 85) + '!'; | |
1008 | b /= 85; | |
1009 | c[3] = (b % 85) + '!'; | |
1010 | b /= 85; | |
1011 | c[2] = (b % 85) + '!'; | |
1012 | b /= 85; | |
1013 | c[1] = (b % 85) + '!'; | |
1014 | b /= 85; | |
1015 | c[0] = b + '!'; | |
1016 | ||
ed19bd98 | 1017 | fwrite(c, length + 1, 1, stdout); |
1018 | } | |
516ba4c9 | 1019 | |
ed19bd98 | 1020 | puts("~>"); |
b5cb0608 | 1021 | col = 0; |
516ba4c9 | 1022 | } |
516ba4c9 | 1023 | } |
1024 | ||
1025 | ||
1026 | /* | |
c9d3f842 | 1027 | * End of "$Id$". |
516ba4c9 | 1028 | */ |