Revert manifest to default one
[external/cups.git] / filter / bannertops.c
1 /*
2  * "$Id: bannertops.c 9793 2011-05-20 03:49:49Z mike $"
3  *
4  *   Banner to PostScript filter for CUPS.
5  *
6  *   Copyright 2008-2011 by Apple Inc.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Apple Inc. and are protected by Federal copyright
10  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
11  *   which should have been included with this file.  If this file is
12  *   file is missing or damaged, see the license at "http://www.cups.org/".
13  *
14  *   This file is subject to the Apple OS-Developed Software exception.
15  *
16  * Contents:
17  *
18  *   main()           - Generate PostScript cover pages.
19  *   load_banner()    - Load the banner file.
20  *   ps_ascii85()     - Print binary data as a series of base-85 numbers.
21  *   write_banner()   - Write a banner page...
22  *   write_epilogue() - Write the PostScript file epilogue.
23  *   write_prolog()   - Write the PostScript file prolog with options.
24  */
25
26 /*
27  * Include necessary headers...
28  */
29
30 #include "pstext.h"
31 #include "image.h"
32 #include <cups/language-private.h>
33
34
35 /*
36  * Constants...
37  */
38
39 #define SHOW_IMAGEABLE_AREA             1       /* Show imageable area */
40 #define SHOW_JOB_BILLING                2       /* Show billing string */
41 #define SHOW_JOB_ID                     4       /* Show job ID */
42 #define SHOW_JOB_NAME                   8       /* Show job title */
43 #define SHOW_JOB_ORIGINATING_USER_NAME  16      /* Show owner of job */
44 #define SHOW_JOB_ORIGINATING_HOST_NAME  32      /* Show submitting system */
45 #define SHOW_JOB_UUID                   64      /* Show job UUID */
46 #define SHOW_OPTIONS                    128     /* Show print options */
47 #define SHOW_PAPER_NAME                 256     /* Show paper size name */
48 #define SHOW_PAPER_SIZE                 512     /* Show paper dimensions */
49 #define SHOW_PRINTER_DRIVER_NAME        1024    /* Show printer driver name */
50 #define SHOW_PRINTER_DRIVER_VERSION     2048    /* Show printer driver version */
51 #define SHOW_PRINTER_INFO               4096    /* Show printer description */
52 #define SHOW_PRINTER_LOCATION           8192    /* Show printer location */
53 #define SHOW_PRINTER_MAKE_AND_MODEL     16384   /* Show printer make and model */
54 #define SHOW_PRINTER_NAME               32768   /* Show printer queue ID */
55 #define SHOW_TIME_AT_CREATION           65536   /* Show date/time when submitted */
56 #define SHOW_TIME_AT_PROCESSING         131072  /* Show date/time when printed */
57
58
59 /*
60  * Structures...
61  */
62
63 typedef struct banner_file_s            /**** Banner file data ****/
64 {
65   int           show;                   /* What to show */
66   char          *header,                /* Header text */
67                 *footer;                /* Footer text */
68   cups_array_t  *notices,               /* Notices to show */
69                 *images;                /* Images to show */
70 } banner_file_t;
71
72
73 /*
74  * Local functions...
75  */
76
77 static banner_file_t    *load_banner(const char *filename);
78 static int              write_banner(banner_file_t *banner, ppd_file_t *ppd,
79                                      ps_text_t *fonts, int job_id,
80                                      const char *title, const char *username,
81                                      int num_options, cups_option_t *options);
82 static void             write_epilogue(int num_pages);
83 static ps_text_t        *write_prolog(const char *title, const char *user);
84
85
86 /*
87  * 'main()' - Generate PostScript cover pages.
88  */
89
90 int                                     /* O - Exit status */
91 main(int  argc,                         /* I - Number of command-line args */
92      char *argv[])                      /* I - Command-line arguments */
93 {
94   banner_file_t *banner;                /* Banner file data */
95   int           num_options;            /* Number of print options */
96   cups_option_t *options;               /* Print options */
97   ppd_file_t    *ppd;                   /* PPD file */
98   ps_text_t     *fonts;                 /* Fonts for output */
99   int           job_id;                 /* Job ID from command-line */
100   const char    *title,                 /* Title from command-line */
101                 *username;              /* Username from command-line */
102   int           num_pages;              /* Number of pages printed */
103
104
105  /*
106   * Make sure status messages are not buffered...
107   */
108
109   setbuf(stderr, NULL);
110
111  /*
112   * Check command-line...
113   */
114
115   if (argc < 6 || argc > 7)
116   {
117     _cupsLangPrintf(stderr,
118                     _("Usage: %s job-id user title copies options file"),
119                     argv[0]);
120     return (1);
121   }
122
123  /*
124   * Get stuff from command-line...
125   */
126
127   job_id      = atoi(argv[1]);
128   username    = argv[2];
129   title       = argv[3];
130   options     = NULL;
131   num_options = cupsParseOptions(argv[5], 0, &options);
132   banner      = load_banner(argv[6]);
133
134  /*
135   * Set standard options and get the PPD file for this printer...
136   */
137
138   ppd = SetCommonOptions(num_options, options, 1);
139
140  /*
141   * Write a PostScript banner document and return...
142   */
143
144   fonts       = write_prolog(title, username);
145   num_pages   = write_banner(banner, ppd, fonts, job_id, title, username,
146                              num_options, options);
147
148   write_epilogue(num_pages);
149
150   return (0);
151 }
152
153
154 /*
155  * 'load_banner()' - Load the banner file.
156  */
157
158 static banner_file_t *                  /* O - Banner file data */
159 load_banner(const char *filename)       /* I - Filename or NULL for stdin */
160 {
161   cups_file_t   *fp;                    /* File */
162   char          line[2048],             /* Line buffer */
163                 *ptr;                   /* Pointer into line */
164   int           linenum;                /* Current line number */
165   banner_file_t *banner;                /* Banner file data */
166   const char    *cups_docroot;          /* CUPS_DOCROOT environment variable */
167
168
169   fprintf(stderr, "DEBUG: load_banner(filename=\"%s\")\n",
170           filename ? filename : "(stdin)");
171
172  /*
173   * Open the banner file...
174   */
175
176   if (filename)
177     fp = cupsFileOpen(filename, "r");
178   else
179     fp = cupsFileStdin();
180
181   if (!fp)
182   {
183     _cupsLangPrintError("ERROR", _("Unable to open print file"));
184     exit(1);
185   }
186
187  /*
188   * Read the banner file...
189   */
190
191   if ((cups_docroot = getenv("CUPS_DOCROOT")) == NULL)
192     cups_docroot = CUPS_DOCROOT;
193
194   banner  = calloc(1, sizeof(banner_file_t));
195   linenum = 0;
196
197   while (cupsFileGets(fp, line, sizeof(line)))
198   {
199    /*
200     * Skip blank and comment lines...
201     */
202
203     linenum ++;
204
205     fprintf(stderr, "DEBUG: %4d %s\n", linenum, line);
206
207     if (line[0] == '#' || !line[0])
208       continue;
209
210    /*
211     * Break the line into keyword and value parts...
212     */
213
214     for (ptr = line; *ptr && !isspace(*ptr & 255); ptr ++);
215
216     while (isspace(*ptr & 255))
217       *ptr++ = '\0';
218
219     if (!*ptr)
220     {
221       _cupsLangPrintFilter(stderr, "ERROR",
222                            _("Missing value on line %d of banner file."),
223                            linenum);
224       continue;
225     }
226
227    /*
228     * Save keyword values in the appropriate places...
229     */
230
231     if (!_cups_strcasecmp(line, "Footer"))
232     {
233       if (banner->footer)
234         fprintf(stderr, "DEBUG: Extra \"Footer\" on line %d of banner file\n",
235                 linenum);
236       else
237         banner->footer = strdup(ptr);
238     }
239     else if (!_cups_strcasecmp(line, "Header"))
240     {
241       if (banner->header)
242         fprintf(stderr, "DEBUG: Extra \"Header\" on line %d of banner file\n",
243                 linenum);
244       else
245         banner->header = strdup(ptr);
246     }
247     else if (!_cups_strcasecmp(line, "Image"))
248     {
249       char      imagefile[1024];        /* Image filename */
250
251
252       if (ptr[0] == '/')
253         strlcpy(imagefile, ptr, sizeof(imagefile));
254       else
255         snprintf(imagefile, sizeof(imagefile), "%s/%s", cups_docroot, ptr);
256
257       if (access(imagefile, R_OK))
258       {
259         fprintf(stderr, "DEBUG: Image \"%s\" on line %d of banner file: %s\n",
260                 ptr, linenum, strerror(errno));
261       }
262       else
263       {
264         if (!banner->images)
265           banner->images = cupsArrayNew(NULL, NULL);
266
267         cupsArrayAdd(banner->images, strdup(imagefile));
268       }
269     }
270     else if (!_cups_strcasecmp(line, "Notice"))
271     {
272       if (!banner->notices)
273         banner->notices = cupsArrayNew(NULL, NULL);
274
275       cupsArrayAdd(banner->notices, strdup(ptr));
276     }
277     else if (!_cups_strcasecmp(line, "Show"))
278     {
279       char      *value;                 /* Current value */
280
281
282       for (value = ptr; *value; value = ptr)
283       {
284        /*
285         * Find the end of the current value
286         */
287
288         while (*ptr && !isspace(*ptr & 255))
289           ptr ++;
290
291         while (*ptr && isspace(*ptr & 255))
292           *ptr++ = '\0';
293
294        /*
295         * Add the value to the show flags...
296         */
297         if (!_cups_strcasecmp(value, "imageable-area"))
298           banner->show |= SHOW_IMAGEABLE_AREA;
299         else if (!_cups_strcasecmp(value, "job-billing"))
300           banner->show |= SHOW_JOB_BILLING;
301         else if (!_cups_strcasecmp(value, "job-id"))
302           banner->show |= SHOW_JOB_ID;
303         else if (!_cups_strcasecmp(value, "job-name"))
304           banner->show |= SHOW_JOB_NAME;
305         else if (!_cups_strcasecmp(value, "job-originating-host-name"))
306           banner->show |= SHOW_JOB_ORIGINATING_HOST_NAME;
307         else if (!_cups_strcasecmp(value, "job-originating-user-name"))
308           banner->show |= SHOW_JOB_ORIGINATING_USER_NAME;
309         else if (!_cups_strcasecmp(value, "job-uuid"))
310           banner->show |= SHOW_JOB_UUID;
311         else if (!_cups_strcasecmp(value, "options"))
312           banner->show |= SHOW_OPTIONS;
313         else if (!_cups_strcasecmp(value, "paper-name"))
314           banner->show |= SHOW_PAPER_NAME;
315         else if (!_cups_strcasecmp(value, "paper-size"))
316           banner->show |= SHOW_PAPER_SIZE;
317         else if (!_cups_strcasecmp(value, "printer-driver-name"))
318           banner->show |= SHOW_PRINTER_DRIVER_NAME;
319         else if (!_cups_strcasecmp(value, "printer-driver-version"))
320           banner->show |= SHOW_PRINTER_DRIVER_VERSION;
321         else if (!_cups_strcasecmp(value, "printer-info"))
322           banner->show |= SHOW_PRINTER_INFO;
323         else if (!_cups_strcasecmp(value, "printer-location"))
324           banner->show |= SHOW_PRINTER_LOCATION;
325         else if (!_cups_strcasecmp(value, "printer-make-and-model"))
326           banner->show |= SHOW_PRINTER_MAKE_AND_MODEL;
327         else if (!_cups_strcasecmp(value, "printer-name"))
328           banner->show |= SHOW_PRINTER_NAME;
329         else if (!_cups_strcasecmp(value, "time-at-creation"))
330           banner->show |= SHOW_TIME_AT_CREATION;
331         else if (!_cups_strcasecmp(value, "time-at-processing"))
332           banner->show |= SHOW_TIME_AT_PROCESSING;
333         else
334         {
335           fprintf(stderr,
336                   "DEBUG: Unknown \"Show\" value \"%s\" on line %d of banner "
337                   "file\n", value, linenum);
338         }
339       }
340     }
341     else
342       fprintf(stderr, "DEBUG: Unknown key \"%s\" on line %d of banner file\n",
343               line, linenum);
344   }
345
346   if (filename)
347     cupsFileClose(fp);
348
349   return (banner);
350 }
351
352
353 /*
354  * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
355  */
356
357 static void
358 ps_ascii85(cups_ib_t *data,             /* I - Data to print */
359            int       length,            /* I - Number of bytes to print */
360            int       last_line)         /* I - Last line of raster data? */
361 {
362   unsigned      b;                      /* Binary data word */
363   unsigned char c[5];                   /* ASCII85 encoded chars */
364   static int    col = 0;                /* Current column */
365
366
367   while (length > 3)
368   {
369     b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
370
371     if (b == 0)
372     {
373       putchar('z');
374       col ++;
375     }
376     else
377     {
378       c[4] = (b % 85) + '!';
379       b /= 85;
380       c[3] = (b % 85) + '!';
381       b /= 85;
382       c[2] = (b % 85) + '!';
383       b /= 85;
384       c[1] = (b % 85) + '!';
385       b /= 85;
386       c[0] = b + '!';
387
388       fwrite(c, 5, 1, stdout);
389       col += 5;
390     }
391
392     data += 4;
393     length -= 4;
394
395     if (col >= 75)
396     {
397       putchar('\n');
398       col = 0;
399     }
400   }
401
402   if (last_line)
403   {
404     if (length > 0)
405     {
406       memset(data + length, 0, 4 - length);
407       b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
408
409       c[4] = (b % 85) + '!';
410       b /= 85;
411       c[3] = (b % 85) + '!';
412       b /= 85;
413       c[2] = (b % 85) + '!';
414       b /= 85;
415       c[1] = (b % 85) + '!';
416       b /= 85;
417       c[0] = b + '!';
418
419       fwrite(c, length + 1, 1, stdout);
420     }
421
422     puts("~>");
423     col = 0;
424   }
425 }
426
427
428 /*
429  * 'write_banner()' - Write a banner page...
430  */
431
432 static int                              /* O - Number of pages */
433 write_banner(banner_file_t *banner,     /* I - Banner file */
434              ppd_file_t    *ppd,        /* I - PPD file */
435              ps_text_t     *fonts,      /* I - Fonts */
436              int           job_id,      /* I - Job ID */
437              const char    *title,      /* I - Title of job */
438              const char    *username,   /* I - Owner of job */
439              int           num_options, /* I - Number of options */
440              cups_option_t *options)    /* I - Options */
441 {
442   char          *notice;                /* Current notice */
443   char          *imagefile;             /* Current image file */
444   cups_array_t  *images;                /* Images */
445   cups_image_t  *image;                 /* Current image */
446   const char    *option;                /* Option value */
447   int           i, j;                   /* Looping vars */
448   float         x,                      /* Current X position */
449                 y;                      /* Current Y position */
450   cups_lang_t   *language;              /* Default language */
451   int           showlines;              /* Number of lines to show */
452   float         fontsize;               /* Font size to use */
453   int           num_pages;              /* Number of pages */
454   float         print_width,            /* Printable width of page */
455                 print_height,           /* Printable height of page */
456                 info_top,               /* Top of info fields */
457                 info_height,            /* Height of info fields */
458                 line_height,            /* Height of info lines */
459                 notices_height,         /* Height of all notices */
460                 images_width,           /* Width of all images */
461                 images_height,          /* Height of all images */
462                 total_height;           /* Height of all content */
463   char          text[1024];             /* Formatted field text */
464
465
466  /*
467   * Figure out how many lines of text will be shown...
468   */
469
470   showlines = 0;
471   if (banner->show & SHOW_IMAGEABLE_AREA)
472     showlines += 2;
473   if (banner->show & SHOW_JOB_BILLING)
474     showlines ++;
475   if (banner->show & SHOW_JOB_ID)
476     showlines ++;
477   if (banner->show & SHOW_JOB_NAME)
478     showlines ++;
479   if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
480     showlines ++;
481   if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
482     showlines ++;
483   if (banner->show & SHOW_JOB_UUID)
484     showlines ++;
485   if (banner->show & SHOW_OPTIONS)
486   {
487     for (j = 0; j < num_options; j ++)
488     {
489       if (_cups_strcasecmp("media", options[j].name) &&
490           _cups_strcasecmp("PageSize", options[j].name) &&
491           _cups_strcasecmp("PageRegion", options[j].name) &&
492           _cups_strcasecmp("InputSlot", options[j].name) &&
493           _cups_strcasecmp("MediaType", options[j].name) &&
494           _cups_strcasecmp("finishings", options[j].name) &&
495           _cups_strcasecmp("sides", options[j].name) &&
496           _cups_strcasecmp("Duplex", options[j].name) &&
497           _cups_strcasecmp("orientation-requested", options[j].name) &&
498           _cups_strcasecmp("landscape", options[j].name) &&
499           _cups_strcasecmp("number-up", options[j].name) &&
500           _cups_strcasecmp("OutputOrder", options[j].name))
501       continue;
502
503       showlines ++;
504     }
505   }
506   if (banner->show & SHOW_PAPER_NAME)
507     showlines ++;
508   if (banner->show & SHOW_PAPER_SIZE)
509     showlines += 2;
510   if (banner->show & SHOW_PRINTER_DRIVER_NAME)
511     showlines ++;
512   if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
513     showlines ++;
514   if (banner->show & SHOW_PRINTER_INFO)
515     showlines ++;
516   if (banner->show & SHOW_PRINTER_LOCATION)
517     showlines ++;
518   if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
519     showlines ++;
520   if (banner->show & SHOW_PRINTER_NAME)
521     showlines ++;
522   if (banner->show & SHOW_TIME_AT_CREATION)
523     showlines ++;
524   if (banner->show & SHOW_TIME_AT_PROCESSING)
525     showlines ++;
526
527  /*
528   * Figure out the dimensions and positions of everything...
529   */
530
531   print_width    = PageRight - PageLeft;
532   print_height   = PageTop - PageBottom;
533   fontsize       = print_height / 60;   /* Nominally 12pts */
534   line_height    = 1.2 * fontsize;
535   info_height    = showlines * line_height;
536   notices_height = cupsArrayCount(banner->notices) * line_height;
537
538   if (cupsArrayCount(banner->images))
539   {
540     images        = cupsArrayNew(NULL, NULL);
541     images_height = print_height / 10;  /* Nominally 1" */
542
543     for (imagefile = (char *)cupsArrayFirst(banner->images), images_width = 0.0;
544          imagefile;
545          imagefile = (char *)cupsArrayNext(banner->images))
546     {
547       if ((image = cupsImageOpen(imagefile, ColorDevice ? CUPS_IMAGE_RGB_CMYK :
548                                                           CUPS_IMAGE_WHITE,
549                                  CUPS_IMAGE_WHITE, 100, 0, NULL)) == NULL)
550       {
551         fprintf(stderr, "DEBUG: Unable to open image file \"%s\"\n",
552                 imagefile);
553         continue;
554       }
555
556       images_width += cupsImageGetWidth(image) * images_height /
557                       cupsImageGetHeight(image);
558       cupsArrayAdd(images, image);
559     }
560   }
561   else
562   {
563     images        = NULL;
564     images_height = 0;
565     images_width  = 0;
566   }
567
568   total_height = info_height + notices_height + images_height;
569   if (cupsArrayCount(banner->notices) && showlines)
570     total_height += 2 * line_height;
571   if (cupsArrayCount(banner->images) &&
572       (showlines || cupsArrayCount(banner->notices)))
573     total_height += 2 * line_height;
574
575   info_top = 0.5 * (print_height + total_height);
576
577  /*
578   * Write the page(s)...
579   */
580
581   language  = cupsLangDefault();
582   num_pages = Duplex ? 2 : 1;
583
584   for (i = 1; i <= num_pages; i ++)
585   {
586    /*
587     * Start the page...
588     */
589
590     printf("%%%%Page: %s %d\n", i == 1 ? "coverpage" : "coverback", i);
591     puts("gsave");
592     if (i == 1)
593       printf("%.1f %.1f translate\n", PageLeft, PageBottom);
594     else
595       printf("%.1f %.1f translate\n", PageWidth - PageRight,
596              PageLength - PageTop);
597     puts("0 setgray");
598
599     y = info_top;
600
601    /*
602     * Information...
603     */
604
605     if (banner->show)
606     {
607       x = 0.33 * print_width;
608
609       if (banner->show & SHOW_PRINTER_NAME)
610       {
611         printf("%.1f %.1f moveto", x, y);
612         y -= line_height;
613         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
614                    _cupsLangString(language, _("Printer Name: ")));
615         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, getenv("PRINTER"));
616       }
617       if (banner->show & SHOW_JOB_ID)
618       {
619         snprintf(text, sizeof(text), "%s-%d", getenv("PRINTER"), job_id);
620         printf("%.1f %.1f moveto", x, y);
621         y -= line_height;
622         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
623                    _cupsLangString(language, _("Job ID: ")));
624         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
625       }
626       if (banner->show & SHOW_JOB_UUID)
627       {
628         printf("%.1f %.1f moveto", x, y);
629         y -= line_height;
630         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
631                    _cupsLangString(language, _("Job UUID: ")));
632         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
633                    cupsGetOption("job-uuid", num_options, options));
634       }
635       if (banner->show & SHOW_JOB_NAME)
636       {
637         printf("%.1f %.1f moveto", x, y);
638         y -= line_height;
639         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
640                    _cupsLangString(language, _("Title: ")));
641         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, title);
642       }
643       if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
644       {
645         printf("%.1f %.1f moveto", x, y);
646         y -= line_height;
647         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
648                    _cupsLangString(language, _("Printed For: ")));
649         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, username);
650       }
651       if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
652       {
653         printf("%.1f %.1f moveto", x, y);
654         y -= line_height;
655         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
656                    _cupsLangString(language, _("Printed From: ")));
657         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
658                    cupsGetOption("job-originating-host-name", num_options,
659                                  options));
660       }
661       if (banner->show & SHOW_JOB_BILLING)
662       {
663         printf("%.1f %.1f moveto", x, y);
664         y -= line_height;
665         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
666                    _cupsLangString(language, _("Billing Information: ")));
667         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
668                    cupsGetOption("job-billing", num_options, options));
669       }
670       if (banner->show & SHOW_OPTIONS)
671       {
672         printf("%.1f %.1f moveto", x, y);
673         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
674                    _cupsLangString(language, _("Options: ")));
675
676         for (j = 0; j < num_options; j ++)
677         {
678           if (_cups_strcasecmp("media", options[j].name) &&
679               _cups_strcasecmp("PageSize", options[j].name) &&
680               _cups_strcasecmp("PageRegion", options[j].name) &&
681               _cups_strcasecmp("InputSlot", options[j].name) &&
682               _cups_strcasecmp("MediaType", options[j].name) &&
683               _cups_strcasecmp("finishings", options[j].name) &&
684               _cups_strcasecmp("sides", options[j].name) &&
685               _cups_strcasecmp("Duplex", options[j].name) &&
686               _cups_strcasecmp("orientation-requested", options[j].name) &&
687               _cups_strcasecmp("landscape", options[j].name) &&
688               _cups_strcasecmp("number-up", options[j].name) &&
689               _cups_strcasecmp("OutputOrder", options[j].name))
690           continue;
691
692           if (!_cups_strcasecmp("landscape", options[j].name))
693             strlcpy(text, "orientation-requested=landscape", sizeof(text));
694           else if (!_cups_strcasecmp("orientation-requested", options[j].name))
695           {
696             switch (atoi(options[j].value))
697             {
698               default :
699               case IPP_PORTRAIT :
700                   strlcpy(text, "orientation-requested=portrait",
701                           sizeof(text));
702                   break;
703
704               case IPP_LANDSCAPE :
705                   strlcpy(text, "orientation-requested=landscape",
706                           sizeof(text));
707                   break;
708
709               case IPP_REVERSE_PORTRAIT :
710                   strlcpy(text, "orientation-requested=reverse-portrait",
711                           sizeof(text));
712                   break;
713
714               case IPP_REVERSE_LANDSCAPE :
715                   strlcpy(text, "orientation-requested=reverse-landscape",
716                           sizeof(text));
717                   break;
718             }
719           }
720           else
721             snprintf(text, sizeof(text), "%s=%s", options[j].name,
722                      options[j].value);
723
724           printf("%.1f %.1f moveto", x, y);
725           y -= line_height;
726           psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
727         }
728       }
729
730       if (banner->show & SHOW_PRINTER_INFO)
731       {
732         printf("%.1f %.1f moveto", x, y);
733         y -= line_height;
734         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
735                    _cupsLangString(language, _("Description: ")));
736         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
737                    getenv("PRINTER_INFO"));
738       }
739       if (banner->show & SHOW_PRINTER_LOCATION)
740       {
741         printf("%.1f %.1f moveto", x, y);
742         y -= line_height;
743         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
744                    _cupsLangString(language, _("Location: ")));
745         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
746                    getenv("PRINTER_LOCATION"));
747       }
748       if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
749       {
750         printf("%.1f %.1f moveto", x, y);
751         y -= line_height;
752         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
753                    _cupsLangString(language, _("Make and Model: ")));
754         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
755                    ppd ? ppd->nickname : NULL);
756       }
757
758       if (banner->show & SHOW_PAPER_NAME)
759       {
760         if ((option = cupsGetOption("media", num_options, options)) == NULL)
761           if ((option = cupsGetOption("PageSize", num_options, options)) == NULL)
762             if ((option = cupsGetOption("PageRegion", num_options,
763                                         options)) == NULL)
764               option = "Default";
765
766         printf("%.1f %.1f moveto", x, y);
767         y -= line_height;
768         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
769                    _cupsLangString(language, _("Media Name: ")));
770         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, option);
771       }
772       if (banner->show & SHOW_PAPER_SIZE)
773       {
774         snprintf(text, sizeof(text),
775                  _cupsLangString(language, _("%.2f x %.2f inches")),
776                  PageWidth / 72.0, PageLength / 72.0);
777         printf("%.1f %.1f moveto", x, y);
778         y -= line_height;
779         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
780                    _cupsLangString(language, _("Media Dimensions: ")));
781         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
782
783         snprintf(text, sizeof(text),
784                  _cupsLangString(language, _("%.0f x %.0f millimeters")),
785                  PageWidth * 25.4 / 72.0, PageLength * 25.4 / 72.0);
786         printf("%.1f %.1f moveto", x, y);
787         y -= line_height;
788         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
789       }
790       if (banner->show & SHOW_IMAGEABLE_AREA)
791       {
792         snprintf(text, sizeof(text),
793                  _cupsLangString(language,
794                                  _("%.2f x %.2f to %.2f x %.2f inches")),
795                  PageLeft / 72.0, PageBottom / 72.0,
796                  PageRight / 72.0, PageTop / 72.0);
797         printf("%.1f %.1f moveto", x, y);
798         y -= line_height;
799         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
800                    _cupsLangString(language, _("Media Limits: ")));
801         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
802
803         snprintf(text, sizeof(text),
804                  _cupsLangString(language,
805                                  _("%.0f x %.0f to %.0f x %.0f millimeters")),
806                  PageLeft * 25.4 / 72.0, PageBottom * 25.4 / 72.0,
807                  PageRight * 25.4 / 72.0, PageTop * 25.4 / 72.0);
808         printf("%.1f %.1f moveto", x, y);
809         y -= line_height;
810         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
811
812         printf("gsave 2 setlinewidth 1 1 %.1f %.1f rectstroke grestore\n",
813                print_width - 2.0, print_height - 2.0);
814       }
815       if (banner->show & SHOW_PRINTER_DRIVER_NAME)
816       {
817         printf("%.1f %.1f moveto", x, y);
818         y -= line_height;
819         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
820                    _cupsLangString(language, _("Driver Name: ")));
821         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
822                    ppd ? ppd->pcfilename : NULL);
823       }
824       if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
825       {
826         ppd_attr_t  *file_version = ppdFindAttr(ppd, "FileVersion", NULL);
827
828         printf("%.1f %.1f moveto", x, y);
829         y -= line_height;
830         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
831                    _cupsLangString(language, _("Driver Version: ")));
832         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
833                    file_version ? file_version->value : NULL);
834       }
835       if (banner->show & SHOW_TIME_AT_CREATION)
836       {
837         if ((option = cupsGetOption("time-at-creation", num_options,
838                                     options)) != NULL)
839         {
840           time_t        curtime;        /* Current time */
841           struct tm     *curdate;       /* Current date */
842
843           curtime = (time_t)atoi(option);
844           curdate = localtime(&curtime);
845
846           strftime(text, sizeof(text), "%c", curdate);
847         }
848         else
849           strlcpy(text, "?", sizeof(text));
850
851         printf("%.1f %.1f moveto", x, y);
852         y -= line_height;
853         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
854                    _cupsLangString(language, _("Created On: ")));
855         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
856       }
857       if (banner->show & SHOW_TIME_AT_PROCESSING)
858       {
859         if ((option = cupsGetOption("time-at-processing", num_options,
860                                     options)) != NULL)
861         {
862           time_t        curtime;        /* Current time */
863           struct tm     *curdate;       /* Current date */
864
865           curtime = (time_t)atoi(option);
866           curdate = localtime(&curtime);
867
868           strftime(text, sizeof(text), "%c", curdate);
869         }
870         else
871           strlcpy(text, "?", sizeof(text));
872
873         printf("%.1f %.1f moveto", x, y);
874         y -= line_height;
875         psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
876                    _cupsLangString(language, _("Printed On: ")));
877         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
878       }
879     }
880
881    /*
882     * Notices...
883     */
884
885     if (cupsArrayCount(banner->notices))
886     {
887       if (banner->show)
888         y -= 2 * line_height;
889
890       x = 0.5 * print_width;
891
892       for (notice = (char *)cupsArrayFirst(banner->notices);
893            notice;
894            notice = (char *)cupsArrayNext(banner->notices))
895       {
896         printf("%.1f %.1f moveto", x, y);
897         y -= line_height;
898         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_CENTER, notice);
899       }
900     }
901
902    /*
903     * Images...
904     */
905
906     if (cupsArrayCount(images))
907     {
908       if (banner->show || cupsArrayCount(banner->notices))
909         y -= 2 * line_height;
910
911       x = 0.5 * (print_width - images_width);
912
913       for (image = (cups_image_t *)cupsArrayFirst(images);
914            image;
915            image = (cups_image_t *)cupsArrayNext(images))
916       {
917         float           temp_width;     /* Width of this image */
918         int             depth,          /* Bytes per pixel */
919                         num_cols,       /* Number of columns */
920                         row,            /* Current row */
921                         num_rows,       /* Number of rows */
922                         out_length,     /* Length of data to write */
923                         out_offset;     /* Offset in line buffer */
924         unsigned char   *line;          /* Data for current row */
925
926
927         depth      = cupsImageGetDepth(image);
928         num_cols   = cupsImageGetWidth(image);
929         num_rows   = cupsImageGetHeight(image);
930         line       = malloc(depth * num_cols + 3);
931         temp_width = num_cols * images_height / num_rows;
932
933         printf("gsave %.1f %.1f translate %.3f %.3f scale\n", x, y,
934                temp_width / num_cols, images_height / num_rows);
935         x += temp_width;
936
937         switch (cupsImageGetColorSpace(image))
938         {
939           default :
940           case CUPS_IMAGE_WHITE :
941               printf("/DeviceGray setcolorspace"
942                      "<<"
943                      "/ImageType 1"
944                      "/Width %d"
945                      "/Height %d"
946                      "/BitsPerComponent 8"
947                      "/Decode[0 1]\n",
948                      num_cols, num_rows);
949               break;
950
951           case CUPS_IMAGE_RGB :
952               printf("/DeviceRGB setcolorspace"
953                      "<<"
954                      "/ImageType 1"
955                      "/Width %d"
956                      "/Height %d"
957                      "/BitsPerComponent 8"
958                      "/Decode[0 1 0 1 0 1]\n",
959                      num_cols, num_rows);
960               break;
961
962           case CUPS_IMAGE_CMYK :
963               printf("/DeviceCMYK setcolorspace"
964                      "<<"
965                      "/ImageType 1"
966                      "/Width %d"
967                      "/Height %d"
968                      "/BitsPerComponent 8"
969                      "/Decode[0 1 0 1 0 1 0 1]\n",
970                      num_cols, num_rows);
971               break;
972         }
973
974         puts("/DataSource currentfile"
975              "/ASCII85Decode filter"
976              "/ImageMatrix[1 0 0 -1 0 1]>>image");
977
978         for (row = 0, out_offset = 0; row < num_rows; row ++)
979         {
980           cupsImageGetRow(image, 0, row, num_cols, line + out_offset);
981
982           out_length = num_cols * depth + out_offset;
983           out_offset = out_length & 3;
984
985           ps_ascii85(line, out_length, row == (num_rows - 1));
986
987           if (out_offset > 0)
988             memcpy(line, line + out_length - out_offset, out_offset);
989         }
990
991         puts("grestore");
992
993         if (i == num_pages)
994           cupsImageClose(image);
995
996         free(line);
997       }
998     }
999
1000    /*
1001     * Header and footer...
1002     */
1003
1004     x = 0.5 * print_width;
1005
1006     if (banner->header)
1007     {
1008       printf("%.1f %.1f moveto", x, print_height - 2 * fontsize);
1009       psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->header);
1010     }
1011
1012     if (banner->footer)
1013     {
1014       printf("%.1f %.1f moveto", x, fontsize);
1015       psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->footer);
1016     }
1017
1018    /*
1019     * Show the page...
1020     */
1021
1022     puts("grestore");
1023     puts("showpage");
1024   }
1025
1026   return (num_pages);
1027 }
1028
1029
1030 /*
1031  * 'write_epilogue()' - Write the PostScript file epilogue.
1032  */
1033
1034 static void
1035 write_epilogue(int num_pages)           /* I - Number of pages */
1036 {
1037   puts("%%Trailer");
1038   printf("%%%%Pages: %d\n", num_pages);
1039   puts("%%EOF");
1040 }
1041
1042
1043 /*
1044  * 'write_prolog()' - Write the PostScript file prolog with options.
1045  */
1046
1047 ps_text_t *                             /* O - Fonts */
1048 write_prolog(const char *title,         /* I - Title of job */
1049              const char *username)      /* I - Username */
1050 {
1051   time_t        curtime;                /* Current time */
1052   struct tm     *curtm;                 /* Current date */
1053   char          curdate[255];           /* Current date (text format) */
1054   ps_text_t     *fonts;                 /* Fonts */
1055
1056
1057  /*
1058   * Get the fonts we'll need...
1059   */
1060
1061   fonts = psTextInitialize();
1062
1063  /*
1064   * Output the DSC header...
1065   */
1066
1067   curtime = time(NULL);
1068   curtm   = localtime(&curtime);
1069   strftime(curdate, sizeof(curdate), "%c", curtm);
1070
1071   puts("%!PS-Adobe-3.0");
1072   printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
1073          PageRight, PageTop);
1074   printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
1075   puts("%%Creator: bannertops/" CUPS_SVERSION);
1076   printf("%%%%CreationDate: %s\n", curdate);
1077   puts("%%LanguageLevel: 2");
1078   puts("%%DocumentData: Clean7Bit");
1079   WriteTextComment("Title", title);
1080   WriteTextComment("For", username);
1081   printf("%%%%Pages: %d\n", Duplex ? 2 : 1);
1082   psTextListFonts(fonts);
1083   puts("%%EndComments");
1084   puts("%%BeginProlog");
1085   psTextEmbedFonts(fonts);
1086   puts("%%EndProlog");
1087
1088   return (fonts);
1089 }
1090
1091
1092 /*
1093  * End of "$Id: bannertops.c 9793 2011-05-20 03:49:49Z mike $".
1094  */