]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/imagetops.c
More localization work.
[thirdparty/cups.git] / filter / imagetops.c
1 /*
2 * "$Id$"
3 *
4 * Image file to PostScript filter for CUPS.
5 *
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1993-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
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/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
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.
22 */
23
24 /*
25 * Include necessary headers...
26 */
27
28 #include "common.h"
29 #include "image.h"
30 #include <math.h>
31 #include <cups/language-private.h>
32
33
34 /*
35 * Globals...
36 */
37
38 int Flip = 0, /* Flip/mirror pages */
39 XPosition = 0, /* Horizontal position on page */
40 YPosition = 0, /* Vertical position on page */
41 Collate = 0, /* Collate copies? */
42 Copies = 1; /* Number of copies */
43
44
45 /*
46 * Local functions...
47 */
48
49 static void ps_hex(cups_ib_t *, int, int);
50 static void ps_ascii85(cups_ib_t *, int, int);
51
52
53 /*
54 * 'main()' - Main entry...
55 */
56
57 int /* O - Exit status */
58 main(int argc, /* I - Number of command-line arguments */
59 char *argv[]) /* I - Command-line arguments */
60 {
61 cups_image_t *img; /* Image to print */
62 float xprint, /* Printable area */
63 yprint,
64 xinches, /* Total size in inches */
65 yinches;
66 float xsize, /* Total size in points */
67 ysize,
68 xsize2,
69 ysize2;
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 */
76 int xc0, yc0, /* Corners of the page in image coords */
77 xc1, yc1;
78 cups_ib_t *row; /* Current row */
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 */
94 int realcopies, /* Real copies being printed */
95 emit_jcl; /* Emit JCL? */
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 */
101
102
103 /*
104 * Make sure status messages are not buffered...
105 */
106
107 setbuf(stderr, NULL);
108
109 /*
110 * Check command-line...
111 */
112
113 if (argc < 6 || argc > 7)
114 {
115 _cupsLangPrintf(stderr,
116 _("Usage: %s job-id user title copies options file"),
117 argv[0]);
118 return (1);
119 }
120
121 /*
122 * Copy stdin as needed...
123 */
124
125 if (argc == 6)
126 {
127 int fd; /* File to write to */
128 char buffer[8192]; /* Buffer to read into */
129 int bytes; /* # of bytes to read */
130
131
132 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
133 {
134 _cupsLangPrintError("ERROR", _("Unable to copy print file"));
135 return (1);
136 }
137
138 fprintf(stderr, "DEBUG: imagetops - copying to temp print file \"%s\".\n",
139 filename);
140
141 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
142 write(fd, buffer, bytes);
143
144 close(fd);
145 }
146 else
147 strlcpy(filename, argv[6], sizeof(filename));
148
149 /*
150 * Process command-line options and write the prolog...
151 */
152
153 zoom = 0.0;
154 xppi = 0;
155 yppi = 0;
156 hue = 0;
157 sat = 100;
158 g = 1.0;
159 b = 1.0;
160
161 Copies = atoi(argv[4]);
162
163 options = NULL;
164 num_options = cupsParseOptions(argv[5], 0, &options);
165
166 ppd = SetCommonOptions(num_options, options, 0);
167
168 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
169 {
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 *
176 * separate-documents-uncollated-copies allows for uncollated copies.
177 */
178
179 Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
180 }
181
182 if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
183 strcasecmp(val, "True") == 0)
184 Collate = 1;
185
186 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
187 {
188 /*
189 * Get gamma value from 1 to 10000...
190 */
191
192 g = atoi(val) * 0.001f;
193
194 if (g < 0.001f)
195 g = 0.001f;
196 else if (g > 10.0f)
197 g = 10.0f;
198 }
199
200 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
201 {
202 /*
203 * Get brightness value from 10 to 1000.
204 */
205
206 b = atoi(val) * 0.01f;
207
208 if (b < 0.1f)
209 b = 0.1f;
210 else if (b > 10.0f)
211 b = 10.0f;
212 }
213
214 if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
215 zoom = atoi(val) * 0.01;
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"))
221 zoom = 1.0;
222
223 if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
224 if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
225 yppi = xppi;
226
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
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);
281
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")))
292 Flip = 1;
293
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
301 /*
302 * Open the input image to print...
303 */
304
305 colorspace = ColorDevice ? CUPS_IMAGE_RGB_CMYK : CUPS_IMAGE_WHITE;
306
307 img = cupsImageOpen(filename, colorspace, CUPS_IMAGE_WHITE, sat, hue, NULL);
308
309 if (argc == 6)
310 unlink(filename);
311
312 if (img == NULL)
313 {
314 _cupsLangPrintFilter(stderr, "ERROR",
315 _("The print file could not be opened."));
316 ppdClose(ppd);
317 return (1);
318 }
319
320 colorspace = cupsImageGetColorSpace(img);
321
322 /*
323 * Scale as necessary...
324 */
325
326 if (zoom == 0.0 && xppi == 0)
327 {
328 xppi = cupsImageGetXPPI(img);
329 yppi = cupsImageGetYPPI(img);
330 }
331
332 if (yppi == 0)
333 yppi = xppi;
334
335 fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
336 xppi, yppi, zoom);
337
338 if (xppi > 0)
339 {
340 /*
341 * Scale the image as neccesary to match the desired pixels-per-inch.
342 */
343
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
358 xinches = (float)cupsImageGetWidth(img) / (float)xppi;
359 yinches = (float)cupsImageGetHeight(img) / (float)yppi;
360
361 fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n",
362 xinches, yinches);
363
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
370 if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
371 cupsGetOption("landscape", num_options, options) == NULL)
372 {
373 /*
374 * Rotate the image if it will fit landscape but not portrait...
375 */
376
377 fputs("DEBUG: Auto orientation...\n", stderr);
378
379 if ((xinches > xprint || yinches > yprint) &&
380 xinches <= yprint && yinches <= xprint)
381 {
382 /*
383 * Rotate the image as needed...
384 */
385
386 fputs("DEBUG: Using landscape orientation...\n", stderr);
387
388 Orientation = (Orientation + 1) & 3;
389 xsize = yprint;
390 yprint = xprint;
391 xprint = xsize;
392 }
393 }
394 }
395 else
396 {
397 /*
398 * Scale percentage of page size...
399 */
400
401 xprint = (PageRight - PageLeft) / 72.0;
402 yprint = (PageTop - PageBottom) / 72.0;
403 aspect = (float)cupsImageGetYPPI(img) / (float)cupsImageGetXPPI(img);
404
405 fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
406 xprint, yprint);
407
408 fprintf(stderr, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n",
409 cupsImageGetXPPI(img), cupsImageGetYPPI(img), aspect);
410
411 xsize = xprint * zoom;
412 ysize = xsize * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect;
413
414 if (ysize > (yprint * zoom))
415 {
416 ysize = yprint * zoom;
417 xsize = ysize * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img);
418 }
419
420 xsize2 = yprint * zoom;
421 ysize2 = xsize2 * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect;
422
423 if (ysize2 > (xprint * zoom))
424 {
425 ysize2 = xprint * zoom;
426 xsize2 = ysize2 * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img);
427 }
428
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);
431
432 if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
433 cupsGetOption("landscape", num_options, options) == NULL)
434 {
435 /*
436 * Choose the rotation with the largest area, but prefer
437 * portrait if they are equal...
438 */
439
440 fputs("DEBUG: Auto orientation...\n", stderr);
441
442 if ((xsize * ysize) < (xsize2 * xsize2))
443 {
444 /*
445 * Do landscape orientation...
446 */
447
448 fputs("DEBUG: Using landscape orientation...\n", stderr);
449
450 Orientation = 1;
451 xinches = xsize2;
452 yinches = ysize2;
453 xprint = (PageTop - PageBottom) / 72.0;
454 yprint = (PageRight - PageLeft) / 72.0;
455 }
456 else
457 {
458 /*
459 * Do portrait orientation...
460 */
461
462 fputs("DEBUG: Using portrait orientation...\n", stderr);
463
464 Orientation = 0;
465 xinches = xsize;
466 yinches = ysize;
467 }
468 }
469 else if (Orientation & 1)
470 {
471 fputs("DEBUG: Using landscape orientation...\n", stderr);
472
473 xinches = xsize2;
474 yinches = ysize2;
475 xprint = (PageTop - PageBottom) / 72.0;
476 yprint = (PageRight - PageLeft) / 72.0;
477 }
478 else
479 {
480 fputs("DEBUG: Using portrait orientation...\n", stderr);
481
482 xinches = xsize;
483 yinches = ysize;
484 xprint = (PageRight - PageLeft) / 72.0;
485 yprint = (PageTop - PageBottom) / 72.0;
486 }
487 }
488
489 /*
490 * Compute the number of pages to print and the size of the image on each
491 * page...
492 */
493
494 xpages = ceil(xinches / xprint);
495 ypages = ceil(yinches / yprint);
496
497 xprint = xinches / xpages;
498 yprint = yinches / ypages;
499
500 fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
501 xpages, xprint, ypages, yprint);
502
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
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
530 /*
531 * Add margins to page size...
532 */
533
534 width += ppd->custom_margins[0] + ppd->custom_margins[2];
535 length += ppd->custom_margins[1] + ppd->custom_margins[3];
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
547 fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
548 width / 72.0, length / 72.0);
549
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];
567 }
568
569 /*
570 * See if we need to collate, and if so how we need to do it...
571 */
572
573 if (xpages == 1 && ypages == 1)
574 Collate = 0;
575
576 slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
577
578 if (Copies > 1 && !slowcollate)
579 {
580 realcopies = Copies;
581 Copies = 1;
582 }
583 else
584 realcopies = 1;
585
586 /*
587 * Write any "exit server" options that have been selected...
588 */
589
590 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
591
592 /*
593 * Write any JCL commands that are needed to print PostScript code...
594 */
595
596 if (emit_jcl)
597 ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
598
599 /*
600 * Start sending the document with any commands needed...
601 */
602
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);
614 strftime(curdate, sizeof(curdate), "%c", curtm);
615 printf("%%%%CreationDate: %s\n", curdate);
616 WriteTextComment("Title", argv[3]);
617 WriteTextComment("For", argv[2]);
618 if (Orientation & 1)
619 puts("%%Orientation: Landscape");
620 else
621 puts("%%Orientation: Portrait");
622 puts("%%EndComments");
623 puts("%%BeginProlog");
624
625 if (ppd != NULL && ppd->patches != NULL)
626 puts(ppd->patches);
627
628 ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
629 ppdEmit(ppd, stdout, PPD_ORDER_ANY);
630 ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
631
632 if (g != 1.0 || b != 1.0)
633 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
634 "ifelse %.3f mul } bind settransfer\n", g, b);
635
636 WriteCommon();
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 }
661
662 if (realcopies > 1)
663 {
664 if (ppd == NULL || ppd->language_level == 1)
665 printf("/#copies %d def\n", realcopies);
666 else
667 printf("<</NumCopies %d>>setpagedevice\n", realcopies);
668 }
669
670 puts("%%EndProlog");
671
672 /*
673 * Output the pages...
674 */
675
676 row = malloc(cupsImageGetWidth(img) * abs(colorspace) + 3);
677
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
686 switch (Orientation)
687 {
688 default :
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
803 for (page = 1; Copies > 0; Copies --)
804 for (xpage = 0; xpage < xpages; xpage ++)
805 for (ypage = 0; ypage < ypages; ypage ++, page ++)
806 {
807 if (ppd && ppd->num_filters == 0)
808 fprintf(stderr, "PAGE: %d %d\n", page, realcopies);
809
810 _cupsLangPrintFilter(stderr, "INFO", _("Printing page %d."), page);
811
812 printf("%%%%Page: %d %d\n", page, page);
813
814 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
815
816 puts("gsave");
817
818 if (Flip)
819 printf("%.0f 0 translate -1 1 scale\n", PageWidth);
820
821 switch (Orientation)
822 {
823 case 1 : /* Landscape */
824 printf("%.0f 0 translate 90 rotate\n", PageWidth);
825 break;
826 case 2 : /* Reverse Portrait */
827 printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
828 break;
829 case 3 : /* Reverse Landscape */
830 printf("0 %.0f translate -90 rotate\n", PageLength);
831 break;
832 }
833
834 puts("gsave");
835
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;
840
841 printf("%.1f %.1f translate\n", left, top);
842
843 printf("%.3f %.3f scale\n\n",
844 xprint * 72.0 / (xc1 - xc0 + 1),
845 yprint * 72.0 / (yc1 - yc0 + 1));
846
847 if (LanguageLevel == 1)
848 {
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));
851
852 if (colorspace == CUPS_IMAGE_WHITE)
853 puts("{currentfile picture readhexstring pop} image");
854 else
855 printf("{currentfile picture readhexstring pop} false %d colorimage\n",
856 abs(colorspace));
857
858 for (y = yc0; y <= yc1; y ++)
859 {
860 cupsImageGetRow(img, xc0, y, xc1 - xc0 + 1, row);
861 ps_hex(row, (xc1 - xc0 + 1) * abs(colorspace), y == yc1);
862 }
863 }
864 else
865 {
866 switch (colorspace)
867 {
868 case CUPS_IMAGE_WHITE :
869 puts("/DeviceGray setcolorspace");
870 break;
871 case CUPS_IMAGE_RGB :
872 puts("/DeviceRGB setcolorspace");
873 break;
874 case CUPS_IMAGE_CMYK :
875 puts("/DeviceCMYK setcolorspace");
876 break;
877 }
878
879 printf("<<"
880 "/ImageType 1"
881 "/Width %d"
882 "/Height %d"
883 "/BitsPerComponent 8",
884 xc1 - xc0 + 1, yc1 - yc0 + 1);
885
886 switch (colorspace)
887 {
888 case CUPS_IMAGE_WHITE :
889 fputs("/Decode[0 1]", stdout);
890 break;
891 case CUPS_IMAGE_RGB :
892 fputs("/Decode[0 1 0 1 0 1]", stdout);
893 break;
894 case CUPS_IMAGE_CMYK :
895 fputs("/Decode[0 1 0 1 0 1 0 1]", stdout);
896 break;
897 }
898
899 fputs("\n/DataSource currentfile/ASCII85Decode filter", stdout);
900
901 if (((xc1 - xc0 + 1) / xprint) < 100.0)
902 fputs("/Interpolate true", stdout);
903
904 puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
905
906 for (y = yc0, out_offset = 0; y <= yc1; y ++)
907 {
908 cupsImageGetRow(img, xc0, y, xc1 - xc0 + 1, row + out_offset);
909
910 out_length = (xc1 - xc0 + 1) * abs(colorspace) + out_offset;
911 out_offset = out_length & 3;
912
913 ps_ascii85(row, out_length, y == yc1);
914
915 if (out_offset > 0)
916 memcpy(row, row + out_length - out_offset, out_offset);
917 }
918 }
919
920 puts("grestore");
921 WriteLabels(0);
922 puts("grestore");
923 puts("showpage");
924 }
925
926 puts("%%EOF");
927
928 /*
929 * End the job with the appropriate JCL command or CTRL-D otherwise.
930 */
931
932 if (emit_jcl)
933 {
934 if (ppd && ppd->jcl_end)
935 ppdEmitJCLEnd(ppd, stdout);
936 else
937 putchar(0x04);
938 }
939
940 /*
941 * Close files...
942 */
943
944 cupsImageClose(img);
945 ppdClose(ppd);
946
947 return (0);
948 }
949
950
951 /*
952 * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
953 */
954
955 static void
956 ps_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? */
959 {
960 static int col = 0; /* Current column */
961 static char *hex = "0123456789ABCDEF";
962 /* Hex digits */
963
964
965 while (length > 0)
966 {
967 /*
968 * Put the hex chars out to the file; note that we don't use printf()
969 * for speed reasons...
970 */
971
972 putchar(hex[*data >> 4]);
973 putchar(hex[*data & 15]);
974
975 data ++;
976 length --;
977
978 col += 2;
979 if (col > 78)
980 {
981 putchar('\n');
982 col = 0;
983 }
984 }
985
986 if (last_line && col)
987 {
988 putchar('\n');
989 col = 0;
990 }
991 }
992
993
994 /*
995 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
996 */
997
998 static void
999 ps_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? */
1002 {
1003 unsigned b; /* Binary data word */
1004 unsigned char c[5]; /* ASCII85 encoded chars */
1005 static int col = 0; /* Current column */
1006
1007
1008 while (length > 3)
1009 {
1010 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
1011
1012 if (b == 0)
1013 {
1014 putchar('z');
1015 col ++;
1016 }
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
1029 fwrite(c, 5, 1, stdout);
1030 col += 5;
1031 }
1032
1033 data += 4;
1034 length -= 4;
1035
1036 if (col >= 75)
1037 {
1038 putchar('\n');
1039 col = 0;
1040 }
1041 }
1042
1043 if (last_line)
1044 {
1045 if (length > 0)
1046 {
1047 memset(data + length, 0, 4 - length);
1048 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
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
1060 fwrite(c, length + 1, 1, stdout);
1061 }
1062
1063 puts("~>");
1064 col = 0;
1065 }
1066 }
1067
1068
1069 /*
1070 * End of "$Id$".
1071 */