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 */
SetCommonOptions(int num_options,cups_option_t * options,int change_size)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
UpdatePageVars(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
WriteCommon(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
WriteLabelProlog(const char * label,float bottom,float top,float width)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
WriteLabels(int orient)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
WriteTextComment(const char * name,const char * value)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