mirror of https://gitee.com/openkylin/cups.git
503 lines
17 KiB
C
503 lines
17 KiB
C
/*
|
||
* CUPS raster to PWG raster format filter for CUPS.
|
||
*
|
||
* Copyright © 2011, 2014-2017 Apple Inc.
|
||
*
|
||
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||
* information.
|
||
*/
|
||
|
||
/*
|
||
* Include necessary headers...
|
||
*/
|
||
|
||
#include <cups/cups-private.h>
|
||
#include <cups/ppd-private.h>
|
||
#include <cups/raster.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
|
||
|
||
/*
|
||
* 'main()' - Main entry for filter.
|
||
*/
|
||
|
||
int /* O - Exit status */
|
||
main(int argc, /* I - Number of command-line args */
|
||
char *argv[]) /* I - Command-line arguments */
|
||
{
|
||
const char *final_content_type;
|
||
/* FINAL_CONTENT_TYPE env var */
|
||
int fd; /* Raster file */
|
||
cups_raster_t *inras, /* Input raster stream */
|
||
*outras; /* Output raster stream */
|
||
cups_page_header2_t inheader, /* Input raster page header */
|
||
outheader; /* Output raster page header */
|
||
unsigned y; /* Current line */
|
||
unsigned char *line; /* Line buffer */
|
||
unsigned page = 0, /* Current page */
|
||
page_width, /* Actual page width */
|
||
page_height, /* Actual page height */
|
||
page_top, /* Top margin */
|
||
page_bottom, /* Bottom margin */
|
||
page_left, /* Left margin */
|
||
page_right, /* Right margin */
|
||
linesize, /* Bytes per line */
|
||
lineoffset; /* Offset into line */
|
||
int tmp;
|
||
unsigned char white; /* White pixel */
|
||
ppd_file_t *ppd; /* PPD file */
|
||
ppd_attr_t *back; /* cupsBackSide attribute */
|
||
_ppd_cache_t *cache; /* PPD cache */
|
||
pwg_size_t *pwg_size; /* PWG media size */
|
||
pwg_media_t *pwg_media; /* PWG media name */
|
||
int num_options; /* Number of options */
|
||
cups_option_t *options = NULL;/* Options */
|
||
const char *val; /* Option value */
|
||
|
||
|
||
if (argc != 6 && argc != 7)
|
||
{
|
||
puts("Usage: rastertopwg job user title copies options [filename]");
|
||
return (1);
|
||
}
|
||
else if (argc == 7)
|
||
{
|
||
if ((fd = open(argv[6], O_RDONLY)) < 0)
|
||
{
|
||
perror("ERROR: Unable to open print file");
|
||
return (1);
|
||
}
|
||
}
|
||
else
|
||
fd = 0;
|
||
|
||
if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
|
||
final_content_type = "image/pwg-raster";
|
||
|
||
inras = cupsRasterOpen(fd, CUPS_RASTER_READ);
|
||
outras = cupsRasterOpen(1, !strcmp(final_content_type, "image/pwg-raster") ? CUPS_RASTER_WRITE_PWG : CUPS_RASTER_WRITE_APPLE);
|
||
|
||
ppd = ppdOpenFile(getenv("PPD"));
|
||
back = ppdFindAttr(ppd, "cupsBackSide", NULL);
|
||
|
||
num_options = cupsParseOptions(argv[5], 0, &options);
|
||
|
||
ppdMarkDefaults(ppd);
|
||
cupsMarkOptions(ppd, num_options, options);
|
||
|
||
cache = ppd ? ppd->cache : NULL;
|
||
|
||
while (cupsRasterReadHeader2(inras, &inheader))
|
||
{
|
||
/*
|
||
* Show page device dictionary...
|
||
*/
|
||
|
||
fprintf(stderr, "DEBUG: Duplex = %d\n", inheader.Duplex);
|
||
fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", inheader.HWResolution[0], inheader.HWResolution[1]);
|
||
fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", inheader.ImagingBoundingBox[0], inheader.ImagingBoundingBox[1], inheader.ImagingBoundingBox[2], inheader.ImagingBoundingBox[3]);
|
||
fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", inheader.Margins[0], inheader.Margins[1]);
|
||
fprintf(stderr, "DEBUG: ManualFeed = %d\n", inheader.ManualFeed);
|
||
fprintf(stderr, "DEBUG: MediaPosition = %d\n", inheader.MediaPosition);
|
||
fprintf(stderr, "DEBUG: NumCopies = %d\n", inheader.NumCopies);
|
||
fprintf(stderr, "DEBUG: Orientation = %d\n", inheader.Orientation);
|
||
fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", inheader.PageSize[0], inheader.PageSize[1]);
|
||
fprintf(stderr, "DEBUG: cupsWidth = %d\n", inheader.cupsWidth);
|
||
fprintf(stderr, "DEBUG: cupsHeight = %d\n", inheader.cupsHeight);
|
||
fprintf(stderr, "DEBUG: cupsMediaType = %d\n", inheader.cupsMediaType);
|
||
fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", inheader.cupsBitsPerColor);
|
||
fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", inheader.cupsBitsPerPixel);
|
||
fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", inheader.cupsBytesPerLine);
|
||
fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", inheader.cupsColorOrder);
|
||
fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", inheader.cupsColorSpace);
|
||
fprintf(stderr, "DEBUG: cupsCompression = %d\n", inheader.cupsCompression);
|
||
|
||
/*
|
||
* Compute the real raster size...
|
||
*/
|
||
|
||
page ++;
|
||
|
||
fprintf(stderr, "PAGE: %d %d\n", page, inheader.NumCopies);
|
||
|
||
page_width = (unsigned)(inheader.cupsPageSize[0] * inheader.HWResolution[0] / 72.0);
|
||
if (page_width < inheader.cupsWidth &&
|
||
page_width >= inheader.cupsWidth - 1)
|
||
page_width = (unsigned)inheader.cupsWidth;
|
||
page_height = (unsigned)(inheader.cupsPageSize[1] * inheader.HWResolution[1] / 72.0);
|
||
if (page_height < inheader.cupsHeight &&
|
||
page_height >= inheader.cupsHeight - 1)
|
||
page_height = (unsigned)inheader.cupsHeight;
|
||
page_left = (unsigned)(inheader.cupsImagingBBox[0] * inheader.HWResolution[0] / 72.0);
|
||
page_bottom = (unsigned)(inheader.cupsImagingBBox[1] * inheader.HWResolution[1] / 72.0);
|
||
tmp = (int)(page_height - page_bottom - inheader.cupsHeight);
|
||
if (tmp < 0 && tmp >= -1) /* Rounding error */
|
||
page_top = 0;
|
||
else
|
||
page_top = (unsigned)tmp;
|
||
tmp = (int)(page_width - page_left - inheader.cupsWidth);
|
||
if (tmp < 0 && tmp >= -1) /* Rounding error */
|
||
page_right = 0;
|
||
else
|
||
page_right = (unsigned)tmp;
|
||
linesize = (page_width * inheader.cupsBitsPerPixel + 7) / 8;
|
||
lineoffset = page_left * inheader.cupsBitsPerPixel / 8; /* Round down */
|
||
|
||
fprintf(stderr, "DEBUG: In pixels: Width: %u Height: %u Left: %u Right: %u Top: %u Bottom: %u\n", page_width, page_height, page_left, page_right, page_top, page_bottom);
|
||
if (page_left > page_width || page_top > page_height || page_bottom > page_height || page_right > page_width)
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
|
||
fprintf(stderr, "DEBUG: Bad bottom/left/top margin on page %d.\n", page);
|
||
return (1);
|
||
}
|
||
|
||
if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
|
||
fprintf(stderr, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n",
|
||
inheader.cupsColorOrder, page);
|
||
return (1);
|
||
}
|
||
|
||
if (inheader.cupsBitsPerPixel != 1 &&
|
||
inheader.cupsBitsPerColor != 8 && inheader.cupsBitsPerColor != 16)
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
|
||
fprintf(stderr, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n",
|
||
inheader.cupsBitsPerColor, page);
|
||
return (1);
|
||
}
|
||
|
||
switch (inheader.cupsColorSpace)
|
||
{
|
||
case CUPS_CSPACE_W :
|
||
case CUPS_CSPACE_RGB :
|
||
case CUPS_CSPACE_SW :
|
||
case CUPS_CSPACE_SRGB :
|
||
case CUPS_CSPACE_ADOBERGB :
|
||
white = 255;
|
||
break;
|
||
|
||
case CUPS_CSPACE_K :
|
||
case CUPS_CSPACE_CMYK :
|
||
case CUPS_CSPACE_DEVICE1 :
|
||
case CUPS_CSPACE_DEVICE2 :
|
||
case CUPS_CSPACE_DEVICE3 :
|
||
case CUPS_CSPACE_DEVICE4 :
|
||
case CUPS_CSPACE_DEVICE5 :
|
||
case CUPS_CSPACE_DEVICE6 :
|
||
case CUPS_CSPACE_DEVICE7 :
|
||
case CUPS_CSPACE_DEVICE8 :
|
||
case CUPS_CSPACE_DEVICE9 :
|
||
case CUPS_CSPACE_DEVICEA :
|
||
case CUPS_CSPACE_DEVICEB :
|
||
case CUPS_CSPACE_DEVICEC :
|
||
case CUPS_CSPACE_DEVICED :
|
||
case CUPS_CSPACE_DEVICEE :
|
||
case CUPS_CSPACE_DEVICEF :
|
||
white = 0;
|
||
break;
|
||
|
||
default :
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
|
||
fprintf(stderr, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n",
|
||
inheader.cupsColorSpace, page);
|
||
return (1);
|
||
}
|
||
|
||
memcpy(&outheader, &inheader, sizeof(outheader));
|
||
outheader.cupsWidth = page_width;
|
||
outheader.cupsHeight = page_height;
|
||
outheader.cupsBytesPerLine = linesize;
|
||
|
||
outheader.cupsInteger[14] = 0; /* VendorIdentifier */
|
||
outheader.cupsInteger[15] = 0; /* VendorLength */
|
||
|
||
if ((val = cupsGetOption("print-content-optimize", num_options,
|
||
options)) != NULL)
|
||
{
|
||
if (!strcmp(val, "automatic"))
|
||
strlcpy(outheader.OutputType, "Automatic",
|
||
sizeof(outheader.OutputType));
|
||
else if (!strcmp(val, "graphics"))
|
||
strlcpy(outheader.OutputType, "Graphics", sizeof(outheader.OutputType));
|
||
else if (!strcmp(val, "photo"))
|
||
strlcpy(outheader.OutputType, "Photo", sizeof(outheader.OutputType));
|
||
else if (!strcmp(val, "text"))
|
||
strlcpy(outheader.OutputType, "Text", sizeof(outheader.OutputType));
|
||
else if (!strcmp(val, "text-and-graphics"))
|
||
strlcpy(outheader.OutputType, "TextAndGraphics",
|
||
sizeof(outheader.OutputType));
|
||
else
|
||
{
|
||
fputs("DEBUG: Unsupported print-content-optimize value.\n", stderr);
|
||
outheader.OutputType[0] = '\0';
|
||
}
|
||
}
|
||
|
||
if ((val = cupsGetOption("print-quality", num_options, options)) != NULL)
|
||
{
|
||
unsigned quality = (unsigned)atoi(val); /* print-quality value */
|
||
|
||
if (quality >= IPP_QUALITY_DRAFT && quality <= IPP_QUALITY_HIGH)
|
||
outheader.cupsInteger[8] = quality;
|
||
else
|
||
{
|
||
fprintf(stderr, "DEBUG: Unsupported print-quality %d.\n", quality);
|
||
outheader.cupsInteger[8] = 0;
|
||
}
|
||
}
|
||
|
||
if ((val = cupsGetOption("print-rendering-intent", num_options,
|
||
options)) != NULL)
|
||
{
|
||
if (!strcmp(val, "absolute"))
|
||
strlcpy(outheader.cupsRenderingIntent, "Absolute",
|
||
sizeof(outheader.cupsRenderingIntent));
|
||
else if (!strcmp(val, "automatic"))
|
||
strlcpy(outheader.cupsRenderingIntent, "Automatic",
|
||
sizeof(outheader.cupsRenderingIntent));
|
||
else if (!strcmp(val, "perceptual"))
|
||
strlcpy(outheader.cupsRenderingIntent, "Perceptual",
|
||
sizeof(outheader.cupsRenderingIntent));
|
||
else if (!strcmp(val, "relative"))
|
||
strlcpy(outheader.cupsRenderingIntent, "Relative",
|
||
sizeof(outheader.cupsRenderingIntent));
|
||
else if (!strcmp(val, "relative-bpc"))
|
||
strlcpy(outheader.cupsRenderingIntent, "RelativeBpc",
|
||
sizeof(outheader.cupsRenderingIntent));
|
||
else if (!strcmp(val, "saturation"))
|
||
strlcpy(outheader.cupsRenderingIntent, "Saturation",
|
||
sizeof(outheader.cupsRenderingIntent));
|
||
else
|
||
{
|
||
fputs("DEBUG: Unsupported print-rendering-intent value.\n", stderr);
|
||
outheader.cupsRenderingIntent[0] = '\0';
|
||
}
|
||
}
|
||
|
||
if (inheader.cupsPageSizeName[0] && (pwg_size = _ppdCacheGetSize(cache, inheader.cupsPageSizeName)) != NULL && pwg_size->map.pwg)
|
||
{
|
||
strlcpy(outheader.cupsPageSizeName, pwg_size->map.pwg,
|
||
sizeof(outheader.cupsPageSizeName));
|
||
}
|
||
else
|
||
{
|
||
pwg_media = pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] / 72.0),
|
||
(int)(2540.0 * inheader.cupsPageSize[1] / 72.0));
|
||
|
||
if (pwg_media)
|
||
strlcpy(outheader.cupsPageSizeName, pwg_media->pwg,
|
||
sizeof(outheader.cupsPageSizeName));
|
||
else
|
||
{
|
||
fprintf(stderr, "DEBUG: Unsupported PageSize %.2fx%.2f.\n",
|
||
inheader.cupsPageSize[0], inheader.cupsPageSize[1]);
|
||
outheader.cupsPageSizeName[0] = '\0';
|
||
}
|
||
}
|
||
|
||
if (inheader.Duplex && !(page & 1) &&
|
||
back && _cups_strcasecmp(back->value, "Normal"))
|
||
{
|
||
if (_cups_strcasecmp(back->value, "Flipped"))
|
||
{
|
||
if (inheader.Tumble)
|
||
{
|
||
outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = 1; /* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_right;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_top;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_width - page_left;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_bottom;
|
||
/* ImageBoxBottom */
|
||
}
|
||
else
|
||
{
|
||
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = ~0U;/* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_left;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_bottom;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_top;
|
||
/* ImageBoxBottom */
|
||
}
|
||
}
|
||
else if (_cups_strcasecmp(back->value, "ManualTumble"))
|
||
{
|
||
if (inheader.Tumble)
|
||
{
|
||
outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = ~0U;/* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_width - page_left -
|
||
inheader.cupsWidth;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_bottom;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_width - page_left;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_top;
|
||
/* ImageBoxBottom */
|
||
}
|
||
else
|
||
{
|
||
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = 1; /* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_left;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_top;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_bottom;
|
||
/* ImageBoxBottom */
|
||
}
|
||
}
|
||
else if (_cups_strcasecmp(back->value, "Rotated"))
|
||
{
|
||
if (inheader.Tumble)
|
||
{
|
||
outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = ~0U;/* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_right;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_bottom;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_width - page_left;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_top;
|
||
/* ImageBoxBottom */
|
||
}
|
||
else
|
||
{
|
||
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = 1; /* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_left;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_top;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_bottom;
|
||
/* ImageBoxBottom */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Unsupported value...
|
||
*/
|
||
|
||
fputs("DEBUG: Unsupported cupsBackSide value.\n", stderr);
|
||
|
||
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = 1; /* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_left;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_top;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_bottom;
|
||
/* ImageBoxBottom */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
|
||
outheader.cupsInteger[2] = 1; /* FeedTransform */
|
||
|
||
outheader.cupsInteger[3] = page_left;
|
||
/* ImageBoxLeft */
|
||
outheader.cupsInteger[4] = page_top;
|
||
/* ImageBoxTop */
|
||
outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
|
||
/* ImageBoxRight */
|
||
outheader.cupsInteger[6] = page_height - page_bottom;
|
||
/* ImageBoxBottom */
|
||
}
|
||
|
||
if (!cupsRasterWriteHeader2(outras, &outheader))
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
|
||
fprintf(stderr, "DEBUG: Unable to write header for page %d.\n", page);
|
||
return (1);
|
||
}
|
||
|
||
/*
|
||
* Copy raster data...
|
||
*/
|
||
|
||
if (linesize < inheader.cupsBytesPerLine)
|
||
linesize = inheader.cupsBytesPerLine;
|
||
|
||
if ((lineoffset + inheader.cupsBytesPerLine) > linesize)
|
||
lineoffset = linesize - inheader.cupsBytesPerLine;
|
||
|
||
line = malloc(linesize);
|
||
|
||
memset(line, white, linesize);
|
||
for (y = page_top; y > 0; y --)
|
||
if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
|
||
fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
|
||
page_top - y + 1, page);
|
||
return (1);
|
||
}
|
||
|
||
for (y = inheader.cupsHeight; y > 0; y --)
|
||
{
|
||
if (cupsRasterReadPixels(inras, line + lineoffset, inheader.cupsBytesPerLine) != inheader.cupsBytesPerLine)
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Error reading raster data."));
|
||
fprintf(stderr, "DEBUG: Unable to read line %d for page %d.\n",
|
||
inheader.cupsHeight - y + page_top + 1, page);
|
||
return (1);
|
||
}
|
||
|
||
if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
|
||
fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
|
||
inheader.cupsHeight - y + page_top + 1, page);
|
||
return (1);
|
||
}
|
||
}
|
||
|
||
memset(line, white, linesize);
|
||
for (y = page_bottom; y > 0; y --)
|
||
if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
|
||
{
|
||
_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
|
||
fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
|
||
page_bottom - y + page_top + inheader.cupsHeight + 1, page);
|
||
return (1);
|
||
}
|
||
|
||
free(line);
|
||
}
|
||
|
||
cupsRasterClose(inras);
|
||
if (fd)
|
||
close(fd);
|
||
|
||
cupsRasterClose(outras);
|
||
|
||
return (0);
|
||
}
|