]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/bannertops.c
Merge changes from CUPS 1.4svn-r8540.
[thirdparty/cups.git] / filter / bannertops.c
CommitLineData
1f6f3dbc
MS
1/*
2 * "$Id$"
3 *
4 * Banner to PostScript filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2008 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 *
58dc1933
MS
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.
1f6f3dbc
MS
24 */
25
26/*
27 * Include necessary headers...
28 */
29
cda47a96 30#include "pstext.h"
1f6f3dbc
MS
31#include "image.h"
32#include <cups/i18n.h>
33
34
35/*
cda47a96 36 * Constants...
1f6f3dbc
MS
37 */
38
cda47a96
MS
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 */
1f6f3dbc
MS
57
58
59/*
cda47a96 60 * Structures...
1f6f3dbc
MS
61 */
62
cda47a96 63typedef struct banner_file_s /**** Banner file data ****/
1f6f3dbc 64{
cda47a96
MS
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;
1f6f3dbc
MS
71
72
73/*
cda47a96 74 * Local functions...
1f6f3dbc
MS
75 */
76
cda47a96
MS
77static banner_file_t *load_banner(const char *filename);
78static 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);
82static void write_epilogue(int num_pages);
83static ps_text_t *write_prolog(const char *title, const char *user);
1f6f3dbc
MS
84
85
86/*
cda47a96 87 * 'main()' - Generate PostScript cover pages.
1f6f3dbc
MS
88 */
89
cda47a96
MS
90int /* O - Exit status */
91main(int argc, /* I - Number of command-line args */
92 char *argv[]) /* I - Command-line arguments */
1f6f3dbc 93{
cda47a96
MS
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 */
1f6f3dbc
MS
103
104
105 /*
cda47a96 106 * Make sure status messages are not buffered...
1f6f3dbc
MS
107 */
108
cda47a96 109 setbuf(stderr, NULL);
1f6f3dbc
MS
110
111 /*
cda47a96 112 * Check command-line...
1f6f3dbc
MS
113 */
114
cda47a96 115 if (argc < 6 || argc > 7)
1f6f3dbc 116 {
cda47a96
MS
117 _cupsLangPrintf(stderr,
118 _("Usage: %s job-id user title copies options [file]\n"),
119 "bannertops");
120 return (1);
1f6f3dbc
MS
121 }
122
123 /*
cda47a96 124 * Get stuff from command-line...
1f6f3dbc
MS
125 */
126
cda47a96
MS
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]);
1f6f3dbc 133
cda47a96
MS
134 /*
135 * Set standard options and get the PPD file for this printer...
136 */
1f6f3dbc 137
cda47a96 138 ppd = SetCommonOptions(num_options, options, 1);
1f6f3dbc
MS
139
140 /*
cda47a96 141 * Write a PostScript banner document and return...
1f6f3dbc
MS
142 */
143
cda47a96
MS
144 fonts = write_prolog(title, username);
145 num_pages = write_banner(banner, ppd, fonts, job_id, title, username,
146 num_options, options);
1f6f3dbc 147
cda47a96 148 write_epilogue(num_pages);
1f6f3dbc 149
cda47a96
MS
150 return (0);
151}
1f6f3dbc 152
1f6f3dbc 153
cda47a96
MS
154/*
155 * 'load_banner()' - Load the banner file.
156 */
1f6f3dbc 157
cda47a96
MS
158static banner_file_t * /* O - Banner file data */
159load_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 */
1f6f3dbc 167
1f6f3dbc 168
cda47a96
MS
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");
1f6f3dbc 178 else
cda47a96
MS
179 fp = cupsFileStdin();
180
181 if (!fp)
1f6f3dbc 182 {
cda47a96
MS
183 _cupsLangPrintf(stderr,
184 _("ERROR: Unable to open banner file \"%s\" - %s\n"),
185 filename ? filename : "(stdin)", strerror(errno));
1f6f3dbc
MS
186 exit(1);
187 }
188
189 /*
cda47a96 190 * Read the banner file...
1f6f3dbc
MS
191 */
192
cda47a96
MS
193 if ((cups_docroot = getenv("CUPS_DOCROOT")) == NULL)
194 cups_docroot = CUPS_DOCROOT;
195
196 banner = calloc(1, sizeof(banner_file_t));
197 linenum = 0;
198
199 while (cupsFileGets(fp, line, sizeof(line)))
1f6f3dbc 200 {
cda47a96
MS
201 /*
202 * Skip blank and comment lines...
203 */
1f6f3dbc 204
cda47a96 205 linenum ++;
1f6f3dbc 206
cda47a96
MS
207 if (line[0] == '#' || !line[0])
208 continue;
1f6f3dbc
MS
209
210 /*
cda47a96 211 * Break the line into keyword and value parts...
1f6f3dbc
MS
212 */
213
cda47a96 214 for (ptr = line; *ptr && !isspace(*ptr & 255); ptr ++);
1f6f3dbc 215
cda47a96
MS
216 while (isspace(*ptr & 255))
217 *ptr++ = '\0';
1f6f3dbc 218
cda47a96 219 if (!*ptr)
1f6f3dbc 220 {
cda47a96
MS
221 _cupsLangPrintf(stderr,
222 _("ERROR: Missing value on line %d of banner file!\n"),
223 linenum);
224 continue;
1f6f3dbc
MS
225 }
226
227 /*
cda47a96 228 * Save keyword values in the appropriate places...
1f6f3dbc
MS
229 */
230
cda47a96 231 if (!strcasecmp(line, "Footer"))
1f6f3dbc 232 {
cda47a96
MS
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 (!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 (!strcasecmp(line, "Image"))
248 {
249 char imagefile[1024]; /* Image filename */
1f6f3dbc 250
1f6f3dbc 251
cda47a96
MS
252 if (ptr[0] == '/')
253 strlcpy(imagefile, ptr, sizeof(imagefile));
254 else
255 snprintf(imagefile, sizeof(imagefile), "%s/%s", cups_docroot, ptr);
1f6f3dbc 256
cda47a96 257 if (access(imagefile, R_OK))
1f6f3dbc 258 {
cda47a96
MS
259 fprintf(stderr, "DEBUG: Image \"%s\" on line %d of banner file: %s\n",
260 ptr, linenum, strerror(errno));
1f6f3dbc 261 }
cda47a96 262 else
1f6f3dbc 263 {
cda47a96
MS
264 if (!banner->images)
265 banner->images = cupsArrayNew(NULL, NULL);
1f6f3dbc 266
cda47a96 267 cupsArrayAdd(banner->images, strdup(imagefile));
1f6f3dbc 268 }
1f6f3dbc 269 }
cda47a96 270 else if (!strcasecmp(line, "Notice"))
1f6f3dbc 271 {
cda47a96
MS
272 if (!banner->notices)
273 banner->notices = cupsArrayNew(NULL, NULL);
1f6f3dbc 274
cda47a96
MS
275 cupsArrayAdd(banner->notices, strdup(ptr));
276 }
277 else if (!strcasecmp(line, "Show"))
278 {
279 char *value; /* Current value */
1f6f3dbc 280
1f6f3dbc 281
cda47a96 282 for (value = ptr; *value; value = ptr)
1f6f3dbc
MS
283 {
284 /*
cda47a96 285 * Find the end of the current value
1f6f3dbc
MS
286 */
287
cda47a96
MS
288 while (*ptr && !isspace(*ptr & 255))
289 ptr ++;
1f6f3dbc 290
cda47a96
MS
291 while (*ptr && isspace(*ptr & 255))
292 *ptr++ = '\0';
1f6f3dbc
MS
293
294 /*
cda47a96 295 * Add the value to the show flags...
1f6f3dbc 296 */
cda47a96
MS
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;
333 else
334 {
335 fprintf(stderr,
336 "DEBUG: Unknown \"Show\" value \"%s\" on line %d of banner "
337 "file!\n", value, linenum);
1f6f3dbc 338 }
1f6f3dbc 339 }
1f6f3dbc
MS
340 }
341 else
cda47a96
MS
342 fprintf(stderr, "DEBUG: Unknown key \"%s\" on line %d of banner file!\n",
343 line, linenum);
1f6f3dbc 344 }
1f6f3dbc 345
cda47a96
MS
346 if (filename)
347 cupsFileClose(fp);
1f6f3dbc 348
cda47a96
MS
349 return (banner);
350}
1f6f3dbc 351
1f6f3dbc 352
cda47a96
MS
353/*
354 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
355 */
1f6f3dbc 356
cda47a96
MS
357static void
358ps_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 */
1f6f3dbc 365
1f6f3dbc 366
cda47a96
MS
367 while (length > 3)
368 {
369 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
1f6f3dbc 370
cda47a96
MS
371 if (b == 0)
372 {
373 putchar('z');
374 col ++;
1f6f3dbc 375 }
1f6f3dbc 376 else
1f6f3dbc 377 {
cda47a96
MS
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;
1f6f3dbc 390 }
1f6f3dbc 391
cda47a96
MS
392 data += 4;
393 length -= 4;
1f6f3dbc 394
cda47a96
MS
395 if (col >= 75)
396 {
397 putchar('\n');
398 col = 0;
1f6f3dbc
MS
399 }
400 }
401
cda47a96 402 if (last_line)
1f6f3dbc 403 {
cda47a96 404 if (length > 0)
1f6f3dbc 405 {
cda47a96
MS
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);
1f6f3dbc 420 }
1f6f3dbc 421
cda47a96
MS
422 puts("~>");
423 col = 0;
424 }
425}
1f6f3dbc 426
1f6f3dbc 427
cda47a96
MS
428/*
429 * 'write_banner()' - Write a banner page...
430 */
1f6f3dbc 431
cda47a96
MS
432static int /* O - Number of pages */
433write_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 */
1f6f3dbc 464
1f6f3dbc
MS
465
466 /*
cda47a96 467 * Figure out how many lines of text will be shown...
1f6f3dbc
MS
468 */
469
cda47a96
MS
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)
1f6f3dbc 486 {
cda47a96 487 for (j = 0; j < num_options; j ++)
1f6f3dbc 488 {
cda47a96
MS
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))
501 continue;
502
503 showlines ++;
1f6f3dbc 504 }
1f6f3dbc 505 }
cda47a96
MS
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 ++;
1f6f3dbc
MS
526
527 /*
cda47a96 528 * Figure out the dimensions and positions of everything...
1f6f3dbc
MS
529 */
530
cda47a96
MS
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;
1f6f3dbc 537
cda47a96
MS
538 if (cupsArrayCount(banner->images))
539 {
540 images = cupsArrayNew(NULL, NULL);
541 images_height = print_height / 10; /* Nominally 1" */
1f6f3dbc 542
cda47a96
MS
543 for (imagefile = (char *)cupsArrayFirst(banner->images), images_width = 0.0;
544 imagefile;
545 imagefile = (char *)cupsArrayNext(banner->images))
1f6f3dbc 546 {
cda47a96
MS
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);
1f6f3dbc
MS
559 }
560 }
561 else
562 {
cda47a96
MS
563 images = NULL;
564 images_height = 0;
58dc1933 565 images_width = 0;
cda47a96 566 }
1f6f3dbc 567
cda47a96
MS
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;
1f6f3dbc 574
cda47a96 575 info_top = 0.5 * (print_height + total_height);
1f6f3dbc
MS
576
577 /*
cda47a96 578 * Write the page(s)...
1f6f3dbc
MS
579 */
580
cda47a96
MS
581 language = cupsLangDefault();
582 num_pages = Duplex ? 2 : 1;
1f6f3dbc 583
cda47a96 584 for (i = 1; i <= num_pages; i ++)
1f6f3dbc 585 {
cda47a96
MS
586 /*
587 * Start the page...
588 */
1f6f3dbc 589
28b9d139 590 printf("%%%%Page: %s %d\n", i == 1 ? "coverpage" : "coverback", i);
cda47a96
MS
591 puts("gsave");
592 printf("%.1f %.1f translate\n", PageLeft, PageBottom);
593 puts("0 setgray");
1f6f3dbc 594
cda47a96 595 y = info_top;
1f6f3dbc 596
cda47a96
MS
597 /*
598 * Information...
599 */
1f6f3dbc 600
cda47a96 601 if (banner->show)
1f6f3dbc 602 {
cda47a96 603 x = 0.33 * print_width;
1f6f3dbc 604
cda47a96
MS
605 if (banner->show & SHOW_PRINTER_NAME)
606 {
607 printf("%.1f %.1f moveto", x, y);
608 y -= line_height;
609 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
610 _cupsLangString(language, _("Printer Name: ")));
58dc1933 611 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, getenv("PRINTER"));
cda47a96
MS
612 }
613 if (banner->show & SHOW_JOB_ID)
614 {
58dc1933 615 snprintf(text, sizeof(text), "%s-%d", getenv("PRINTER"), job_id);
cda47a96
MS
616 printf("%.1f %.1f moveto", x, y);
617 y -= line_height;
618 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
619 _cupsLangString(language, _("Job ID: ")));
620 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
621 }
622 if (banner->show & SHOW_JOB_UUID)
623 {
624 printf("%.1f %.1f moveto", x, y);
625 y -= line_height;
626 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
627 _cupsLangString(language, _("Job UUID: ")));
628 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
629 cupsGetOption("job-uuid", num_options, options));
630 }
631 if (banner->show & SHOW_JOB_NAME)
632 {
633 printf("%.1f %.1f moveto", x, y);
634 y -= line_height;
635 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
636 _cupsLangString(language, _("Title: ")));
637 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, title);
638 }
639 if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
640 {
641 printf("%.1f %.1f moveto", x, y);
642 y -= line_height;
643 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
644 _cupsLangString(language, _("Printed For: ")));
645 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, username);
646 }
647 if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
648 {
649 printf("%.1f %.1f moveto", x, y);
650 y -= line_height;
651 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
652 _cupsLangString(language, _("Printed From: ")));
653 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
654 cupsGetOption("job-originating-host-name", num_options,
655 options));
656 }
657 if (banner->show & SHOW_JOB_BILLING)
658 {
659 printf("%.1f %.1f moveto", x, y);
660 y -= line_height;
661 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
662 _cupsLangString(language, _("Billing Information: ")));
663 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
664 cupsGetOption("job-billing", num_options, options));
665 }
666 if (banner->show & SHOW_OPTIONS)
667 {
668 printf("%.1f %.1f moveto", x, y);
669 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
670 _cupsLangString(language, _("Options: ")));
1f6f3dbc 671
cda47a96
MS
672 for (j = 0; j < num_options; j ++)
673 {
674 if (strcasecmp("media", options[j].name) &&
675 strcasecmp("PageSize", options[j].name) &&
676 strcasecmp("PageRegion", options[j].name) &&
677 strcasecmp("InputSlot", options[j].name) &&
678 strcasecmp("MediaType", options[j].name) &&
679 strcasecmp("finishings", options[j].name) &&
680 strcasecmp("sides", options[j].name) &&
681 strcasecmp("Duplex", options[j].name) &&
682 strcasecmp("orientation-requested", options[j].name) &&
683 strcasecmp("landscape", options[j].name) &&
684 strcasecmp("number-up", options[j].name) &&
685 strcasecmp("OutputOrder", options[j].name))
686 continue;
687
688 if (!strcasecmp("landscape", options[j].name))
689 strlcpy(text, "orientation-requested=landscape", sizeof(text));
690 else if (!strcasecmp("orientation-requested", options[j].name))
691 {
692 switch (atoi(options[j].value))
693 {
694 default :
695 case IPP_PORTRAIT :
696 strlcpy(text, "orientation-requested=portrait",
697 sizeof(text));
698 break;
699
700 case IPP_LANDSCAPE :
701 strlcpy(text, "orientation-requested=landscape",
702 sizeof(text));
703 break;
704
705 case IPP_REVERSE_PORTRAIT :
706 strlcpy(text, "orientation-requested=reverse-portrait",
707 sizeof(text));
708 break;
709
710 case IPP_REVERSE_LANDSCAPE :
711 strlcpy(text, "orientation-requested=reverse-landscape",
712 sizeof(text));
713 break;
714 }
715 }
716 else
717 snprintf(text, sizeof(text), "%s=%s", options[j].name,
718 options[j].value);
719
720 printf("%.1f %.1f moveto", x, y);
721 y -= line_height;
722 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
723 }
724 }
1f6f3dbc 725
cda47a96
MS
726 if (banner->show & SHOW_PRINTER_INFO)
727 {
728 printf("%.1f %.1f moveto", x, y);
729 y -= line_height;
730 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
731 _cupsLangString(language, _("Description: ")));
732 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
733 getenv("PRINTER_INFO"));
734 }
735 if (banner->show & SHOW_PRINTER_LOCATION)
736 {
737 printf("%.1f %.1f moveto", x, y);
738 y -= line_height;
739 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
740 _cupsLangString(language, _("Location: ")));
741 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
742 getenv("PRINTER_LOCATION"));
743 }
744 if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
745 {
746 printf("%.1f %.1f moveto", x, y);
747 y -= line_height;
748 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
749 _cupsLangString(language, _("Make and Model: ")));
750 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
751 ppd ? ppd->nickname : NULL);
752 }
1f6f3dbc 753
cda47a96
MS
754 if (banner->show & SHOW_PAPER_NAME)
755 {
756 if ((option = cupsGetOption("media", num_options, options)) == NULL)
757 if ((option = cupsGetOption("PageSize", num_options, options)) == NULL)
758 if ((option = cupsGetOption("PageRegion", num_options,
759 options)) == NULL)
760 option = "Default";
761
762 printf("%.1f %.1f moveto", x, y);
763 y -= line_height;
764 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
765 _cupsLangString(language, _("Media Name: ")));
766 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, option);
767 }
768 if (banner->show & SHOW_PAPER_SIZE)
769 {
770 snprintf(text, sizeof(text),
771 _cupsLangString(language, _("%.2f x %.2f inches")),
772 PageWidth / 72.0, PageLength / 72.0);
773 printf("%.1f %.1f moveto", x, y);
774 y -= line_height;
775 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
776 _cupsLangString(language, _("Media Dimensions: ")));
777 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
778
779 snprintf(text, sizeof(text),
780 _cupsLangString(language, _("%.0f x %.0f millimeters")),
781 PageWidth * 25.4 / 72.0, PageLength * 25.4 / 72.0);
782 printf("%.1f %.1f moveto", x, y);
783 y -= line_height;
784 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
785 }
786 if (banner->show & SHOW_IMAGEABLE_AREA)
787 {
788 snprintf(text, sizeof(text),
789 _cupsLangString(language,
790 _("%.2f x %.2f to %.2f x %.2f inches")),
791 PageLeft / 72.0, PageBottom / 72.0,
792 PageRight / 72.0, PageTop / 72.0);
793 printf("%.1f %.1f moveto", x, y);
794 y -= line_height;
795 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
796 _cupsLangString(language, _("Media Limits: ")));
797 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
798
799 snprintf(text, sizeof(text),
800 _cupsLangString(language,
801 _("%.0f x %.0f to %.0f x %.0f millimeters")),
802 PageLeft * 25.4 / 72.0, PageBottom * 25.4 / 72.0,
803 PageRight * 25.4 / 72.0, PageTop * 25.4 / 72.0);
804 printf("%.1f %.1f moveto", x, y);
805 y -= line_height;
806 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
807
808 printf("gsave 2 setlinewidth 1 1 %.1f %.1f rectstroke grestore\n",
809 print_width - 2.0, print_height - 2.0);
810 }
811 if (banner->show & SHOW_PRINTER_DRIVER_NAME)
812 {
813 printf("%.1f %.1f moveto", x, y);
814 y -= line_height;
815 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
816 _cupsLangString(language, _("Driver Name: ")));
817 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
818 ppd ? ppd->pcfilename : NULL);
819 }
820 if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
821 {
822 ppd_attr_t *file_version = ppdFindAttr(ppd, "FileVersion", NULL);
823
824 printf("%.1f %.1f moveto", x, y);
825 y -= line_height;
826 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
827 _cupsLangString(language, _("Driver Version: ")));
828 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
829 file_version ? file_version->value : NULL);
830 }
831 if (banner->show & SHOW_TIME_AT_CREATION)
832 {
833 if ((option = cupsGetOption("time-at-creation", num_options,
834 options)) != NULL)
835 {
836 time_t curtime; /* Current time */
837 struct tm *curdate; /* Current date */
1f6f3dbc 838
cda47a96
MS
839 curtime = (time_t)atoi(option);
840 curdate = localtime(&curtime);
1f6f3dbc 841
cda47a96
MS
842 strftime(text, sizeof(text), "%c", curdate);
843 }
844 else
845 strlcpy(text, "?", sizeof(text));
1f6f3dbc 846
cda47a96
MS
847 printf("%.1f %.1f moveto", x, y);
848 y -= line_height;
849 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
850 _cupsLangString(language, _("Created On: ")));
851 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
852 }
853 if (banner->show & SHOW_TIME_AT_PROCESSING)
854 {
855 if ((option = cupsGetOption("time-at-processing", num_options,
856 options)) != NULL)
857 {
858 time_t curtime; /* Current time */
859 struct tm *curdate; /* Current date */
1f6f3dbc 860
cda47a96
MS
861 curtime = (time_t)atoi(option);
862 curdate = localtime(&curtime);
1f6f3dbc 863
cda47a96
MS
864 strftime(text, sizeof(text), "%c", curdate);
865 }
866 else
867 strlcpy(text, "?", sizeof(text));
1f6f3dbc 868
cda47a96
MS
869 printf("%.1f %.1f moveto", x, y);
870 y -= line_height;
871 psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
872 _cupsLangString(language, _("Printed On: ")));
873 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
874 }
1f6f3dbc
MS
875 }
876
cda47a96
MS
877 /*
878 * Notices...
879 */
1f6f3dbc 880
cda47a96 881 if (cupsArrayCount(banner->notices))
1f6f3dbc 882 {
cda47a96
MS
883 if (banner->show)
884 y -= 2 * line_height;
1f6f3dbc 885
cda47a96 886 x = 0.5 * print_width;
1f6f3dbc 887
cda47a96
MS
888 for (notice = (char *)cupsArrayFirst(banner->notices);
889 notice;
890 notice = (char *)cupsArrayNext(banner->notices))
1f6f3dbc 891 {
cda47a96
MS
892 printf("%.1f %.1f moveto", x, y);
893 y -= line_height;
894 psTextUTF8(fonts, fontsize, PS_NORMAL, PS_CENTER, notice);
1f6f3dbc 895 }
1f6f3dbc 896 }
1f6f3dbc 897
cda47a96
MS
898 /*
899 * Images...
900 */
1f6f3dbc 901
cda47a96
MS
902 if (cupsArrayCount(images))
903 {
904 if (banner->show || cupsArrayCount(banner->notices))
905 y -= 2 * line_height;
1f6f3dbc 906
cda47a96 907 x = 0.5 * (print_width - images_width);
1f6f3dbc 908
cda47a96
MS
909 for (image = (cups_image_t *)cupsArrayFirst(images);
910 image;
911 image = (cups_image_t *)cupsArrayNext(images))
912 {
913 float temp_width; /* Width of this image */
914 int depth, /* Bytes per pixel */
915 num_cols, /* Number of columns */
916 row, /* Current row */
917 num_rows, /* Number of rows */
918 out_length, /* Length of data to write */
919 out_offset; /* Offset in line buffer */
920 unsigned char *line; /* Data for current row */
921
922
923 depth = cupsImageGetDepth(image);
924 num_cols = cupsImageGetWidth(image);
925 num_rows = cupsImageGetHeight(image);
926 line = malloc(depth * num_cols + 3);
927 temp_width = num_cols * images_height / num_rows;
cda47a96
MS
928
929 printf("gsave %.1f %.1f translate %.3f %.3f scale\n", x, y,
930 temp_width / num_cols, images_height / num_rows);
931 x += temp_width;
932
933 switch (cupsImageGetColorSpace(image))
1f6f3dbc 934 {
cda47a96
MS
935 default :
936 case CUPS_IMAGE_WHITE :
937 printf("/DeviceGray setcolorspace"
938 "<<"
939 "/ImageType 1"
940 "/Width %d"
941 "/Height %d"
942 "/BitsPerComponent 8"
943 "/Decode[0 1]\n",
944 num_cols, num_rows);
945 break;
946
947 case CUPS_IMAGE_RGB :
948 printf("/DeviceRGB setcolorspace"
949 "<<"
950 "/ImageType 1"
951 "/Width %d"
952 "/Height %d"
953 "/BitsPerComponent 8"
954 "/Decode[0 1 0 1 0 1]\n",
955 num_cols, num_rows);
956 break;
957
958 case CUPS_IMAGE_CMYK :
959 printf("/DeviceCMYK setcolorspace"
960 "<<"
961 "/ImageType 1"
962 "/Width %d"
963 "/Height %d"
964 "/BitsPerComponent 8"
965 "/Decode[0 1 0 1 0 1 0 1]\n",
966 num_cols, num_rows);
967 break;
1f6f3dbc
MS
968 }
969
cda47a96
MS
970 puts("/DataSource currentfile"
971 "/ASCII85Decode filter"
972 "/ImageMatrix[1 0 0 -1 0 1]>>image");
1f6f3dbc 973
cda47a96
MS
974 for (row = 0, out_offset = 0; row < num_rows; row ++)
975 {
976 cupsImageGetRow(image, 0, row, num_cols, line + out_offset);
1f6f3dbc 977
cda47a96
MS
978 out_length = num_cols * depth + out_offset;
979 out_offset = out_length & 3;
1f6f3dbc 980
cda47a96 981 ps_ascii85(line, out_length, row == (num_rows - 1));
1f6f3dbc 982
cda47a96
MS
983 if (out_offset > 0)
984 memcpy(line, line + out_length - out_offset, out_offset);
985 }
1f6f3dbc 986
cda47a96 987 puts("grestore");
1f6f3dbc 988
cda47a96
MS
989 if (i == num_pages)
990 cupsImageClose(image);
991 }
992 }
1f6f3dbc 993
1f6f3dbc 994 /*
cda47a96 995 * Header and footer...
1f6f3dbc
MS
996 */
997
cda47a96 998 x = 0.5 * print_width;
1f6f3dbc 999
cda47a96 1000 if (banner->header)
1f6f3dbc 1001 {
cda47a96
MS
1002 printf("%.1f %.1f moveto", x, print_height - 2 * fontsize);
1003 psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->header);
1004 }
1f6f3dbc 1005
cda47a96
MS
1006 if (banner->footer)
1007 {
1008 printf("%.1f %.1f moveto", x, fontsize);
1009 psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->footer);
1f6f3dbc
MS
1010 }
1011
1f6f3dbc 1012 /*
cda47a96 1013 * Show the page...
1f6f3dbc
MS
1014 */
1015
cda47a96
MS
1016 puts("grestore");
1017 puts("showpage");
1f6f3dbc
MS
1018 }
1019
cda47a96 1020 return (num_pages);
1f6f3dbc
MS
1021}
1022
1023
1024/*
cda47a96 1025 * 'write_epilogue()' - Write the PostScript file epilogue.
1f6f3dbc
MS
1026 */
1027
1028static void
cda47a96 1029write_epilogue(int num_pages) /* I - Number of pages */
1f6f3dbc 1030{
cda47a96
MS
1031 puts("%%Trailer");
1032 printf("%%%%Pages: %d\n", num_pages);
1033 puts("%%EOF");
1034}
1f6f3dbc 1035
1f6f3dbc 1036
cda47a96
MS
1037/*
1038 * 'write_prolog()' - Write the PostScript file prolog with options.
1039 */
1f6f3dbc 1040
cda47a96
MS
1041ps_text_t * /* O - Fonts */
1042write_prolog(const char *title, /* I - Title of job */
1043 const char *username) /* I - Username */
1044{
1045 time_t curtime; /* Current time */
1046 struct tm *curtm; /* Current date */
1047 char curdate[255]; /* Current date (text format) */
1048 ps_text_t *fonts; /* Fonts */
1f6f3dbc 1049
1f6f3dbc 1050
cda47a96
MS
1051 /*
1052 * Get the fonts we'll need...
1053 */
1f6f3dbc 1054
cda47a96 1055 fonts = psTextInitialize();
1f6f3dbc 1056
cda47a96
MS
1057 /*
1058 * Output the DSC header...
1059 */
1f6f3dbc 1060
cda47a96
MS
1061 curtime = time(NULL);
1062 curtm = localtime(&curtime);
1063 strftime(curdate, sizeof(curdate), "%c", curtm);
1f6f3dbc 1064
cda47a96
MS
1065 puts("%!PS-Adobe-3.0");
1066 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
1067 PageRight, PageTop);
1068 printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
1069 puts("%%Creator: bannertops/" CUPS_SVERSION);
1070 printf("%%%%CreationDate: %s\n", curdate);
1071 puts("%%LanguageLevel: 2");
1072 puts("%%DocumentData: Clean7Bit");
1073 WriteTextComment("Title", title);
1074 WriteTextComment("For", username);
1075 printf("%%%%Pages: %d\n", Duplex ? 2 : 1);
1076 psTextListFonts(fonts);
1077 puts("%%EndComments");
1078 puts("%%BeginProlog");
1079 psTextEmbedFonts(fonts);
1080 puts("%%EndProlog");
1f6f3dbc 1081
cda47a96 1082 return (fonts);
1f6f3dbc
MS
1083}
1084
1085
1086/*
1087 * End of "$Id$".
1088 */