/* * Common filter routines for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "LICENSE.txt" * which should have been included with this file. If this file is * missing or damaged, see the license at "http://www.cups.org/". * * This file is subject to the Apple OS-Developed Software exception. */ /* * Include necessary headers... */ #include "config.h" #ifdef WITH_LSPP #define _GNU_SOURCE #include #endif /* WITH_LSPP */ #include "common.h" #include /* * Globals... */ int Orientation = 0, /* 0 = portrait, 1 = landscape, etc. */ Duplex = 0, /* Duplexed? */ LanguageLevel = 1, /* Language level of printer */ ColorDevice = 1; /* Do color text? */ float PageLeft = 18.0f, /* Left margin */ PageRight = 594.0f, /* Right margin */ PageBottom = 36.0f, /* Bottom margin */ PageTop = 756.0f, /* Top margin */ PageWidth = 612.0f, /* Total page width */ PageLength = 792.0f; /* Total page length */ /* * 'SetCommonOptions()' - Set common filter options for media size, etc. */ ppd_file_t * /* O - PPD file */ SetCommonOptions( int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ int change_size) /* I - Change page size? */ { ppd_file_t *ppd; /* PPD file */ ppd_size_t *pagesize; /* Current page size */ const char *val; /* Option value */ #ifdef LC_TIME setlocale(LC_TIME, ""); #endif /* LC_TIME */ ppd = ppdOpenFile(getenv("PPD")); ppdMarkDefaults(ppd); cupsMarkOptions(ppd, num_options, options); if ((pagesize = ppdPageSize(ppd, NULL)) != NULL) { PageWidth = pagesize->width; PageLength = pagesize->length; PageTop = pagesize->top; PageBottom = pagesize->bottom; PageLeft = pagesize->left; PageRight = pagesize->right; fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n", PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop); } if (ppd != NULL) { ColorDevice = ppd->color_device; LanguageLevel = ppd->language_level; } if ((val = cupsGetOption("landscape", num_options, options)) != NULL) { if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 && _cups_strcasecmp(val, "false") != 0) { if (ppd && ppd->landscape > 0) Orientation = 1; else Orientation = 3; } } else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL) { /* * Map IPP orientation values to 0 to 3: * * 3 = 0 degrees = 0 * 4 = 90 degrees = 1 * 5 = -90 degrees = 3 * 6 = 180 degrees = 2 */ Orientation = atoi(val) - 3; if (Orientation >= 2) Orientation ^= 1; } if ((val = cupsGetOption("page-left", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageLeft = (float)atof(val); break; case 1 : PageBottom = (float)atof(val); break; case 2 : PageRight = PageWidth - (float)atof(val); break; case 3 : PageTop = PageLength - (float)atof(val); break; } } if ((val = cupsGetOption("page-right", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageRight = PageWidth - (float)atof(val); break; case 1 : PageTop = PageLength - (float)atof(val); break; case 2 : PageLeft = (float)atof(val); break; case 3 : PageBottom = (float)atof(val); break; } } if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageBottom = (float)atof(val); break; case 1 : PageLeft = (float)atof(val); break; case 2 : PageTop = PageLength - (float)atof(val); break; case 3 : PageRight = PageWidth - (float)atof(val); break; } } if ((val = cupsGetOption("page-top", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageTop = PageLength - (float)atof(val); break; case 1 : PageRight = PageWidth - (float)atof(val); break; case 2 : PageBottom = (float)atof(val); break; case 3 : PageLeft = (float)atof(val); break; } } if (change_size) UpdatePageVars(); if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") || ppdIsMarked(ppd, "Duplex", "DuplexTumble") || ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") || ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") || ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") || ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") || ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") || ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble")) Duplex = 1; return (ppd); } /* * 'UpdatePageVars()' - Update the page variables for the orientation. */ void UpdatePageVars(void) { float temp; /* Swapping variable */ switch (Orientation & 3) { case 0 : /* Portait */ break; case 1 : /* Landscape */ temp = PageLeft; PageLeft = PageBottom; PageBottom = temp; temp = PageRight; PageRight = PageTop; PageTop = temp; temp = PageWidth; PageWidth = PageLength; PageLength = temp; break; case 2 : /* Reverse Portrait */ temp = PageWidth - PageLeft; PageLeft = PageWidth - PageRight; PageRight = temp; temp = PageLength - PageBottom; PageBottom = PageLength - PageTop; PageTop = temp; break; case 3 : /* Reverse Landscape */ temp = PageWidth - PageLeft; PageLeft = PageWidth - PageRight; PageRight = temp; temp = PageLength - PageBottom; PageBottom = PageLength - PageTop; PageTop = temp; temp = PageLeft; PageLeft = PageBottom; PageBottom = temp; temp = PageRight; PageRight = PageTop; PageTop = temp; temp = PageWidth; PageWidth = PageLength; PageLength = temp; break; } } /* * 'WriteCommon()' - Write common procedures... */ void WriteCommon(void) { puts("% x y w h ESPrc - Clip to a rectangle.\n" "userdict/ESPrc/rectclip where{pop/rectclip load}\n" "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" "neg 0 rlineto closepath clip newpath}bind}ifelse put"); puts("% x y w h ESPrf - Fill a rectangle.\n" "userdict/ESPrf/rectfill where{pop/rectfill load}\n" "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" "neg 0 rlineto closepath fill grestore}bind}ifelse put"); puts("% x y w h ESPrs - Stroke a rectangle.\n" "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n" "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" "neg 0 rlineto closepath stroke grestore}bind}ifelse put"); } /* * 'WriteLabelProlog()' - Write the prolog with the classification * and page label. */ void WriteLabelProlog(const char *label, /* I - Page label */ float bottom, /* I - Bottom position in points */ float top, /* I - Top position in points */ float width) /* I - Width in points */ { const char *classification; /* CLASSIFICATION environment variable */ const char *ptr; /* Temporary string pointer */ #ifdef WITH_LSPP int i, /* counter */ n, /* counter */ lines, /* number of lines needed */ line_len, /* index into tmp_label */ label_len, /* length of the label in characters */ label_index, /* index into the label */ longest, /* length of the longest line */ longest_line, /* index to the longest line */ max_width; /* maximum width in characters */ char **wrapped_label; /* label with line breaks */ #endif /* WITH_LSPP */ /* * First get the current classification... */ if ((classification = getenv("CLASSIFICATION")) == NULL) classification = ""; if (strcmp(classification, "none") == 0) classification = ""; /* * If there is nothing to show, bind an empty 'write labels' procedure * and return... */ if (!classification[0] && (label == NULL || !label[0])) { puts("userdict/ESPwl{}bind put"); return; } #ifdef WITH_LSPP if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL) { /* * Based on the 12pt fixed width font below determine the max_width */ max_width = width / 8; longest_line = 0; longest = 0; classification += 5; // Skip the "LSPP:" label_len = strlen(classification); if (label_len > max_width) { lines = 1 + (int)(label_len / max_width); line_len = (int)(label_len / lines); wrapped_label = malloc(sizeof(*wrapped_label) * lines); label_index = i = n = 0; while (classification[label_index]) { if ((label_index + line_len) > label_len) break; switch (classification[label_index + line_len + i]) { case ':': case ',': case '-': i++; wrapped_label[n++] = strndup(&classification[label_index], (line_len + i)); label_index += line_len + i; i = 0; break; default: i++; break; } if ((i + line_len) == max_width) { wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i)); label_index = label_index + line_len + i; i = 0; } } wrapped_label[n] = strndup(&classification[label_index], label_len - label_index); } else { lines = 1; wrapped_label = malloc(sizeof(*wrapped_label)); wrapped_label[0] = (char*)classification; } for (n = 0; n < lines; n++ ) { printf("userdict/ESPp%c(", ('a' + n)); for (ptr = wrapped_label[n], i = 0; *ptr; ptr ++, i++) if (*ptr < 32 || *ptr > 126) printf("\\%03o", *ptr); else { if (*ptr == '(' || *ptr == ')' || *ptr == '\\') putchar('\\'); printf("%c", *ptr); } if (i > longest) { longest = i; longest_line = n; } printf(")put\n"); } /* * For LSPP use a fixed width font so that line wrapping can be calculated */ puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put"); /* * Finally, the procedure to write the labels on the page... */ printf("userdict/ESPwl{\n" " ESPlf setfont\n"); printf(" ESPp%c stringwidth pop dup 12 add exch -0.5 mul %.0f add\n ", 'a' + longest_line, width * 0.5f); for (n = 1; n < lines; n++) printf(" dup"); printf("\n 1 setgray\n"); printf(" dup 6 sub %.0f %d index %.0f ESPrf\n", (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines)); printf(" dup 6 sub %.0f %d index %.0f ESPrf\n", (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines)); printf(" 0 setgray\n"); printf(" dup 6 sub %.0f %d index %.0f ESPrs\n", (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines)); printf(" dup 6 sub %.0f %d index %.0f ESPrs\n", (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines)); for (n = 0; n < lines; n ++) { printf(" dup %.0f moveto ESPp%c show\n", bottom + 6.0 + ((lines - (n+1)) * 16.0), 'a' + n); printf(" %.0f moveto ESPp%c show\n", top + 2.0 - ((n + 1) * 16.0), 'a' + n); } printf(" pop\n" "}bind put\n"); /* * Do some clean up at the end of the LSPP special case */ free(wrapped_label); } else { #endif /* !WITH_LSPP */ /* * Set the classification + page label string... */ printf("userdict"); if (strcmp(classification, "confidential") == 0) printf("/ESPpl(CONFIDENTIAL"); else if (strcmp(classification, "classified") == 0) printf("/ESPpl(CLASSIFIED"); else if (strcmp(classification, "secret") == 0) printf("/ESPpl(SECRET"); else if (strcmp(classification, "topsecret") == 0) printf("/ESPpl(TOP SECRET"); else if (strcmp(classification, "unclassified") == 0) printf("/ESPpl(UNCLASSIFIED"); else { printf("/ESPpl("); for (ptr = classification; *ptr; ptr ++) if (*ptr < 32 || *ptr > 126) printf("\\%03o", *ptr); else if (*ptr == '_') putchar(' '); else { if (*ptr == '(' || *ptr == ')' || *ptr == '\\') putchar('\\'); putchar(*ptr); } } if (label) { if (classification[0]) printf(" - "); /* * Quote the label string as needed... */ for (ptr = label; *ptr; ptr ++) if (*ptr < 32 || *ptr > 126) printf("\\%03o", *ptr); else { if (*ptr == '(' || *ptr == ')' || *ptr == '\\') putchar('\\'); putchar(*ptr); } } puts(")put"); /* * Then get a 14 point Helvetica-Bold font... */ puts("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put"); /* * Finally, the procedure to write the labels on the page... */ puts("userdict/ESPwl{"); puts(" ESPpf setfont"); printf(" ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n", width * 0.5f); puts(" 1 setgray"); printf(" dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0); printf(" dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0); puts(" 0 setgray"); printf(" dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0); printf(" dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0); printf(" dup %.0f moveto ESPpl show\n", bottom + 2.0); printf(" %.0f moveto ESPpl show\n", top - 14.0); puts("pop"); puts("}bind put"); } #ifdef WITH_LSPP } #endif /* WITH_LSPP */ /* * 'WriteLabels()' - Write the actual page labels. */ void WriteLabels(int orient) /* I - Orientation of the page */ { float width, /* Width of page */ length; /* Length of page */ puts("gsave"); if ((orient ^ Orientation) & 1) { width = PageLength; length = PageWidth; } else { width = PageWidth; length = PageLength; } switch (orient & 3) { case 1 : /* Landscape */ printf("%.1f 0.0 translate 90 rotate\n", length); break; case 2 : /* Reverse Portrait */ printf("%.1f %.1f translate 180 rotate\n", width, length); break; case 3 : /* Reverse Landscape */ printf("0.0 %.1f translate -90 rotate\n", width); break; } puts("ESPwl"); puts("grestore"); } /* * 'WriteTextComment()' - Write a DSC text comment. */ void WriteTextComment(const char *name, /* I - Comment name ("Title", etc.) */ const char *value) /* I - Comment value */ { int len; /* Current line length */ /* * DSC comments are of the form: * * %%name: value * * The name and value must be limited to 7-bit ASCII for most printers, * so we escape all non-ASCII and ASCII control characters as described * in the Adobe Document Structuring Conventions specification. */ printf("%%%%%s: (", name); len = 5 + (int)strlen(name); while (*value) { if (*value < ' ' || *value >= 127) { /* * Escape this character value... */ if (len >= 251) /* Keep line < 254 chars */ break; printf("\\%03o", *value & 255); len += 4; } else if (*value == '\\') { /* * Escape the backslash... */ if (len >= 253) /* Keep line < 254 chars */ break; putchar('\\'); putchar('\\'); len += 2; } else { /* * Put this character literally... */ if (len >= 254) /* Keep line < 254 chars */ break; putchar(*value); len ++; } value ++; } puts(")"); }