mirror of https://gitee.com/openkylin/cups.git
512 lines
11 KiB
C
512 lines
11 KiB
C
|
/*
|
||
|
* Common filter routines for CUPS.
|
||
|
*
|
||
|
* Copyright 2007-2014 by Apple Inc.
|
||
|
* Copyright 1997-2006 by Easy Software Products.
|
||
|
*
|
||
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more information.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Include necessary headers...
|
||
|
*/
|
||
|
|
||
|
#include "common.h"
|
||
|
#include <locale.h>
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 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 : /* Portrait */
|
||
|
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 */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* First get the current classification...
|
||
|
*/
|
||
|
|
||
|
if ((classification = getenv("CLASSIFICATION")) == NULL)
|
||
|
classification = "";
|
||
|
else 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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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");
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* '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(")");
|
||
|
}
|