4 * Banner to PostScript filter for CUPS.
6 * Copyright 2008-2010 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 (!strcasecmp(line
, "Footer"))
234 fprintf(stderr
, "DEBUG: Extra \"Footer\" on line %d of banner file\n",
237 banner
->footer
= strdup(ptr
);
239 else if (!strcasecmp(line
, "Header"))
242 fprintf(stderr
, "DEBUG: Extra \"Header\" on line %d of banner file\n",
245 banner
->header
= strdup(ptr
);
247 else if (!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 (!strcasecmp(line
, "Notice"))
272 if (!banner
->notices
)
273 banner
->notices
= cupsArrayNew(NULL
, NULL
);
275 cupsArrayAdd(banner
->notices
, strdup(ptr
));
277 else if (!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 (!strcasecmp(value
, "imageable-area"))
298 banner
->show
|= SHOW_IMAGEABLE_AREA
;
299 else if (!strcasecmp(value
, "job-billing"))
300 banner
->show
|= SHOW_JOB_BILLING
;
301 else if (!strcasecmp(value
, "job-id"))
302 banner
->show
|= SHOW_JOB_ID
;
303 else if (!strcasecmp(value
, "job-name"))
304 banner
->show
|= SHOW_JOB_NAME
;
305 else if (!strcasecmp(value
, "job-originating-host-name"))
306 banner
->show
|= SHOW_JOB_ORIGINATING_HOST_NAME
;
307 else if (!strcasecmp(value
, "job-originating-user-name"))
308 banner
->show
|= SHOW_JOB_ORIGINATING_USER_NAME
;
309 else if (!strcasecmp(value
, "job-uuid"))
310 banner
->show
|= SHOW_JOB_UUID
;
311 else if (!strcasecmp(value
, "options"))
312 banner
->show
|= SHOW_OPTIONS
;
313 else if (!strcasecmp(value
, "paper-name"))
314 banner
->show
|= SHOW_PAPER_NAME
;
315 else if (!strcasecmp(value
, "paper-size"))
316 banner
->show
|= SHOW_PAPER_SIZE
;
317 else if (!strcasecmp(value
, "printer-driver-name"))
318 banner
->show
|= SHOW_PRINTER_DRIVER_NAME
;
319 else if (!strcasecmp(value
, "printer-driver-version"))
320 banner
->show
|= SHOW_PRINTER_DRIVER_VERSION
;
321 else if (!strcasecmp(value
, "printer-info"))
322 banner
->show
|= SHOW_PRINTER_INFO
;
323 else if (!strcasecmp(value
, "printer-location"))
324 banner
->show
|= SHOW_PRINTER_LOCATION
;
325 else if (!strcasecmp(value
, "printer-make-and-model"))
326 banner
->show
|= SHOW_PRINTER_MAKE_AND_MODEL
;
327 else if (!strcasecmp(value
, "printer-name"))
328 banner
->show
|= SHOW_PRINTER_NAME
;
329 else if (!strcasecmp(value
, "time-at-creation"))
330 banner
->show
|= SHOW_TIME_AT_CREATION
;
331 else if (!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 (strcasecmp("media", options
[j
].name
) &&
490 strcasecmp("PageSize", options
[j
].name
) &&
491 strcasecmp("PageRegion", options
[j
].name
) &&
492 strcasecmp("InputSlot", options
[j
].name
) &&
493 strcasecmp("MediaType", options
[j
].name
) &&
494 strcasecmp("finishings", options
[j
].name
) &&
495 strcasecmp("sides", options
[j
].name
) &&
496 strcasecmp("Duplex", options
[j
].name
) &&
497 strcasecmp("orientation-requested", options
[j
].name
) &&
498 strcasecmp("landscape", options
[j
].name
) &&
499 strcasecmp("number-up", options
[j
].name
) &&
500 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 (strcasecmp("media", options
[j
].name
) &&
679 strcasecmp("PageSize", options
[j
].name
) &&
680 strcasecmp("PageRegion", options
[j
].name
) &&
681 strcasecmp("InputSlot", options
[j
].name
) &&
682 strcasecmp("MediaType", options
[j
].name
) &&
683 strcasecmp("finishings", options
[j
].name
) &&
684 strcasecmp("sides", options
[j
].name
) &&
685 strcasecmp("Duplex", options
[j
].name
) &&
686 strcasecmp("orientation-requested", options
[j
].name
) &&
687 strcasecmp("landscape", options
[j
].name
) &&
688 strcasecmp("number-up", options
[j
].name
) &&
689 strcasecmp("OutputOrder", options
[j
].name
))
692 if (!strcasecmp("landscape", options
[j
].name
))
693 strlcpy(text
, "orientation-requested=landscape", sizeof(text
));
694 else if (!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
);
999 * Header and footer...
1002 x
= 0.5 * print_width
;
1006 printf("%.1f %.1f moveto", x
, print_height
- 2 * fontsize
);
1007 psTextUTF8(fonts
, 2 * fontsize
, PS_BOLD
, PS_CENTER
, banner
->header
);
1012 printf("%.1f %.1f moveto", x
, fontsize
);
1013 psTextUTF8(fonts
, 2 * fontsize
, PS_BOLD
, PS_CENTER
, banner
->footer
);
1029 * 'write_epilogue()' - Write the PostScript file epilogue.
1033 write_epilogue(int num_pages
) /* I - Number of pages */
1036 printf("%%%%Pages: %d\n", num_pages
);
1042 * 'write_prolog()' - Write the PostScript file prolog with options.
1045 ps_text_t
* /* O - Fonts */
1046 write_prolog(const char *title
, /* I - Title of job */
1047 const char *username
) /* I - Username */
1049 time_t curtime
; /* Current time */
1050 struct tm
*curtm
; /* Current date */
1051 char curdate
[255]; /* Current date (text format) */
1052 ps_text_t
*fonts
; /* Fonts */
1056 * Get the fonts we'll need...
1059 fonts
= psTextInitialize();
1062 * Output the DSC header...
1065 curtime
= time(NULL
);
1066 curtm
= localtime(&curtime
);
1067 strftime(curdate
, sizeof(curdate
), "%c", curtm
);
1069 puts("%!PS-Adobe-3.0");
1070 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft
, PageBottom
,
1071 PageRight
, PageTop
);
1072 printf("%%cupsRotation: %d\n", (Orientation
& 3) * 90);
1073 puts("%%Creator: bannertops/" CUPS_SVERSION
);
1074 printf("%%%%CreationDate: %s\n", curdate
);
1075 puts("%%LanguageLevel: 2");
1076 puts("%%DocumentData: Clean7Bit");
1077 WriteTextComment("Title", title
);
1078 WriteTextComment("For", username
);
1079 printf("%%%%Pages: %d\n", Duplex
? 2 : 1);
1080 psTextListFonts(fonts
);
1081 puts("%%EndComments");
1082 puts("%%BeginProlog");
1083 psTextEmbedFonts(fonts
);
1084 puts("%%EndProlog");