Home | History | Annotate | Download | only in filter
      1 /*
      2  * Common filter routines for CUPS.
      3  *
      4  * Copyright 2007-2014 by Apple Inc.
      5  * Copyright 1997-2006 by Easy Software Products.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include "common.h"
     21 #include <locale.h>
     22 
     23 
     24 /*
     25  * Globals...
     26  */
     27 
     28 int	Orientation = 0,		/* 0 = portrait, 1 = landscape, etc. */
     29 	Duplex = 0,			/* Duplexed? */
     30 	LanguageLevel = 1,		/* Language level of printer */
     31 	ColorDevice = 1;		/* Do color text? */
     32 float	PageLeft = 18.0f,		/* Left margin */
     33 	PageRight = 594.0f,		/* Right margin */
     34 	PageBottom = 36.0f,		/* Bottom margin */
     35 	PageTop = 756.0f,		/* Top margin */
     36 	PageWidth = 612.0f,		/* Total page width */
     37 	PageLength = 792.0f;		/* Total page length */
     38 
     39 
     40 /*
     41  * 'SetCommonOptions()' - Set common filter options for media size, etc.
     42  */
     43 
     44 ppd_file_t *				/* O - PPD file */
     45 SetCommonOptions(
     46     int           num_options,		/* I - Number of options */
     47     cups_option_t *options,		/* I - Options */
     48     int           change_size)		/* I - Change page size? */
     49 {
     50   ppd_file_t	*ppd;			/* PPD file */
     51   ppd_size_t	*pagesize;		/* Current page size */
     52   const char	*val;			/* Option value */
     53 
     54 
     55 #ifdef LC_TIME
     56   setlocale(LC_TIME, "");
     57 #endif /* LC_TIME */
     58 
     59   ppd = ppdOpenFile(getenv("PPD"));
     60 
     61   ppdMarkDefaults(ppd);
     62   cupsMarkOptions(ppd, num_options, options);
     63 
     64   if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
     65   {
     66     PageWidth  = pagesize->width;
     67     PageLength = pagesize->length;
     68     PageTop    = pagesize->top;
     69     PageBottom = pagesize->bottom;
     70     PageLeft   = pagesize->left;
     71     PageRight  = pagesize->right;
     72 
     73     fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
     74             PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop);
     75   }
     76 
     77   if (ppd != NULL)
     78   {
     79     ColorDevice   = ppd->color_device;
     80     LanguageLevel = ppd->language_level;
     81   }
     82 
     83   if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
     84   {
     85     if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 &&
     86         _cups_strcasecmp(val, "false") != 0)
     87     {
     88       if (ppd && ppd->landscape > 0)
     89         Orientation = 1;
     90       else
     91         Orientation = 3;
     92     }
     93   }
     94   else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL)
     95   {
     96    /*
     97     * Map IPP orientation values to 0 to 3:
     98     *
     99     *   3 = 0 degrees   = 0
    100     *   4 = 90 degrees  = 1
    101     *   5 = -90 degrees = 3
    102     *   6 = 180 degrees = 2
    103     */
    104 
    105     Orientation = atoi(val) - 3;
    106     if (Orientation >= 2)
    107       Orientation ^= 1;
    108   }
    109 
    110   if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
    111   {
    112     switch (Orientation & 3)
    113     {
    114       case 0 :
    115           PageLeft = (float)atof(val);
    116 	  break;
    117       case 1 :
    118           PageBottom = (float)atof(val);
    119 	  break;
    120       case 2 :
    121           PageRight = PageWidth - (float)atof(val);
    122 	  break;
    123       case 3 :
    124           PageTop = PageLength - (float)atof(val);
    125 	  break;
    126     }
    127   }
    128 
    129   if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
    130   {
    131     switch (Orientation & 3)
    132     {
    133       case 0 :
    134           PageRight = PageWidth - (float)atof(val);
    135 	  break;
    136       case 1 :
    137           PageTop = PageLength - (float)atof(val);
    138 	  break;
    139       case 2 :
    140           PageLeft = (float)atof(val);
    141 	  break;
    142       case 3 :
    143           PageBottom = (float)atof(val);
    144 	  break;
    145     }
    146   }
    147 
    148   if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
    149   {
    150     switch (Orientation & 3)
    151     {
    152       case 0 :
    153           PageBottom = (float)atof(val);
    154 	  break;
    155       case 1 :
    156           PageLeft = (float)atof(val);
    157 	  break;
    158       case 2 :
    159           PageTop = PageLength - (float)atof(val);
    160 	  break;
    161       case 3 :
    162           PageRight = PageWidth - (float)atof(val);
    163 	  break;
    164     }
    165   }
    166 
    167   if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
    168   {
    169     switch (Orientation & 3)
    170     {
    171       case 0 :
    172           PageTop = PageLength - (float)atof(val);
    173 	  break;
    174       case 1 :
    175           PageRight = PageWidth - (float)atof(val);
    176 	  break;
    177       case 2 :
    178           PageBottom = (float)atof(val);
    179 	  break;
    180       case 3 :
    181           PageLeft = (float)atof(val);
    182 	  break;
    183     }
    184   }
    185 
    186   if (change_size)
    187     UpdatePageVars();
    188 
    189   if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
    190       ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
    191       ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
    192       ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
    193       ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
    194       ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
    195       ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
    196       ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
    197     Duplex = 1;
    198 
    199   return (ppd);
    200 }
    201 
    202 
    203 /*
    204  * 'UpdatePageVars()' - Update the page variables for the orientation.
    205  */
    206 
    207 void
    208 UpdatePageVars(void)
    209 {
    210   float		temp;			/* Swapping variable */
    211 
    212 
    213   switch (Orientation & 3)
    214   {
    215     case 0 : /* Portait */
    216         break;
    217 
    218     case 1 : /* Landscape */
    219 	temp       = PageLeft;
    220 	PageLeft   = PageBottom;
    221 	PageBottom = temp;
    222 
    223 	temp       = PageRight;
    224 	PageRight  = PageTop;
    225 	PageTop    = temp;
    226 
    227 	temp       = PageWidth;
    228 	PageWidth  = PageLength;
    229 	PageLength = temp;
    230 	break;
    231 
    232     case 2 : /* Reverse Portrait */
    233 	temp       = PageWidth - PageLeft;
    234 	PageLeft   = PageWidth - PageRight;
    235 	PageRight  = temp;
    236 
    237 	temp       = PageLength - PageBottom;
    238 	PageBottom = PageLength - PageTop;
    239 	PageTop    = temp;
    240         break;
    241 
    242     case 3 : /* Reverse Landscape */
    243 	temp       = PageWidth - PageLeft;
    244 	PageLeft   = PageWidth - PageRight;
    245 	PageRight  = temp;
    246 
    247 	temp       = PageLength - PageBottom;
    248 	PageBottom = PageLength - PageTop;
    249 	PageTop    = temp;
    250 
    251 	temp       = PageLeft;
    252 	PageLeft   = PageBottom;
    253 	PageBottom = temp;
    254 
    255 	temp       = PageRight;
    256 	PageRight  = PageTop;
    257 	PageTop    = temp;
    258 
    259 	temp       = PageWidth;
    260 	PageWidth  = PageLength;
    261 	PageLength = temp;
    262 	break;
    263   }
    264 }
    265 
    266 
    267 /*
    268  * 'WriteCommon()' - Write common procedures...
    269  */
    270 
    271 void
    272 WriteCommon(void)
    273 {
    274   puts("% x y w h ESPrc - Clip to a rectangle.\n"
    275        "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
    276        "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
    277        "neg 0 rlineto closepath clip newpath}bind}ifelse put");
    278   puts("% x y w h ESPrf - Fill a rectangle.\n"
    279        "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
    280        "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
    281        "neg 0 rlineto closepath fill grestore}bind}ifelse put");
    282   puts("% x y w h ESPrs - Stroke a rectangle.\n"
    283        "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
    284        "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
    285        "neg 0 rlineto closepath stroke grestore}bind}ifelse put");
    286 }
    287 
    288 
    289 /*
    290  * 'WriteLabelProlog()' - Write the prolog with the classification
    291  *                        and page label.
    292  */
    293 
    294 void
    295 WriteLabelProlog(const char *label,	/* I - Page label */
    296 		 float      bottom,	/* I - Bottom position in points */
    297 		 float      top,	/* I - Top position in points */
    298 		 float      width)	/* I - Width in points */
    299 {
    300   const char	*classification;	/* CLASSIFICATION environment variable */
    301   const char	*ptr;			/* Temporary string pointer */
    302 
    303 
    304  /*
    305   * First get the current classification...
    306   */
    307 
    308   if ((classification = getenv("CLASSIFICATION")) == NULL)
    309     classification = "";
    310   if (strcmp(classification, "none") == 0)
    311     classification = "";
    312 
    313  /*
    314   * If there is nothing to show, bind an empty 'write labels' procedure
    315   * and return...
    316   */
    317 
    318   if (!classification[0] && (label == NULL || !label[0]))
    319   {
    320     puts("userdict/ESPwl{}bind put");
    321     return;
    322   }
    323 
    324  /*
    325   * Set the classification + page label string...
    326   */
    327 
    328   printf("userdict");
    329   if (strcmp(classification, "confidential") == 0)
    330     printf("/ESPpl(CONFIDENTIAL");
    331   else if (strcmp(classification, "classified") == 0)
    332     printf("/ESPpl(CLASSIFIED");
    333   else if (strcmp(classification, "secret") == 0)
    334     printf("/ESPpl(SECRET");
    335   else if (strcmp(classification, "topsecret") == 0)
    336     printf("/ESPpl(TOP SECRET");
    337   else if (strcmp(classification, "unclassified") == 0)
    338     printf("/ESPpl(UNCLASSIFIED");
    339   else
    340   {
    341     printf("/ESPpl(");
    342 
    343     for (ptr = classification; *ptr; ptr ++)
    344       if (*ptr < 32 || *ptr > 126)
    345         printf("\\%03o", *ptr);
    346       else if (*ptr == '_')
    347         putchar(' ');
    348       else
    349       {
    350 	if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
    351 	  putchar('\\');
    352 
    353 	putchar(*ptr);
    354       }
    355   }
    356 
    357   if (label)
    358   {
    359     if (classification[0])
    360       printf(" - ");
    361 
    362    /*
    363     * Quote the label string as needed...
    364     */
    365 
    366     for (ptr = label; *ptr; ptr ++)
    367       if (*ptr < 32 || *ptr > 126)
    368         printf("\\%03o", *ptr);
    369       else
    370       {
    371 	if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
    372 	  putchar('\\');
    373 
    374 	putchar(*ptr);
    375       }
    376   }
    377 
    378   puts(")put");
    379 
    380  /*
    381   * Then get a 14 point Helvetica-Bold font...
    382   */
    383 
    384   puts("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put");
    385 
    386  /*
    387   * Finally, the procedure to write the labels on the page...
    388   */
    389 
    390   puts("userdict/ESPwl{");
    391   puts("  ESPpf setfont");
    392   printf("  ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
    393          width * 0.5f);
    394   puts("  1 setgray");
    395   printf("  dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
    396   printf("  dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
    397   puts("  0 setgray");
    398   printf("  dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
    399   printf("  dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
    400   printf("  dup %.0f moveto ESPpl show\n", bottom + 2.0);
    401   printf("  %.0f moveto ESPpl show\n", top - 14.0);
    402   puts("pop");
    403   puts("}bind put");
    404 }
    405 
    406 
    407 /*
    408  * 'WriteLabels()' - Write the actual page labels.
    409  */
    410 
    411 void
    412 WriteLabels(int orient)	/* I - Orientation of the page */
    413 {
    414   float	width,		/* Width of page */
    415 	length;		/* Length of page */
    416 
    417 
    418   puts("gsave");
    419 
    420   if ((orient ^ Orientation) & 1)
    421   {
    422     width  = PageLength;
    423     length = PageWidth;
    424   }
    425   else
    426   {
    427     width  = PageWidth;
    428     length = PageLength;
    429   }
    430 
    431   switch (orient & 3)
    432   {
    433     case 1 : /* Landscape */
    434         printf("%.1f 0.0 translate 90 rotate\n", length);
    435         break;
    436     case 2 : /* Reverse Portrait */
    437         printf("%.1f %.1f translate 180 rotate\n", width, length);
    438         break;
    439     case 3 : /* Reverse Landscape */
    440         printf("0.0 %.1f translate -90 rotate\n", width);
    441         break;
    442   }
    443 
    444   puts("ESPwl");
    445   puts("grestore");
    446 }
    447 
    448 
    449 /*
    450  * 'WriteTextComment()' - Write a DSC text comment.
    451  */
    452 
    453 void
    454 WriteTextComment(const char *name,	/* I - Comment name ("Title", etc.) */
    455                  const char *value)	/* I - Comment value */
    456 {
    457   int	len;				/* Current line length */
    458 
    459 
    460  /*
    461   * DSC comments are of the form:
    462   *
    463   *   %%name: value
    464   *
    465   * The name and value must be limited to 7-bit ASCII for most printers,
    466   * so we escape all non-ASCII and ASCII control characters as described
    467   * in the Adobe Document Structuring Conventions specification.
    468   */
    469 
    470   printf("%%%%%s: (", name);
    471   len = 5 + (int)strlen(name);
    472 
    473   while (*value)
    474   {
    475     if (*value < ' ' || *value >= 127)
    476     {
    477      /*
    478       * Escape this character value...
    479       */
    480 
    481       if (len >= 251)			/* Keep line < 254 chars */
    482         break;
    483 
    484       printf("\\%03o", *value & 255);
    485       len += 4;
    486     }
    487     else if (*value == '\\')
    488     {
    489      /*
    490       * Escape the backslash...
    491       */
    492 
    493       if (len >= 253)			/* Keep line < 254 chars */
    494         break;
    495 
    496       putchar('\\');
    497       putchar('\\');
    498       len += 2;
    499     }
    500     else
    501     {
    502      /*
    503       * Put this character literally...
    504       */
    505 
    506       if (len >= 254)			/* Keep line < 254 chars */
    507         break;
    508 
    509       putchar(*value);
    510       len ++;
    511     }
    512 
    513     value ++;
    514   }
    515 
    516   puts(")");
    517 }
    518