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