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