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