]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - filter/bannertops.c
Merge changes from CUPS 1.4svn-r8606.
[thirdparty/cups.git] / filter / bannertops.c
index b4af85090bebee893000862f073de2b74cffd0fb..4bd8ced9dacf76a74d28d3ec02526d757008708f 100644 (file)
  *
  * Contents:
  *
+ *   main()           - Generate PostScript cover pages.
+ *   load_banner()    - Load the banner file.
+ *   ps_ascii85()     - Print binary data as a series of base-85 numbers.
+ *   write_banner()   - Write a banner page...
+ *   write_epilogue() - Write the PostScript file epilogue.
+ *   write_prolog()   - Write the PostScript file prolog with options.
  */
 
 /*
  * Include necessary headers...
  */
 
-#include "common.h"
+#include "pstext.h"
 #include "image.h"
 #include <cups/i18n.h>
 
 
 /*
- * Globals...
+ * Constants...
  */
 
-char           *Glyphs[65536]; /* PostScript glyphs for Unicode */
-int            NumFonts;       /* Number of fonts to use */
-char           *Fonts[256][4]; /* Fonts to use */
-unsigned short Chars[65536];   /* 0xffcc (ff = font, cc = char) */
-unsigned short Codes[65536];   /* Unicode glyph mapping to fonts */
-int            Widths[256];    /* Widths of each font */
-int            Directions[256];/* Text directions for each font */
+#define SHOW_IMAGEABLE_AREA            1       /* Show imageable area */
+#define SHOW_JOB_BILLING               2       /* Show billing string */
+#define SHOW_JOB_ID                    4       /* Show job ID */
+#define SHOW_JOB_NAME                  8       /* Show job title */
+#define SHOW_JOB_ORIGINATING_USER_NAME 16      /* Show owner of job */
+#define SHOW_JOB_ORIGINATING_HOST_NAME 32      /* Show submitting system */
+#define SHOW_JOB_UUID                  64      /* Show job UUID */
+#define SHOW_OPTIONS                   128     /* Show print options */
+#define SHOW_PAPER_NAME                        256     /* Show paper size name */
+#define SHOW_PAPER_SIZE                        512     /* Show paper dimensions */
+#define SHOW_PRINTER_DRIVER_NAME       1024    /* Show printer driver name */
+#define SHOW_PRINTER_DRIVER_VERSION    2048    /* Show printer driver version */
+#define SHOW_PRINTER_INFO              4096    /* Show printer description */
+#define SHOW_PRINTER_LOCATION          8192    /* Show printer location */
+#define SHOW_PRINTER_MAKE_AND_MODEL    16384   /* Show printer make and model */
+#define SHOW_PRINTER_NAME              32768   /* Show printer queue ID */
+#define SHOW_TIME_AT_CREATION          65536   /* Show date/time when submitted */
+#define SHOW_TIME_AT_PROCESSING                131072  /* Show date/time when printed */
 
 
 /*
- * Local functions...
- */
-
-static void    write_line(int row, lchar_t *line);
-static void    write_string(int col, int row, int len, lchar_t *s);
-static void    write_text(const char *s);
-
-
-/*
- * 'main()' - Generate PostScript cover pages.
+ * Structures...
  */
 
-int                    /* O - Exit status */
-main(int  argc,                /* I - Number of command-line arguments */
-     char *argv[])     /* I - Command-line arguments */
+typedef struct banner_file_s           /**** Banner file data ****/
 {
-}
+  int          show;                   /* What to show */
+  char         *header,                /* Header text */
+               *footer;                /* Footer text */
+  cups_array_t *notices,               /* Notices to show */
+               *images;                /* Images to show */
+} banner_file_t;
 
 
 /*
- * 'WriteEpilogue()' - Write the PostScript file epilogue.
- */
-
-void
-WriteEpilogue(void)
-{
-  puts("%%Trailer");
-  printf("%%%%Pages: %d\n", NumPages);
-  puts("%%EOF");
-
-  free(Page[0]);
-  free(Page);
-}
-
-
-/*
- * 'WritePage()' - Write a page of text.
+ * Local functions...
  */
 
-void
-WritePage(void)
-{
-  int  line;                   /* Current line */
-
-
-  NumPages ++;
-  printf("%%%%Page: %d %d\n", NumPages, NumPages);
-
-  puts("gsave");
-
-  if (PrettyPrint)
-    printf("%d H\n", NumPages);
-
-  for (line = 0; line < SizeLines; line ++)
-    write_line(line, Page[line]);
-
-  puts("grestore");
-  puts("showpage");
-
-  memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
-}
+static banner_file_t   *load_banner(const char *filename);
+static int             write_banner(banner_file_t *banner, ppd_file_t *ppd,
+                                    ps_text_t *fonts, int job_id,
+                                    const char *title, const char *username,
+                                    int num_options, cups_option_t *options);
+static void            write_epilogue(int num_pages);
+static ps_text_t       *write_prolog(const char *title, const char *user);
 
 
 /*
- * 'WriteProlog()' - Write the PostScript file prolog with options.
+ * 'main()' - Generate PostScript cover pages.
  */
 
-void
-WriteProlog(const char *title,         /* I - Title of job */
-           const char *user,           /* I - Username */
-            const char *classification,        /* I - Classification */
-           const char *label,          /* I - Page label */
-            ppd_file_t *ppd)           /* I - PPD file info */
+int                                    /* O - Exit status */
+main(int  argc,                                /* I - Number of command-line args */
+     char *argv[])                     /* I - Command-line arguments */
 {
-  int          i, j, k;        /* Looping vars */
-  char         *charset;       /* Character set string */
-  char         filename[1024]; /* Glyph filenames */
-  FILE         *fp;            /* Glyph files */
-  const char   *datadir;       /* CUPS_DATADIR environment variable */
-  char         line[1024],     /* Line from file */
-               *lineptr,       /* Pointer into line */
-               *valptr;        /* Pointer to value in line */
-  int          ch, unicode;    /* Character values */
-  int          start, end;     /* Start and end values for range */
-  char         glyph[64];      /* Glyph name */
-  time_t       curtime;        /* Current time */
-  struct tm    *curtm;         /* Current date */
-  char         curdate[255];   /* Current date (text format) */
-  int          num_fonts;      /* Number of unique fonts */
-  char         *fonts[1024];   /* Unique fonts */
-  static char  *names[] =      /* Font names */
-               {
-                 "cupsNormal",
-                 "cupsBold",
-                 "cupsItalic"
-               };
+  banner_file_t        *banner;                /* Banner file data */
+  int          num_options;            /* Number of print options */
+  cups_option_t        *options;               /* Print options */
+  ppd_file_t   *ppd;                   /* PPD file */
+  ps_text_t    *fonts;                 /* Fonts for output */
+  int          job_id;                 /* Job ID from command-line */
+  const char   *title,                 /* Title from command-line */
+               *username;              /* Username from command-line */
+  int          num_pages;              /* Number of pages printed */
 
 
  /*
-  * Get the data directory...
+  * Make sure status messages are not buffered...
   */
 
-  if ((datadir = getenv("CUPS_DATADIR")) == NULL)
-    datadir = CUPS_DATADIR;
+  setbuf(stderr, NULL);
 
  /*
-  * Adjust margins as necessary...
+  * Check command-line...
   */
 
-  if (classification || label)
+  if (argc < 6 || argc > 7)
   {
-   /*
-    * Leave room for labels...
-    */
-
-    PageBottom += 36;
-    PageTop    -= 36;
+    _cupsLangPrintf(stderr,
+                    _("Usage: %s job-id user title copies options [file]\n"),
+                    "bannertops");
+    return (1);
   }
 
  /*
-  * Allocate memory for the page...
+  * Get stuff from command-line...
   */
 
-  SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
-  SizeLines   = (PageTop - PageBottom) / 72.0 * LinesPerInch;
+  job_id      = atoi(argv[1]);
+  username    = argv[2];
+  title       = argv[3];
+  options     = NULL;
+  num_options = cupsParseOptions(argv[5], 0, &options);
+  banner      = load_banner(argv[6]);
 
-  Page    = calloc(sizeof(lchar_t *), SizeLines);
-  Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
-  for (i = 1; i < SizeLines; i ++)
-    Page[i] = Page[0] + i * SizeColumns;
+ /*
+  * Set standard options and get the PPD file for this printer...
+  */
 
-  if (PageColumns > 1)
-  {
-    ColumnGutter = CharsPerInch / 2;
-    ColumnWidth  = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
-                   PageColumns;
-  }
-  else
-    ColumnWidth = SizeColumns;
+  ppd = SetCommonOptions(num_options, options, 1);
 
  /*
-  * Output the DSC header...
+  * Write a PostScript banner document and return...
   */
 
-  curtime = time(NULL);
-  curtm   = localtime(&curtime);
-  strftime(curdate, sizeof(curdate), "%c", curtm);
+  fonts       = write_prolog(title, username);
+  num_pages   = write_banner(banner, ppd, fonts, job_id, title, username,
+                             num_options, options);
 
-  puts("%!PS-Adobe-3.0");
-  printf("%%%%BoundingBox: 0 0 %.0f %.0f\n", PageWidth, PageLength);
-  printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
-  puts("%%Creator: texttops/" CUPS_SVERSION);
-  printf("%%%%CreationDate: %s\n", curdate);
-  WriteTextComment("Title", title);
-  WriteTextComment("For", user);
-  puts("%%Pages: (atend)");
+  write_epilogue(num_pages);
 
- /*
-  * Initialize globals...
-  */
+  return (0);
+}
 
-  NumFonts = 0;
-  memset(Fonts, 0, sizeof(Fonts));
-  memset(Glyphs, 0, sizeof(Glyphs));
-  memset(Chars, 0, sizeof(Chars));
-  memset(Codes, 0, sizeof(Codes));
 
- /*
-  * Load the PostScript glyph names and the corresponding character
-  * set definition...
-  */
+/*
+ * 'load_banner()' - Load the banner file.
+ */
 
-  snprintf(filename, sizeof(filename), "%s/data/psglyphs", datadir);
+static banner_file_t *                 /* O - Banner file data */
+load_banner(const char *filename)      /* I - Filename or NULL for stdin */
+{
+  cups_file_t  *fp;                    /* File */
+  char         line[2048],             /* Line buffer */
+               *ptr;                   /* Pointer into line */
+  int          linenum;                /* Current line number */
+  banner_file_t        *banner;                /* Banner file data */
+  const char   *cups_docroot;          /* CUPS_DOCROOT environment variable */
 
-  if ((fp = fopen(filename, "r")) != NULL)
-  {
-    while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
-      Glyphs[unicode] = strdup(glyph);
 
-    fclose(fp);
-  }
+  fprintf(stderr, "DEBUG: load_banner(filename=\"%s\")\n",
+          filename ? filename : "(stdin)");
+
+ /*
+  * Open the banner file...
+  */
+
+  if (filename)
+    fp = cupsFileOpen(filename, "r");
   else
+    fp = cupsFileStdin();
+
+  if (!fp)
   {
-    fprintf(stderr, _("ERROR: Unable to open \"%s\" - %s\n"), filename,
-            strerror(errno));
+    _cupsLangPrintf(stderr,
+                   _("ERROR: Unable to open banner file \"%s\" - %s\n"),
+                    filename ? filename : "(stdin)", strerror(errno));
     exit(1);
   }
 
  /*
-  * Get the output character set...
+  * Read the banner file...
   */
 
-  charset = getenv("CHARSET");
-  if (charset != NULL && strcmp(charset, "us-ascii") != 0)
+  if ((cups_docroot = getenv("CUPS_DOCROOT")) == NULL)
+    cups_docroot = CUPS_DOCROOT;
+
+  banner  = calloc(1, sizeof(banner_file_t));
+  linenum = 0;
+
+  while (cupsFileGets(fp, line, sizeof(line)))
   {
-    snprintf(filename, sizeof(filename), "%s/charsets/%s", datadir, charset);
+   /*
+    * Skip blank and comment lines...
+    */
 
-    if ((fp = fopen(filename, "r")) == NULL)
-    {
-     /*
-      * Can't open charset file!
-      */
+    linenum ++;
 
-      fprintf(stderr, _("ERROR: Unable to open %s: %s\n"), filename,
-              strerror(errno));
-      exit(1);
-    }
+    if (line[0] == '#' || !line[0])
+      continue;
 
    /*
-    * Opened charset file; now see if this is really a charset file...
+    * Break the line into keyword and value parts...
     */
 
-    if (fgets(line, sizeof(line), fp) == NULL)
-    {
-     /*
-      * Bad/empty charset file!
-      */
+    for (ptr = line; *ptr && !isspace(*ptr & 255); ptr ++);
 
-      fclose(fp);
-      fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
-      exit(1);
-    }
+    while (isspace(*ptr & 255))
+      *ptr++ = '\0';
 
-    if (strncmp(line, "charset", 7) != 0)
+    if (!*ptr)
     {
-     /*
-      * Bad format/not a charset file!
-      */
-
-      fclose(fp);
-      fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
-      exit(1);
+      _cupsLangPrintf(stderr,
+                      _("ERROR: Missing value on line %d of banner file!\n"),
+                     linenum);
+      continue;
     }
 
    /*
-    * See if this is an 8-bit or UTF-8 character set file...
+    * Save keyword values in the appropriate places...
     */
 
-    line[strlen(line) - 1] = '\0'; /* Drop \n */
-    for (lineptr = line + 7; isspace(*lineptr & 255); lineptr ++); /* Skip whitespace */
-
-    if (strcmp(lineptr, "8bit") == 0)
+    if (!strcasecmp(line, "Footer"))
+    {
+      if (banner->footer)
+        fprintf(stderr, "DEBUG: Extra \"Footer\" on line %d of banner file!\n",
+               linenum);
+      else
+        banner->footer = strdup(ptr);
+    }
+    else if (!strcasecmp(line, "Header"))
     {
-     /*
-      * 8-bit text...
-      */
+      if (banner->header)
+        fprintf(stderr, "DEBUG: Extra \"Header\" on line %d of banner file!\n",
+               linenum);
+      else
+        banner->header = strdup(ptr);
+    }
+    else if (!strcasecmp(line, "Image"))
+    {
+      char     imagefile[1024];        /* Image filename */
 
-      UTF8     = 0;
-      NumFonts = 0;
 
-     /*
-      * Read the font description(s)...
-      */
+      if (ptr[0] == '/')
+        strlcpy(imagefile, ptr, sizeof(imagefile));
+      else
+        snprintf(imagefile, sizeof(imagefile), "%s/%s", cups_docroot, ptr);
 
-      while (fgets(line, sizeof(line), fp) != NULL)
+      if (access(imagefile, R_OK))
       {
-       /*
-        * Skip comment and blank lines...
-       */
-
-        if (line[0] == '#' || line[0] == '\n')
-         continue;
-
-       /*
-       * Read the font descriptions that should look like:
-       *
-       *   first last direction width normal [bold italic bold-italic]
-       */
-
-       lineptr = line;
-
-        start = strtol(lineptr, &lineptr, 16);
-       end   = strtol(lineptr, &lineptr, 16);
-
-       while (isspace(*lineptr & 255))
-         lineptr ++;
-
-        if (!*lineptr)
-         break;        /* Must be a font mapping */
-
-       valptr = lineptr;
-
-       while (!isspace(*lineptr & 255) && *lineptr)
-         lineptr ++;
-
-       if (!*lineptr)
-       {
-        /*
-         * Can't have a font without all required values...
-         */
-
-         fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       *lineptr++ = '\0';
-
-       if (strcmp(valptr, "ltor") == 0)
-         Directions[NumFonts] = 1;
-       else if (strcmp(valptr, "rtol") == 0)
-         Directions[NumFonts] = -1;
-       else
-       {
-         fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       /*
-       * Got the direction, now get the width...
-       */
-
-       while (isspace(*lineptr & 255))
-         lineptr ++;
-
-       valptr = lineptr;
-
-       while (!isspace(*lineptr & 255) && *lineptr)
-         lineptr ++;
-
-       if (!*lineptr)
-       {
-        /*
-         * Can't have a font without all required values...
-         */
-
-         fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       *lineptr++ = '\0';
-
-       if (strcmp(valptr, "single") == 0)
-          Widths[NumFonts] = 1;
-       else if (strcmp(valptr, "double") == 0)
-          Widths[NumFonts] = 2;
-       else 
-       {
-         fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       /*
-       * Get the fonts...
-       */
-
-       for (i = 0; *lineptr && i < 4; i ++)
-       {
-         while (isspace(*lineptr & 255))
-           lineptr ++;
-
-         valptr = lineptr;
-
-         while (!isspace(*lineptr & 255) && *lineptr)
-           lineptr ++;
-
-          if (*lineptr)
-           *lineptr++ = '\0';
-
-          if (lineptr > valptr)
-           Fonts[NumFonts][i] = strdup(valptr);
-       }
-
-       /*
-       * Fill in remaining fonts as needed...
-       */
-
-       for (j = i; j < 4; j ++)
-         Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
-
-       /*
-        * Define the character mappings...
-       */
-
-       for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
-         Chars[i] = j;
-
-        NumFonts ++;
+        fprintf(stderr, "DEBUG: Image \"%s\" on line %d of banner file: %s\n",
+               ptr, linenum, strerror(errno));
       }
-
-     /*
-      * Read encoding lines...
-      */
-
-      do
+      else
       {
-       /*
-        * Skip comment and blank lines...
-       */
+        if (!banner->images)
+         banner->images = cupsArrayNew(NULL, NULL);
 
-        if (line[0] == '#' || line[0] == '\n')
-         continue;
-
-       /*
-        * Grab the character and unicode glyph number.
-       */
-
-       if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256)
-          Codes[Chars[ch]] = unicode;
+        cupsArrayAdd(banner->images, strdup(imagefile));
       }
-      while (fgets(line, sizeof(line), fp) != NULL);
-
-      fclose(fp);
     }
-    else if (strcmp(lineptr, "utf8") == 0)
+    else if (!strcasecmp(line, "Notice"))
     {
-     /*
-      * UTF-8 (Unicode) text...
-      */
-
-      UTF8 = 1;
+      if (!banner->notices)
+       banner->notices = cupsArrayNew(NULL, NULL);
 
-     /*
-      * Read the font descriptions...
-      */
+      cupsArrayAdd(banner->notices, strdup(ptr));
+    }
+    else if (!strcasecmp(line, "Show"))
+    {
+      char     *value;                 /* Current value */
 
-      NumFonts = 0;
 
-      while (fgets(line, sizeof(line), fp) != NULL)
+      for (value = ptr; *value; value = ptr)
       {
        /*
-        * Skip comment and blank lines...
+       * Find the end of the current value
        */
 
-        if (line[0] == '#' || line[0] == '\n')
-         continue;
-
-       /*
-       * Read the font descriptions that should look like:
-       *
-       *   start end direction width normal [bold italic bold-italic]
-       */
-
-       lineptr = line;
-
-        start = strtol(lineptr, &lineptr, 16);
-       end   = strtol(lineptr, &lineptr, 16);
-
-       while (isspace(*lineptr & 255))
-         lineptr ++;
-
-       valptr = lineptr;
-
-       while (!isspace(*lineptr & 255) && *lineptr)
-         lineptr ++;
-
-       if (!*lineptr)
-       {
-        /*
-         * Can't have a font without all required values...
-         */
-
-         fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       *lineptr++ = '\0';
-
-       if (strcmp(valptr, "ltor") == 0)
-         Directions[NumFonts] = 1;
-       else if (strcmp(valptr, "rtol") == 0)
-         Directions[NumFonts] = -1;
-       else
-       {
-         fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       /*
-       * Got the direction, now get the width...
-       */
-
-       while (isspace(*lineptr & 255))
-         lineptr ++;
-
-       valptr = lineptr;
-
-       while (!isspace(*lineptr & 255) && *lineptr)
-         lineptr ++;
-
-       if (!*lineptr)
-       {
-        /*
-         * Can't have a font without all required values...
-         */
-
-         fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       *lineptr++ = '\0';
-
-       if (strcmp(valptr, "single") == 0)
-          Widths[NumFonts] = 1;
-       else if (strcmp(valptr, "double") == 0)
-          Widths[NumFonts] = 2;
-       else 
-       {
-         fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
-         fclose(fp);
-         exit(1);
-       }
-
-       /*
-       * Get the fonts...
-       */
-
-       for (i = 0; *lineptr && i < 4; i ++)
-       {
-         while (isspace(*lineptr & 255))
-           lineptr ++;
-
-         valptr = lineptr;
-
-         while (!isspace(*lineptr & 255) && *lineptr)
-           lineptr ++;
-
-          if (*lineptr)
-           *lineptr++ = '\0';
+        while (*ptr && !isspace(*ptr & 255))
+         ptr ++;
 
-          if (lineptr > valptr)
-           Fonts[NumFonts][i] = strdup(valptr);
-       }
-
-       /*
-       * Fill in remaining fonts as needed...
-       */
-
-       for (j = i; j < 4; j ++)
-         Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
+        while (*ptr && isspace(*ptr & 255))
+         *ptr++ = '\0';
 
        /*
-        * Define the character mappings...
+        * Add the value to the show flags...
        */
-
-       for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
-       {
-         Chars[i] = j;
-          Codes[j] = i;
+       if (!strcasecmp(value, "imageable-area"))
+         banner->show |= SHOW_IMAGEABLE_AREA;
+       else if (!strcasecmp(value, "job-billing"))
+         banner->show |= SHOW_JOB_BILLING;
+       else if (!strcasecmp(value, "job-id"))
+         banner->show |= SHOW_JOB_ID;
+       else if (!strcasecmp(value, "job-name"))
+         banner->show |= SHOW_JOB_NAME;
+       else if (!strcasecmp(value, "job-originating-host-name"))
+         banner->show |= SHOW_JOB_ORIGINATING_HOST_NAME;
+       else if (!strcasecmp(value, "job-originating-user-name"))
+         banner->show |= SHOW_JOB_ORIGINATING_USER_NAME;
+       else if (!strcasecmp(value, "job-uuid"))
+         banner->show |= SHOW_JOB_UUID;
+       else if (!strcasecmp(value, "options"))
+         banner->show |= SHOW_OPTIONS;
+       else if (!strcasecmp(value, "paper-name"))
+         banner->show |= SHOW_PAPER_NAME;
+       else if (!strcasecmp(value, "paper-size"))
+         banner->show |= SHOW_PAPER_SIZE;
+       else if (!strcasecmp(value, "printer-driver-name"))
+         banner->show |= SHOW_PRINTER_DRIVER_NAME;
+       else if (!strcasecmp(value, "printer-driver-version"))
+         banner->show |= SHOW_PRINTER_DRIVER_VERSION;
+       else if (!strcasecmp(value, "printer-info"))
+         banner->show |= SHOW_PRINTER_INFO;
+       else if (!strcasecmp(value, "printer-location"))
+         banner->show |= SHOW_PRINTER_LOCATION;
+       else if (!strcasecmp(value, "printer-make-and-model"))
+         banner->show |= SHOW_PRINTER_MAKE_AND_MODEL;
+       else if (!strcasecmp(value, "printer-name"))
+         banner->show |= SHOW_PRINTER_NAME;
+       else if (!strcasecmp(value, "time-at-creation"))
+         banner->show |= SHOW_TIME_AT_CREATION;
+       else if (!strcasecmp(value, "time-at-processing"))
+         banner->show |= SHOW_TIME_AT_PROCESSING;
+       else
+        {
+         fprintf(stderr,
+                 "DEBUG: Unknown \"Show\" value \"%s\" on line %d of banner "
+                 "file!\n", value, linenum);
        }
-
-       /*
-        * Move to the next font, stopping if needed...
-       */
-
-        NumFonts ++;
-       if (NumFonts >= 256)
-         break;
       }
-
-      fclose(fp);
     }
     else
-    {
-      fprintf(stderr, _("ERROR: Bad charset type %s\n"), lineptr);
-      fclose(fp);
-      exit(1);
-    }
+      fprintf(stderr, "DEBUG: Unknown key \"%s\" on line %d of banner file!\n",
+              line, linenum);
   }
-  else
-  {
-   /*
-    * Standard ASCII output just uses Courier, Courier-Bold, and
-    * possibly Courier-Oblique.
-    */
-
-    NumFonts = 1;
 
-    Fonts[0][ATTR_NORMAL]     = strdup("Courier");
-    Fonts[0][ATTR_BOLD]       = strdup("Courier-Bold");
-    Fonts[0][ATTR_ITALIC]     = strdup("Courier-Oblique");
-    Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique");
+  if (filename)
+    cupsFileClose(fp);
 
-    Widths[0]     = 1;
-    Directions[0] = 1;
+  return (banner);
+}
 
-   /*
-    * Define US-ASCII characters...
-    */
 
-    for (i = 32; i < 127; i ++)
-    {
-      Chars[i] = i;
-      Codes[i] = i;
-    }
-  }
+/*
+ * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
+ */
 
- /*
-  * Generate a list of unique fonts to use...
-  */
+static void
+ps_ascii85(cups_ib_t *data,            /* I - Data to print */
+          int       length,            /* I - Number of bytes to print */
+          int       last_line)         /* I - Last line of raster data? */
+{
+  unsigned     b;                      /* Binary data word */
+  unsigned char        c[5];                   /* ASCII85 encoded chars */
+  static int   col = 0;                /* Current column */
 
-  for (i = 0, num_fonts = 0; i < NumFonts; i ++)
-    for (j = PrettyPrint ? 2 : 1; j >= 0; j --)
-    {
-      for (k = 0; k < num_fonts; k ++)
-        if (strcmp(Fonts[i][j], fonts[k]) == 0)
-         break;
 
-      if (k >= num_fonts)
-      {
-       /*
-        * Add new font...
-       */
+  while (length > 3)
+  {
+    b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
 
-        fonts[num_fonts] = Fonts[i][j];
-       num_fonts ++;
-      }
+    if (b == 0)
+    {
+      putchar('z');
+      col ++;
     }
-
- /*
-  * List the fonts that will be used...
-  */
-
-  for (i = 0; i < num_fonts; i ++)
-    if (i == 0)
-      printf("%%%%DocumentNeededResources: font %s\n", fonts[i]);
     else
-      printf("%%%%+ font %s\n", fonts[i]);
-
-  puts("%%DocumentSuppliedResources: procset texttops 1.1 0");
-
-  for (i = 0; i < num_fonts; i ++)
-  {
-    if (ppd != NULL)
     {
-      fprintf(stderr, "DEBUG: ppd->num_fonts = %d\n", ppd->num_fonts);
-
-      for (j = 0; j < ppd->num_fonts; j ++)
-      {
-        fprintf(stderr, "DEBUG: ppd->fonts[%d] = %s\n", j, ppd->fonts[j]);
-
-       if (strcmp(fonts[i], ppd->fonts[j]) == 0)
-          break;
-      }
+      c[4] = (b % 85) + '!';
+      b /= 85;
+      c[3] = (b % 85) + '!';
+      b /= 85;
+      c[2] = (b % 85) + '!';
+      b /= 85;
+      c[1] = (b % 85) + '!';
+      b /= 85;
+      c[0] = b + '!';
+
+      fwrite(c, 5, 1, stdout);
+      col += 5;
     }
-    else
-      j = 0;
 
-    if ((ppd != NULL && j >= ppd->num_fonts) ||
-        strncmp(fonts[i], "Courier", 7) == 0 ||
-       strcmp(fonts[i], "Symbol") == 0)
-    {
-     /*
-      * Need to embed this font...
-      */
+    data += 4;
+    length -= 4;
 
-      printf("%%%%+ font %s\n", fonts[i]);
+    if (col >= 75)
+    {
+      putchar('\n');
+      col = 0;
     }
   }
 
-  puts("%%EndComments");
-
-  puts("%%BeginProlog");
-
- /*
-  * Download any missing fonts...
-  */
-
-  for (i = 0; i < num_fonts; i ++)
+  if (last_line)
   {
-    if (ppd != NULL)
+    if (length > 0)
     {
-      for (j = 0; j < ppd->num_fonts; j ++)
-       if (strcmp(fonts[i], ppd->fonts[j]) == 0)
-          break;
+      memset(data + length, 0, 4 - length);
+      b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+      c[4] = (b % 85) + '!';
+      b /= 85;
+      c[3] = (b % 85) + '!';
+      b /= 85;
+      c[2] = (b % 85) + '!';
+      b /= 85;
+      c[1] = (b % 85) + '!';
+      b /= 85;
+      c[0] = b + '!';
+
+      fwrite(c, length + 1, 1, stdout);
     }
-    else
-      j = 0;
 
-    if ((ppd != NULL && j >= ppd->num_fonts) ||
-        strncmp(fonts[i], "Courier", 7) == 0 ||
-       strcmp(fonts[i], "Symbol") == 0)
-    {
-     /*
-      * Need to embed this font...
-      */
+    puts("~>");
+    col = 0;
+  }
+}
 
-      printf("%%%%BeginResource: font %s\n", fonts[i]);
 
-      /**** MRS: Need to use CUPS_FONTPATH env var! ****/
-      /**** Also look for Fontmap file or name.pfa, name.pfb... ****/
-      snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, fonts[i]);
-      if ((fp = fopen(filename, "rb")) != NULL)
-      {
-        while ((j = fread(line, 1, sizeof(line), fp)) > 0)
-         fwrite(line, 1, j, stdout);
+/*
+ * 'write_banner()' - Write a banner page...
+ */
 
-       fclose(fp);
-      }
+static int                             /* O - Number of pages */
+write_banner(banner_file_t *banner,    /* I - Banner file */
+             ppd_file_t    *ppd,       /* I - PPD file */
+            ps_text_t     *fonts,      /* I - Fonts */
+            int           job_id,      /* I - Job ID */
+            const char    *title,      /* I - Title of job */
+            const char    *username,   /* I - Owner of job */
+            int           num_options, /* I - Number of options */
+            cups_option_t *options)    /* I - Options */
+{
+  char         *notice;                /* Current notice */
+  char         *imagefile;             /* Current image file */
+  cups_array_t *images;                /* Images */
+  cups_image_t *image;                 /* Current image */
+  const char   *option;                /* Option value */
+  int          i, j;                   /* Looping vars */
+  float                x,                      /* Current X position */
+               y;                      /* Current Y position */
+  cups_lang_t  *language;              /* Default language */
+  int          showlines;              /* Number of lines to show */
+  float                fontsize;               /* Font size to use */
+  int          num_pages;              /* Number of pages */
+  float                print_width,            /* Printable width of page */
+               print_height,           /* Printable height of page */
+               info_top,               /* Top of info fields */
+               info_height,            /* Height of info fields */
+               line_height,            /* Height of info lines */
+               notices_height,         /* Height of all notices */
+               images_width,           /* Width of all images */
+               images_height,          /* Height of all images */
+               total_height;           /* Height of all content */
+  char         text[1024];             /* Formatted field text */
 
-      puts("\n%%EndResource");
-    }
-  }
 
  /*
-  * Write the encoding array(s)...
+  * Figure out how many lines of text will be shown...
   */
 
-  puts("% character encoding(s)");
-
-  for (i = 0; i < NumFonts; i ++)
+  showlines = 0;
+  if (banner->show & SHOW_IMAGEABLE_AREA)
+    showlines += 2;
+  if (banner->show & SHOW_JOB_BILLING)
+    showlines ++;
+  if (banner->show & SHOW_JOB_ID)
+    showlines ++;
+  if (banner->show & SHOW_JOB_NAME)
+    showlines ++;
+  if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
+    showlines ++;
+  if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
+    showlines ++;
+  if (banner->show & SHOW_JOB_UUID)
+    showlines ++;
+  if (banner->show & SHOW_OPTIONS)
   {
-    printf("/cupsEncoding%02x [\n", i);
-
-    for (ch = 0; ch < 256; ch ++)
+    for (j = 0; j < num_options; j ++)
     {
-      if (Glyphs[Codes[i * 256 + ch]])
-       printf("/%s", Glyphs[Codes[i * 256 + ch]]);
-      else if (Codes[i * 256 + ch] > 255)
-        printf("/uni%04X", Codes[i * 256 + ch]);
-      else
-       printf("/.notdef");
-
-      if ((ch & 7) == 7)
-       putchar('\n');
+      if (strcasecmp("media", options[j].name) &&
+         strcasecmp("PageSize", options[j].name) &&
+         strcasecmp("PageRegion", options[j].name) &&
+         strcasecmp("InputSlot", options[j].name) &&
+         strcasecmp("MediaType", options[j].name) &&
+         strcasecmp("finishings", options[j].name) &&
+         strcasecmp("sides", options[j].name) &&
+         strcasecmp("Duplex", options[j].name) &&
+         strcasecmp("orientation-requested", options[j].name) &&
+         strcasecmp("landscape", options[j].name) &&
+         strcasecmp("number-up", options[j].name) &&
+         strcasecmp("OutputOrder", options[j].name))
+      continue;
+
+      showlines ++;
     }
-
-    puts("] def");
   }
+  if (banner->show & SHOW_PAPER_NAME)
+    showlines ++;
+  if (banner->show & SHOW_PAPER_SIZE)
+    showlines += 2;
+  if (banner->show & SHOW_PRINTER_DRIVER_NAME)
+    showlines ++;
+  if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
+    showlines ++;
+  if (banner->show & SHOW_PRINTER_INFO)
+    showlines ++;
+  if (banner->show & SHOW_PRINTER_LOCATION)
+    showlines ++;
+  if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
+    showlines ++;
+  if (banner->show & SHOW_PRINTER_NAME)
+    showlines ++;
+  if (banner->show & SHOW_TIME_AT_CREATION)
+    showlines ++;
+  if (banner->show & SHOW_TIME_AT_PROCESSING)
+    showlines ++;
 
  /*
-  * Create the fonts...
+  * Figure out the dimensions and positions of everything...
   */
 
-  if (NumFonts == 1)
-  {
-   /*
-    * Just reencode the named fonts...
-    */
+  print_width    = PageRight - PageLeft;
+  print_height   = PageTop - PageBottom;
+  fontsize       = print_height / 60;  /* Nominally 12pts */
+  line_height    = 1.2 * fontsize;
+  info_height    = showlines * line_height;
+  notices_height = cupsArrayCount(banner->notices) * line_height;
 
-    puts("% Reencode fonts");
+  if (cupsArrayCount(banner->images))
+  {
+    images        = cupsArrayNew(NULL, NULL);
+    images_height = print_height / 10; /* Nominally 1" */
 
-    for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
+    for (imagefile = (char *)cupsArrayFirst(banner->images), images_width = 0.0;
+         imagefile;
+        imagefile = (char *)cupsArrayNext(banner->images))
     {
-      printf("/%s findfont\n", Fonts[0][i]);
-      puts("dup length 1 add dict begin\n"
-          "    { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
-          "    /Encoding cupsEncoding00 def\n"
-          "    currentdict\n"
-          "end");
-      printf("/%s exch definefont pop\n", names[i]);
+      if ((image = cupsImageOpen(imagefile, ColorDevice ? CUPS_IMAGE_RGB_CMYK :
+                                                          CUPS_IMAGE_WHITE,
+                                CUPS_IMAGE_WHITE, 100, 0, NULL)) == NULL)
+      {
+        fprintf(stderr, "DEBUG: Unable to open image file \"%s\"!\n",
+               imagefile);
+        continue;
+      }
+
+      images_width += cupsImageGetWidth(image) * images_height /
+                      cupsImageGetHeight(image);
+      cupsArrayAdd(images, image);
     }
   }
   else
   {
-   /*
-    * Construct composite fonts...  Start by reencoding the base fonts...
-    */
-
-    puts("% Reencode base fonts");
-
-    for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
-      for (j = 0; j < NumFonts; j ++)
-      {
-       printf("/%s findfont\n", Fonts[j][i]);
-       printf("dup length 1 add dict begin\n"
-              "        { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
-              "        /Encoding cupsEncoding%02x def\n"
-              "        currentdict\n"
-              "end\n", j);
-       printf("/%s%02x exch definefont /%s%02x exch def\n", names[i], j,
-              names[i], j);
-      }
-
-   /*
-    * Then merge them into composite fonts...
-    */
+    images        = NULL;
+    images_height = 0;
+    images_width  = 0;
+  }
 
-    puts("% Create composite fonts...");
+  total_height = info_height + notices_height + images_height;
+  if (cupsArrayCount(banner->notices) && showlines)
+    total_height += 2 * line_height;
+  if (cupsArrayCount(banner->images) &&
+      (showlines || cupsArrayCount(banner->notices)))
+    total_height += 2 * line_height;
 
-    for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
-    {
-      puts("8 dict begin");
-      puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def/Encoding[");
-      for (j = 0; j < NumFonts; j ++)
-        if (j == (NumFonts - 1))
-         printf("%d", j);
-       else if ((j & 15) == 15)
-          printf("%d\n", j);
-       else
-         printf("%d ", j);
-      puts("]def/FDepVector[");
-      for (j = 0; j < NumFonts; j ++)
-        if (j == (NumFonts - 1))
-          printf("%s%02x", names[i], j);
-       else if ((j & 3) == 3)
-          printf("%s%02x\n", names[i], j);
-       else
-         printf("%s%02x ", names[i], j);
-      puts("]def currentdict end");
-      printf("/%s exch definefont pop\n", names[i]);
-    }
-  }
+  info_top = 0.5 * (print_height + total_height);
 
  /*
-  * Output the texttops procset...
+  * Write the page(s)...
   */
 
-  puts("%%BeginResource: procset texttops 1.1 0");
-
-  puts("% Define fonts");
+  language  = cupsLangDefault();
+  num_pages = Duplex ? 2 : 1;
 
-  printf("/FN /cupsNormal findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
-         120.0 / CharsPerInch, 68.0 / LinesPerInch);
-  printf("/FB /cupsBold findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
-         120.0 / CharsPerInch, 68.0 / LinesPerInch);
-  if (PrettyPrint)
-    printf("/FI /cupsItalic findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
-           120.0 / CharsPerInch, 68.0 / LinesPerInch);
-
-  puts("% Common procedures");
-
-  puts("/N { FN setfont moveto } bind def");
-  puts("/B { FB setfont moveto } bind def");
-  printf("/U { gsave 0.5 setlinewidth 0 %.3f rmoveto "
-         "0 rlineto stroke grestore } bind def\n", -6.8 / LinesPerInch);
-
-  if (PrettyPrint)
+  for (i = 1; i <= num_pages; i ++)
   {
-    if (ColorDevice)
-    {
-      puts("/S { 0.0 setgray show } bind def");
-      puts("/r { 0.5 0.0 0.0 setrgbcolor show } bind def");
-      puts("/g { 0.0 0.5 0.0 setrgbcolor show } bind def");
-      puts("/b { 0.0 0.0 0.5 setrgbcolor show } bind def");
-    }
-    else
-    {
-      puts("/S { 0.0 setgray show } bind def");
-      puts("/r { 0.2 setgray show } bind def");
-      puts("/g { 0.2 setgray show } bind def");
-      puts("/b { 0.2 setgray show } bind def");
-    }
-
-    puts("/I { FI setfont moveto } bind def");
-
-    puts("/n {");
-    puts("\t20 string cvs % convert page number to string");
-    if (NumFonts > 1)
-    {
-     /*
-      * Convert a number to double-byte chars...
-      */
-
-      puts("\tdup length % get length");
-      puts("\tdup 2 mul string /P exch def % P = string twice as long");
-      puts("\t0 1 2 index 1 sub { % loop through each character in the page number");
-      puts("\t\tdup 3 index exch get % get character N from the page number");
-      puts("\t\texch 2 mul dup % compute offset in P");
-      puts("\t\tP exch 0 put % font 0");
-      puts("\t\t1 add P exch 2 index put % character");
-      puts("\t\tpop % discard character");
-      puts("\t} for % do for loop");
-      puts("\tpop pop % discard string and length");
-      puts("\tP % put string on stack");
-    }
-    puts("} bind def");
-
-    printf("/T");
-    write_text(title);
-    puts("def");
-
-    printf("/D");
-    write_text(curdate);
-    puts("def");
-
-    puts("/H {");
-    puts("\tgsave");
-    puts("\t0.9 setgray");
+   /*
+    * Start the page...
+    */
 
-    if (Duplex)
-    {
-      puts("\tdup 2 mod 0 eq {");
-      printf("\t\t%.3f %.3f translate } {\n",
-             PageWidth - PageRight, PageTop + 72.0f / LinesPerInch);
-      printf("\t\t%.3f %.3f translate } ifelse\n",
-             PageLeft, PageTop + 72.0f / LinesPerInch);
-    }
+    printf("%%%%Page: %s %d\n", i == 1 ? "coverpage" : "coverback", i);
+    puts("gsave");
+    if (i == 1)
+      printf("%.1f %.1f translate\n", PageLeft, PageBottom);
     else
-      printf("\t%.3f %.3f translate\n",
-             PageLeft, PageTop + 72.0f / LinesPerInch);
+      printf("%.1f %.1f translate\n", PageWidth - PageRight,
+             PageLength - PageRight);
+    puts("0 setgray");
 
-    printf("\t0 0 %.3f %.3f rectfill\n", PageRight - PageLeft,
-          144.0f / LinesPerInch);
+    y = info_top;
 
-    puts("\tFB setfont");
-    puts("\t0 setgray");
+   /*
+    * Information...
+    */
 
-    if (Duplex)
+    if (banner->show)
     {
-      puts("\tdup 2 mod 0 eq {");
-      printf("\t\tT stringwidth pop neg %.3f add %.3f } {\n",
-             PageRight - PageLeft - 36.0f / LinesPerInch,
-            (0.5f + 0.157f) * 72.0f / LinesPerInch);
-      printf("\t\t%.3f %.3f } ifelse\n", 36.0f / LinesPerInch,
-            (0.5f + 0.157f) * 72.0f / LinesPerInch);
-    }
-    else
-      printf("\t%.3f %.3f\n", 36.0f / LinesPerInch,
-            (0.5f + 0.157f) * 72.0f / LinesPerInch);
-
-    puts("\tmoveto T show");
+      x = 0.33 * print_width;
 
-    printf("\tD dup stringwidth pop neg 2 div %.3f add %.3f\n",
-           (PageRight - PageLeft) * 0.5,
-           (0.5f + 0.157f) * 72.0f / LinesPerInch);
-    puts("\tmoveto show");
+      if (banner->show & SHOW_PRINTER_NAME)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Printer Name: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, getenv("PRINTER"));
+      }
+      if (banner->show & SHOW_JOB_ID)
+      {
+        snprintf(text, sizeof(text), "%s-%d", getenv("PRINTER"), job_id);
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Job ID: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+      }
+      if (banner->show & SHOW_JOB_UUID)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Job UUID: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  cupsGetOption("job-uuid", num_options, options));
+      }
+      if (banner->show & SHOW_JOB_NAME)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Title: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, title);
+      }
+      if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Printed For: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, username);
+      }
+      if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Printed From: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  cupsGetOption("job-originating-host-name", num_options,
+                                options));
+      }
+      if (banner->show & SHOW_JOB_BILLING)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Billing Information: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  cupsGetOption("job-billing", num_options, options));
+      }
+      if (banner->show & SHOW_OPTIONS)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Options: ")));
 
-    if (Duplex)
-    {
-      puts("\tdup n exch 2 mod 0 eq {");
-      printf("\t\t%.3f %.3f } {\n", 36.0f / LinesPerInch,
-            (0.5f + 0.157f) * 72.0f / LinesPerInch);
-      printf("\t\tdup stringwidth pop neg %.3f add %.3f } ifelse\n",
-             PageRight - PageLeft - 36.0f / LinesPerInch,
-            (0.5f + 0.157f) * 72.0f / LinesPerInch);
-    }
-    else
-      printf("\tn dup stringwidth pop neg %.3f add %.3f\n",
-             PageRight - PageLeft - 36.0f / LinesPerInch,
-            (0.5f + 0.157f) * 72.0f / LinesPerInch);
+        for (j = 0; j < num_options; j ++)
+       {
+         if (strcasecmp("media", options[j].name) &&
+             strcasecmp("PageSize", options[j].name) &&
+             strcasecmp("PageRegion", options[j].name) &&
+             strcasecmp("InputSlot", options[j].name) &&
+             strcasecmp("MediaType", options[j].name) &&
+             strcasecmp("finishings", options[j].name) &&
+             strcasecmp("sides", options[j].name) &&
+             strcasecmp("Duplex", options[j].name) &&
+             strcasecmp("orientation-requested", options[j].name) &&
+             strcasecmp("landscape", options[j].name) &&
+             strcasecmp("number-up", options[j].name) &&
+             strcasecmp("OutputOrder", options[j].name))
+          continue;
+
+          if (!strcasecmp("landscape", options[j].name))
+           strlcpy(text, "orientation-requested=landscape", sizeof(text));
+         else if (!strcasecmp("orientation-requested", options[j].name))
+         {
+           switch (atoi(options[j].value))
+           {
+             default :
+             case IPP_PORTRAIT :
+                 strlcpy(text, "orientation-requested=portrait",
+                         sizeof(text));
+                 break;
+
+             case IPP_LANDSCAPE :
+                 strlcpy(text, "orientation-requested=landscape",
+                         sizeof(text));
+                 break;
+
+             case IPP_REVERSE_PORTRAIT :
+                 strlcpy(text, "orientation-requested=reverse-portrait",
+                         sizeof(text));
+                 break;
+
+             case IPP_REVERSE_LANDSCAPE :
+                 strlcpy(text, "orientation-requested=reverse-landscape",
+                         sizeof(text));
+                 break;
+           }
+         }
+         else
+           snprintf(text, sizeof(text), "%s=%s", options[j].name,
+                    options[j].value);
+
+         printf("%.1f %.1f moveto", x, y);
+         y -= line_height;
+         psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+        }
+      }
 
-    puts("\tmoveto show");
-    puts("\tgrestore");
-    puts("} bind def");
-  }
-  else
-    puts("/S { show } bind def");
+      if (banner->show & SHOW_PRINTER_INFO)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Description: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  getenv("PRINTER_INFO"));
+      }
+      if (banner->show & SHOW_PRINTER_LOCATION)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Location: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  getenv("PRINTER_LOCATION"));
+      }
+      if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Make and Model: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  ppd ? ppd->nickname : NULL);
+      }
 
-  puts("%%EndResource");
+      if (banner->show & SHOW_PAPER_NAME)
+      {
+        if ((option = cupsGetOption("media", num_options, options)) == NULL)
+         if ((option = cupsGetOption("PageSize", num_options, options)) == NULL)
+           if ((option = cupsGetOption("PageRegion", num_options,
+                                       options)) == NULL)
+             option = "Default";
+
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Media Name: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, option);
+      }
+      if (banner->show & SHOW_PAPER_SIZE)
+      {
+        snprintf(text, sizeof(text),
+                _cupsLangString(language, _("%.2f x %.2f inches")),
+                PageWidth / 72.0, PageLength / 72.0);
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Media Dimensions: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+
+        snprintf(text, sizeof(text),
+                _cupsLangString(language, _("%.0f x %.0f millimeters")),
+                PageWidth * 25.4 / 72.0, PageLength * 25.4 / 72.0);
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+      }
+      if (banner->show & SHOW_IMAGEABLE_AREA)
+      {
+        snprintf(text, sizeof(text),
+                _cupsLangString(language,
+                                _("%.2f x %.2f to %.2f x %.2f inches")),
+                PageLeft / 72.0, PageBottom / 72.0,
+                PageRight / 72.0, PageTop / 72.0);
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Media Limits: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+
+        snprintf(text, sizeof(text),
+                _cupsLangString(language,
+                                _("%.0f x %.0f to %.0f x %.0f millimeters")),
+                PageLeft * 25.4 / 72.0, PageBottom * 25.4 / 72.0,
+                PageRight * 25.4 / 72.0, PageTop * 25.4 / 72.0);
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+
+       printf("gsave 2 setlinewidth 1 1 %.1f %.1f rectstroke grestore\n",
+              print_width - 2.0, print_height - 2.0);
+      }
+      if (banner->show & SHOW_PRINTER_DRIVER_NAME)
+      {
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Driver Name: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  ppd ? ppd->pcfilename : NULL);
+      }
+      if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
+      {
+        ppd_attr_t  *file_version = ppdFindAttr(ppd, "FileVersion", NULL);
+
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Driver Version: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+                  file_version ? file_version->value : NULL);
+      }
+      if (banner->show & SHOW_TIME_AT_CREATION)
+      {
+        if ((option = cupsGetOption("time-at-creation", num_options,
+                                   options)) != NULL)
+        {
+         time_t        curtime;        /* Current time */
+         struct tm     *curdate;       /* Current date */
 
-  puts("%%EndProlog");
-}
+          curtime = (time_t)atoi(option);
+         curdate = localtime(&curtime);
 
+          strftime(text, sizeof(text), "%c", curdate);
+       }
+       else
+         strlcpy(text, "?", sizeof(text));
 
-/*
- * 'write_line()' - Write a row of text.
- */
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Created On: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+      }
+      if (banner->show & SHOW_TIME_AT_PROCESSING)
+      {
+        if ((option = cupsGetOption("time-at-processing", num_options,
+                                   options)) != NULL)
+        {
+         time_t        curtime;        /* Current time */
+         struct tm     *curdate;       /* Current date */
 
-static void
-write_line(int     row,                /* I - Row number (0 to N) */
-           lchar_t *line)      /* I - Line to print */
-{
-  int          i;              /* Looping var */
-  int          col;            /* Current column */
-  int          attr;           /* Current attribute */
-  int          font,           /* Font to use */
-               lastfont,       /* Last font */
-               mono;           /* Monospaced? */
-  lchar_t      *start;         /* First character in sequence */
+          curtime = (time_t)atoi(option);
+         curdate = localtime(&curtime);
 
+          strftime(text, sizeof(text), "%c", curdate);
+       }
+       else
+         strlcpy(text, "?", sizeof(text));
 
-  for (col = 0; col < SizeColumns;)
-  {
-    while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
-    {
-      col ++;
-      line ++;
+       printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+                  _cupsLangString(language, _("Printed On: ")));
+        psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+      }
     }
 
-    if (col >= SizeColumns)
-      break;
+   /*
+    * Notices...
+    */
 
-    if (NumFonts == 1)
+    if (cupsArrayCount(banner->notices))
     {
-     /*
-      * All characters in a single font - assume monospaced...
-      */
+      if (banner->show)
+        y -= 2 * line_height;
 
-      attr  = line->attr;
-      start = line;
+      x = 0.5 * print_width;
 
-      while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+      for (notice = (char *)cupsArrayFirst(banner->notices);
+           notice;
+          notice = (char *)cupsArrayNext(banner->notices))
       {
-       col ++;
-       line ++;
+        printf("%.1f %.1f moveto", x, y);
+       y -= line_height;
+       psTextUTF8(fonts, fontsize, PS_NORMAL, PS_CENTER, notice);
       }
-
-      write_string(col - (line - start), row, line - start, start);
     }
-    else
-    {
-     /*
-      * Multiple fonts; break up based on the font...
-      */
-
-      attr     = line->attr;
-      start    = line;
-      lastfont = Chars[line->ch] / 256;
-      mono     = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
-      col ++;
-      line ++;
 
-      if (mono)
-      {
-       while (col < SizeColumns && line->ch != 0 && attr == line->attr)
-       {
-          font = Chars[line->ch] / 256;
-          if (strncmp(Fonts[font][0], "Courier", 7) != 0 ||
-             font != lastfont)
-           break;
+   /*
+    * Images...
+    */
 
-         col ++;
-         line ++;
-       }
-      }
+    if (cupsArrayCount(images))
+    {
+      if (banner->show || cupsArrayCount(banner->notices))
+        y -= 2 * line_height;
 
-      if (Directions[lastfont] > 0)
-        write_string(col - (line - start), row, line - start, start);
-      else
-      {
-       /*
-        * Do right-to-left text...
-       */
+      x = 0.5 * (print_width - images_width);
 
-       while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+      for (image = (cups_image_t *)cupsArrayFirst(images);
+           image;
+           image = (cups_image_t *)cupsArrayNext(images))
+      {
+        float          temp_width;     /* Width of this image */
+        int            depth,          /* Bytes per pixel */
+                       num_cols,       /* Number of columns */
+                       row,            /* Current row */
+                       num_rows,       /* Number of rows */
+                       out_length,     /* Length of data to write */
+                       out_offset;     /* Offset in line buffer */
+        unsigned char  *line;          /* Data for current row */
+
+
+        depth      = cupsImageGetDepth(image);
+       num_cols   = cupsImageGetWidth(image);
+        num_rows   = cupsImageGetHeight(image);
+       line       = malloc(depth * num_cols + 3);
+        temp_width = num_cols * images_height / num_rows;
+
+        printf("gsave %.1f %.1f translate %.3f %.3f scale\n", x, y,
+              temp_width / num_cols, images_height / num_rows);
+        x += temp_width;
+
+       switch (cupsImageGetColorSpace(image))
        {
-          if (Directions[Chars[line->ch] / 256] > 0 &&
-             !ispunct(line->ch & 255) && !isspace(line->ch & 255))
-           break;
-
-         col ++;
-         line ++;
+         default :
+         case CUPS_IMAGE_WHITE :
+             printf("/DeviceGray setcolorspace"
+                    "<<"
+                    "/ImageType 1"
+                    "/Width %d"
+                    "/Height %d"
+                    "/BitsPerComponent 8"
+                    "/Decode[0 1]\n",
+                    num_cols, num_rows);
+             break;
+
+         case CUPS_IMAGE_RGB :
+             printf("/DeviceRGB setcolorspace"
+                    "<<"
+                    "/ImageType 1"
+                    "/Width %d"
+                    "/Height %d"
+                    "/BitsPerComponent 8"
+                    "/Decode[0 1 0 1 0 1]\n",
+                    num_cols, num_rows);
+             break;
+
+         case CUPS_IMAGE_CMYK :
+             printf("/DeviceCMYK setcolorspace"
+                    "<<"
+                    "/ImageType 1"
+                    "/Width %d"
+                    "/Height %d"
+                    "/BitsPerComponent 8"
+                    "/Decode[0 1 0 1 0 1 0 1]\n",
+                    num_cols, num_rows);
+             break;
        }
 
-        for (i = 1; start < line; i ++, start ++)
-         if (!isspace(start->ch & 255))
-           write_string(col - i, row, 1, start);
-      }
-    }
-  }
-}
-
+        puts("/DataSource currentfile"
+            "/ASCII85Decode filter"
+            "/ImageMatrix[1 0 0 -1 0 1]>>image");
 
-/*
- * 'write_string()' - Write a string of text.
- */
-
-static void
-write_string(int     col,      /* I - Start column */
-             int     row,      /* I - Row */
-             int     len,      /* I - Number of characters */
-             lchar_t *s)       /* I - String to print */
-{
-  int          ch;             /* Current character */
-  float                x, y;           /* Position of text */
-  unsigned     attr;           /* Character attributes */
-
-
- /*
-  * Position the text and set the font...
-  */
-
-  if (Duplex && (NumPages & 1) == 0)
-  {
-    x = PageWidth - PageRight;
-    y = PageTop;
-  }
-  else
-  {
-    x = PageLeft;
-    y = PageTop;
-  }
-
-  x += (float)col * 72.0f / (float)CharsPerInch;
-  y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
-
-  attr = s->attr;
+       for (row = 0, out_offset = 0; row < num_rows; row ++)
+       {
+         cupsImageGetRow(image, 0, row, num_cols, line + out_offset);
 
-  if (attr & ATTR_RAISED)
-    y += 36.0 / (float)LinesPerInch;
-  else if (attr & ATTR_LOWERED)
-    y -= 36.0 / (float)LinesPerInch;
+         out_length = num_cols * depth + out_offset;
+         out_offset = out_length & 3;
 
-  if (x == (int)x)
-    printf("%.0f ", x);
-  else
-    printf("%.3f ", x);
+         ps_ascii85(line, out_length, row == (num_rows - 1));
 
-  if (y == (int)y)
-    printf("%.0f ", y);
-  else
-    printf("%.3f ", y);
+         if (out_offset > 0)
+           memcpy(line, line + out_length - out_offset, out_offset);
+       }
 
-  if (attr & ATTR_BOLD)
-    putchar('B');
-  else if (attr & ATTR_ITALIC)
-    putchar('I');
-  else
-    putchar('N');
+        puts("grestore");
 
-  if (attr & ATTR_UNDERLINE)
-    printf(" %.3f U", (float)len * 72.0 / (float)CharsPerInch);
+       if (i == num_pages)
+         cupsImageClose(image);
+      }
+    }
 
-  if (NumFonts > 1)
-  {
    /*
-    * Write a hex string...
+    * Header and footer...
     */
 
-    putchar('<');
+    x = 0.5 * print_width;
 
-    while (len > 0)
+    if (banner->header)
     {
-      printf("%04x", Chars[s->ch]);
+      printf("%.1f %.1f moveto", x, print_height - 2 * fontsize);
+      psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->header);
+    }
 
-      len --;
-      s ++;
+    if (banner->footer)
+    {
+      printf("%.1f %.1f moveto", x, fontsize);
+      psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->footer);
     }
 
-    putchar('>');
-  }
-  else
-  {
    /*
-    * Write a quoted string...
+    * Show the page...
     */
 
-    putchar('(');
-
-    while (len > 0)
-    {
-      ch = Chars[s->ch];
-
-      if (ch < 32 || ch > 126)
-      {
-       /*
-       * Quote 8-bit and control characters...
-       */
-
-       printf("\\%03o", ch);
-      }
-      else
-      {
-       /*
-       * Quote the parenthesis and backslash as needed...
-       */
-
-       if (ch == '(' || ch == ')' || ch == '\\')
-         putchar('\\');
-
-       putchar(ch);
-      }
-
-      len --;
-      s ++;
-    }
-
-    putchar(')');
+    puts("grestore");
+    puts("showpage");
   }
 
-  if (PrettyPrint)
-  {
-    if (attr & ATTR_RED)
-      puts("r");
-    else if (attr & ATTR_GREEN)
-      puts("g");
-    else if (attr & ATTR_BLUE)
-      puts("b");
-    else
-      puts("S");
-  }
-  else
-    puts("S");
+  return (num_pages);
 }
 
 
 /*
- * 'write_text()' - Write a text string, quoting/encoding as needed.
+ * 'write_epilogue()' - Write the PostScript file epilogue.
  */
 
 static void
-write_text(const char *s)      /* I - String to write */
+write_epilogue(int num_pages)          /* I - Number of pages */
 {
-  int                  ch;     /* Actual character value (UTF8) */
-  const unsigned char  *utf8;  /* UTF8 text */
-
-
-  if (NumFonts > 1)
-  {
-   /*
-    * 8/8 encoding...
-    */
-
-    putchar('<');
+  puts("%%Trailer");
+  printf("%%%%Pages: %d\n", num_pages);
+  puts("%%EOF");
+}
 
-    utf8 = (const unsigned char *)s;
 
-    while (*utf8)
-    {
-      if (*utf8 < 0xc0 || !UTF8)
-        ch = *utf8 ++;
-      else if ((*utf8 & 0xe0) == 0xc0)
-      {
-       /*
-        * Two byte character...
-       */
-
-        ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
-       utf8 += 2;
-      }
-      else
-      {
-       /*
-        * Three byte character...
-       */
+/*
+ * 'write_prolog()' - Write the PostScript file prolog with options.
+ */
 
-        ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
-            (utf8[2] & 0x3f);
-       utf8 += 3;
-      }
+ps_text_t *                            /* O - Fonts */
+write_prolog(const char *title,                /* I - Title of job */
+            const char *username)      /* I - Username */
+{
+  time_t       curtime;                /* Current time */
+  struct tm    *curtm;                 /* Current date */
+  char         curdate[255];           /* Current date (text format) */
+  ps_text_t    *fonts;                 /* Fonts */
 
-      printf("%04x", Chars[ch]);
-    }
 
-    putchar('>');
-  }
-  else
-  {
-   /*
-    * Standard 8-bit encoding...
-    */
+ /*
+  * Get the fonts we'll need...
+  */
 
-    putchar('(');
+  fonts = psTextInitialize();
 
-    while (*s)
-    {
-      if (*s < 32 || *s > 126)
-        printf("\\%03o", *s);
-      else
-      {
-       if (*s == '(' || *s == ')' || *s == '\\')
-         putchar('\\');
+ /*
+  * Output the DSC header...
+  */
 
-       putchar(*s);
-      }
+  curtime = time(NULL);
+  curtm   = localtime(&curtime);
+  strftime(curdate, sizeof(curdate), "%c", curtm);
 
-      s ++;
-    }
+  puts("%!PS-Adobe-3.0");
+  printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
+         PageRight, PageTop);
+  printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
+  puts("%%Creator: bannertops/" CUPS_SVERSION);
+  printf("%%%%CreationDate: %s\n", curdate);
+  puts("%%LanguageLevel: 2");
+  puts("%%DocumentData: Clean7Bit");
+  WriteTextComment("Title", title);
+  WriteTextComment("For", username);
+  printf("%%%%Pages: %d\n", Duplex ? 2 : 1);
+  psTextListFonts(fonts);
+  puts("%%EndComments");
+  puts("%%BeginProlog");
+  psTextEmbedFonts(fonts);
+  puts("%%EndProlog");
 
-    putchar(')');
-  }
+  return (fonts);
 }