2 * "$Id: bannertops.c 9793 2011-05-20 03:49:49Z mike $"
4 * Banner to PostScript filter for CUPS.
6 * Copyright 2008-2011 by Apple Inc.
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/".
14 * This file is subject to the Apple OS-Developed Software exception.
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.
27 * Include necessary headers...
32 #include <cups/language-private.h>
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 */
63 typedef struct banner_file_s /**** Banner file data ****/
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 */
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);
87 * 'main()' - Generate PostScript cover pages.
90 int /* O - Exit status */
91 main(int argc, /* I - Number of command-line args */
92 char *argv[]) /* I - Command-line arguments */
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 */
106 * Make sure status messages are not buffered...
109 setbuf(stderr, NULL);
112 * Check command-line...
115 if (argc < 6 || argc > 7)
117 _cupsLangPrintf(stderr,
118 _("Usage: %s job-id user title copies options file"),
124 * Get stuff from command-line...
127 job_id = atoi(argv[1]);
131 num_options = cupsParseOptions(argv[5], 0, &options);
132 banner = load_banner(argv[6]);
135 * Set standard options and get the PPD file for this printer...
138 ppd = SetCommonOptions(num_options, options, 1);
141 * Write a PostScript banner document and return...
144 fonts = write_prolog(title, username);
145 num_pages = write_banner(banner, ppd, fonts, job_id, title, username,
146 num_options, options);
148 write_epilogue(num_pages);
155 * 'load_banner()' - Load the banner file.
158 static banner_file_t * /* O - Banner file data */
159 load_banner(const char *filename) /* I - Filename or NULL for stdin */
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 */
169 fprintf(stderr, "DEBUG: load_banner(filename=\"%s\")\n",
170 filename ? filename : "(stdin)");
173 * Open the banner file...
177 fp = cupsFileOpen(filename, "r");
179 fp = cupsFileStdin();
183 _cupsLangPrintError("ERROR", _("Unable to open print file"));
188 * Read the banner file...
191 if ((cups_docroot = getenv("CUPS_DOCROOT")) == NULL)
192 cups_docroot = CUPS_DOCROOT;
194 banner = calloc(1, sizeof(banner_file_t));
197 while (cupsFileGets(fp, line, sizeof(line)))
200 * Skip blank and comment lines...
205 fprintf(stderr, "DEBUG: %4d %s\n", linenum, line);
207 if (line[0] == '#' || !line[0])
211 * Break the line into keyword and value parts...
214 for (ptr = line; *ptr && !isspace(*ptr & 255); ptr ++);
216 while (isspace(*ptr & 255))
221 _cupsLangPrintFilter(stderr, "ERROR",
222 _("Missing value on line %d of banner file."),
228 * Save keyword values in the appropriate places...
231 if (!_cups_strcasecmp(line, "Footer"))
234 fprintf(stderr, "DEBUG: Extra \"Footer\" on line %d of banner file\n",
237 banner->footer = strdup(ptr);
239 else if (!_cups_strcasecmp(line, "Header"))
242 fprintf(stderr, "DEBUG: Extra \"Header\" on line %d of banner file\n",
245 banner->header = strdup(ptr);
247 else if (!_cups_strcasecmp(line, "Image"))
249 char imagefile[1024]; /* Image filename */
253 strlcpy(imagefile, ptr, sizeof(imagefile));
255 snprintf(imagefile, sizeof(imagefile), "%s/%s", cups_docroot, ptr);
257 if (access(imagefile, R_OK))
259 fprintf(stderr, "DEBUG: Image \"%s\" on line %d of banner file: %s\n",
260 ptr, linenum, strerror(errno));
265 banner->images = cupsArrayNew(NULL, NULL);
267 cupsArrayAdd(banner->images, strdup(imagefile));
270 else if (!_cups_strcasecmp(line, "Notice"))
272 if (!banner->notices)
273 banner->notices = cupsArrayNew(NULL, NULL);
275 cupsArrayAdd(banner->notices, strdup(ptr));
277 else if (!_cups_strcasecmp(line, "Show"))
279 char *value; /* Current value */
282 for (value = ptr; *value; value = ptr)
285 * Find the end of the current value
288 while (*ptr && !isspace(*ptr & 255))
291 while (*ptr && isspace(*ptr & 255))
295 * Add the value to the show flags...
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;
336 "DEBUG: Unknown \"Show\" value \"%s\" on line %d of banner "
337 "file\n", value, linenum);
342 fprintf(stderr, "DEBUG: Unknown key \"%s\" on line %d of banner file\n",
354 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
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? */
362 unsigned b; /* Binary data word */
363 unsigned char c[5]; /* ASCII85 encoded chars */
364 static int col = 0; /* Current column */
369 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
378 c[4] = (b % 85) + '!';
380 c[3] = (b % 85) + '!';
382 c[2] = (b % 85) + '!';
384 c[1] = (b % 85) + '!';
388 fwrite(c, 5, 1, stdout);
406 memset(data + length, 0, 4 - length);
407 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
409 c[4] = (b % 85) + '!';
411 c[3] = (b % 85) + '!';
413 c[2] = (b % 85) + '!';
415 c[1] = (b % 85) + '!';
419 fwrite(c, length + 1, 1, stdout);
429 * 'write_banner()' - Write a banner page...
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 */
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 */
467 * Figure out how many lines of text will be shown...
471 if (banner->show & SHOW_IMAGEABLE_AREA)
473 if (banner->show & SHOW_JOB_BILLING)
475 if (banner->show & SHOW_JOB_ID)
477 if (banner->show & SHOW_JOB_NAME)
479 if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
481 if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
483 if (banner->show & SHOW_JOB_UUID)
485 if (banner->show & SHOW_OPTIONS)
487 for (j = 0; j < num_options; j ++)
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))
506 if (banner->show & SHOW_PAPER_NAME)
508 if (banner->show & SHOW_PAPER_SIZE)
510 if (banner->show & SHOW_PRINTER_DRIVER_NAME)
512 if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
514 if (banner->show & SHOW_PRINTER_INFO)
516 if (banner->show & SHOW_PRINTER_LOCATION)
518 if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
520 if (banner->show & SHOW_PRINTER_NAME)
522 if (banner->show & SHOW_TIME_AT_CREATION)
524 if (banner->show & SHOW_TIME_AT_PROCESSING)
528 * Figure out the dimensions and positions of everything...
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;
538 if (cupsArrayCount(banner->images))
540 images = cupsArrayNew(NULL, NULL);
541 images_height = print_height / 10; /* Nominally 1" */
543 for (imagefile = (char *)cupsArrayFirst(banner->images), images_width = 0.0;
545 imagefile = (char *)cupsArrayNext(banner->images))
547 if ((image = cupsImageOpen(imagefile, ColorDevice ? CUPS_IMAGE_RGB_CMYK :
549 CUPS_IMAGE_WHITE, 100, 0, NULL)) == NULL)
551 fprintf(stderr, "DEBUG: Unable to open image file \"%s\"\n",
556 images_width += cupsImageGetWidth(image) * images_height /
557 cupsImageGetHeight(image);
558 cupsArrayAdd(images, image);
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;
575 info_top = 0.5 * (print_height + total_height);
578 * Write the page(s)...
581 language = cupsLangDefault();
582 num_pages = Duplex ? 2 : 1;
584 for (i = 1; i <= num_pages; i ++)
590 printf("%%%%Page: %s %d\n", i == 1 ? "coverpage" : "coverback", i);
593 printf("%.1f %.1f translate\n", PageLeft, PageBottom);
595 printf("%.1f %.1f translate\n", PageWidth - PageRight,
596 PageLength - PageTop);
607 x = 0.33 * print_width;
609 if (banner->show & SHOW_PRINTER_NAME)
611 printf("%.1f %.1f moveto", x, y);
613 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
614 _cupsLangString(language, _("Printer Name: ")));
615 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, getenv("PRINTER"));
617 if (banner->show & SHOW_JOB_ID)
619 snprintf(text, sizeof(text), "%s-%d", getenv("PRINTER"), job_id);
620 printf("%.1f %.1f moveto", x, y);
622 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
623 _cupsLangString(language, _("Job ID: ")));
624 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
626 if (banner->show & SHOW_JOB_UUID)
628 printf("%.1f %.1f moveto", x, y);
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));
635 if (banner->show & SHOW_JOB_NAME)
637 printf("%.1f %.1f moveto", x, y);
639 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
640 _cupsLangString(language, _("Title: ")));
641 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, title);
643 if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
645 printf("%.1f %.1f moveto", x, y);
647 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
648 _cupsLangString(language, _("Printed For: ")));
649 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, username);
651 if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
653 printf("%.1f %.1f moveto", x, y);
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,
661 if (banner->show & SHOW_JOB_BILLING)
663 printf("%.1f %.1f moveto", x, y);
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));
670 if (banner->show & SHOW_OPTIONS)
672 printf("%.1f %.1f moveto", x, y);
673 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
674 _cupsLangString(language, _("Options: ")));
676 for (j = 0; j < num_options; j ++)
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))
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))
696 switch (atoi(options[j].value))
700 strlcpy(text, "orientation-requested=portrait",
705 strlcpy(text, "orientation-requested=landscape",
709 case IPP_REVERSE_PORTRAIT :
710 strlcpy(text, "orientation-requested=reverse-portrait",
714 case IPP_REVERSE_LANDSCAPE :
715 strlcpy(text, "orientation-requested=reverse-landscape",
721 snprintf(text, sizeof(text), "%s=%s", options[j].name,
724 printf("%.1f %.1f moveto", x, y);
726 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
730 if (banner->show & SHOW_PRINTER_INFO)
732 printf("%.1f %.1f moveto", x, y);
734 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
735 _cupsLangString(language, _("Description: ")));
736 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
737 getenv("PRINTER_INFO"));
739 if (banner->show & SHOW_PRINTER_LOCATION)
741 printf("%.1f %.1f moveto", x, y);
743 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
744 _cupsLangString(language, _("Location: ")));
745 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
746 getenv("PRINTER_LOCATION"));
748 if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
750 printf("%.1f %.1f moveto", x, y);
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);
758 if (banner->show & SHOW_PAPER_NAME)
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,
766 printf("%.1f %.1f moveto", x, y);
768 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
769 _cupsLangString(language, _("Media Name: ")));
770 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, option);
772 if (banner->show & SHOW_PAPER_SIZE)
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);
779 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
780 _cupsLangString(language, _("Media Dimensions: ")));
781 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
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);
788 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
790 if (banner->show & SHOW_IMAGEABLE_AREA)
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);
799 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
800 _cupsLangString(language, _("Media Limits: ")));
801 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
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);
810 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
812 printf("gsave 2 setlinewidth 1 1 %.1f %.1f rectstroke grestore\n",
813 print_width - 2.0, print_height - 2.0);
815 if (banner->show & SHOW_PRINTER_DRIVER_NAME)
817 printf("%.1f %.1f moveto", x, y);
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);
824 if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
826 ppd_attr_t *file_version = ppdFindAttr(ppd, "FileVersion", NULL);
828 printf("%.1f %.1f moveto", x, y);
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);
835 if (banner->show & SHOW_TIME_AT_CREATION)
837 if ((option = cupsGetOption("time-at-creation", num_options,
840 time_t curtime; /* Current time */
841 struct tm *curdate; /* Current date */
843 curtime = (time_t)atoi(option);
844 curdate = localtime(&curtime);
846 strftime(text, sizeof(text), "%c", curdate);
849 strlcpy(text, "?", sizeof(text));
851 printf("%.1f %.1f moveto", x, y);
853 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
854 _cupsLangString(language, _("Created On: ")));
855 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
857 if (banner->show & SHOW_TIME_AT_PROCESSING)
859 if ((option = cupsGetOption("time-at-processing", num_options,
862 time_t curtime; /* Current time */
863 struct tm *curdate; /* Current date */
865 curtime = (time_t)atoi(option);
866 curdate = localtime(&curtime);
868 strftime(text, sizeof(text), "%c", curdate);
871 strlcpy(text, "?", sizeof(text));
873 printf("%.1f %.1f moveto", x, y);
875 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
876 _cupsLangString(language, _("Printed On: ")));
877 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
885 if (cupsArrayCount(banner->notices))
888 y -= 2 * line_height;
890 x = 0.5 * print_width;
892 for (notice = (char *)cupsArrayFirst(banner->notices);
894 notice = (char *)cupsArrayNext(banner->notices))
896 printf("%.1f %.1f moveto", x, y);
898 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_CENTER, notice);
906 if (cupsArrayCount(images))
908 if (banner->show || cupsArrayCount(banner->notices))
909 y -= 2 * line_height;
911 x = 0.5 * (print_width - images_width);
913 for (image = (cups_image_t *)cupsArrayFirst(images);
915 image = (cups_image_t *)cupsArrayNext(images))
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 */
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;
933 printf("gsave %.1f %.1f translate %.3f %.3f scale\n", x, y,
934 temp_width / num_cols, images_height / num_rows);
937 switch (cupsImageGetColorSpace(image))
940 case CUPS_IMAGE_WHITE :
941 printf("/DeviceGray setcolorspace"
946 "/BitsPerComponent 8"
951 case CUPS_IMAGE_RGB :
952 printf("/DeviceRGB setcolorspace"
957 "/BitsPerComponent 8"
958 "/Decode[0 1 0 1 0 1]\n",
962 case CUPS_IMAGE_CMYK :
963 printf("/DeviceCMYK setcolorspace"
968 "/BitsPerComponent 8"
969 "/Decode[0 1 0 1 0 1 0 1]\n",
974 puts("/DataSource currentfile"
975 "/ASCII85Decode filter"
976 "/ImageMatrix[1 0 0 -1 0 1]>>image");
978 for (row = 0, out_offset = 0; row < num_rows; row ++)
980 cupsImageGetRow(image, 0, row, num_cols, line + out_offset);
982 out_length = num_cols * depth + out_offset;
983 out_offset = out_length & 3;
985 ps_ascii85(line, out_length, row == (num_rows - 1));
988 memcpy(line, line + out_length - out_offset, out_offset);
994 cupsImageClose(image);
1001 * Header and footer...
1004 x = 0.5 * print_width;
1008 printf("%.1f %.1f moveto", x, print_height - 2 * fontsize);
1009 psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->header);
1014 printf("%.1f %.1f moveto", x, fontsize);
1015 psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->footer);
1031 * 'write_epilogue()' - Write the PostScript file epilogue.
1035 write_epilogue(int num_pages) /* I - Number of pages */
1038 printf("%%%%Pages: %d\n", num_pages);
1044 * 'write_prolog()' - Write the PostScript file prolog with options.
1047 ps_text_t * /* O - Fonts */
1048 write_prolog(const char *title, /* I - Title of job */
1049 const char *username) /* I - Username */
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 */
1058 * Get the fonts we'll need...
1061 fonts = psTextInitialize();
1064 * Output the DSC header...
1067 curtime = time(NULL);
1068 curtm = localtime(&curtime);
1069 strftime(curdate, sizeof(curdate), "%c", curtm);
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");
1093 * End of "$Id: bannertops.c 9793 2011-05-20 03:49:49Z mike $".