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 28int Orientation = 0, /* 0 = portrait, 1 = landscape, etc. */ 29 Duplex = 0, /* Duplexed? */ 30 LanguageLevel = 1, /* Language level of printer */ 31 ColorDevice = 1; /* Do color text? */ 32float 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 44ppd_file_t * /* O - PPD file */ 45SetCommonOptions( 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 207void 208UpdatePageVars(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 271void 272WriteCommon(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 294void 295WriteLabelProlog(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 411void 412WriteLabels(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 453void 454WriteTextComment(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