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