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