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