in cups/raster-interpret.c [85:496]
static int setpagedevice(_cups_ps_stack_t *st,
cups_page_header2_t *h,
int *preferred_bits);
#ifdef DEBUG
static void DEBUG_object(const char *prefix, _cups_ps_obj_t *obj);
static void DEBUG_stack(const char *prefix, _cups_ps_stack_t *st);
#endif /* DEBUG */
/*
* '_cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
*
* This function is used by raster image processing (RIP) filters like
* cgpdftoraster and imagetoraster when writing CUPS raster data for a page.
* It is not used by raster printer driver filters which only read CUPS
* raster data.
*
*
* @code cupsRasterInterpretPPD@ does not mark the options in the PPD using
* the "num_options" and "options" arguments. Instead, mark the options with
* @code cupsMarkOptions@ and @code ppdMarkOption@ prior to calling it -
* this allows for per-page options without manipulating the options array.
*
* The "func" argument specifies an optional callback function that is
* called prior to the computation of the final raster data. The function
* can make changes to the @link cups_page_header2_t@ data as needed to use a
* supported raster format and then returns 0 on success and -1 if the
* requested attributes cannot be supported.
*
*
* @code cupsRasterInterpretPPD@ supports a subset of the PostScript language.
* Currently only the @code [@, @code ]@, @code <<@, @code >>@, @code {@,
* @code }@, @code cleartomark@, @code copy@, @code dup@, @code index@,
* @code pop@, @code roll@, @code setpagedevice@, and @code stopped@ operators
* are supported.
*
* @since CUPS 1.2/macOS 10.5@
*/
int /* O - 0 on success, -1 on failure */
_cupsRasterInterpretPPD(
cups_page_header2_t *h, /* O - Page header to create */
ppd_file_t *ppd, /* I - PPD file */
int num_options, /* I - Number of options */
cups_option_t *options, /* I - Options */
cups_interpret_cb_t func) /* I - Optional page header callback (@code NULL@ for none) */
{
int status; /* Cummulative status */
char *code; /* Code to run */
const char *val; /* Option value */
ppd_size_t *size; /* Current size */
float left, /* Left position */
bottom, /* Bottom position */
right, /* Right position */
top, /* Top position */
temp1, temp2; /* Temporary variables for swapping */
int preferred_bits; /* Preferred bits per color */
/*
* Range check input...
*/
_cupsRasterClearError();
if (!h)
{
_cupsRasterAddError("Page header cannot be NULL!\n");
return (-1);
}
/*
* Reset the page header to the defaults...
*/
memset(h, 0, sizeof(cups_page_header2_t));
h->NumCopies = 1;
h->PageSize[0] = 612;
h->PageSize[1] = 792;
h->HWResolution[0] = 100;
h->HWResolution[1] = 100;
h->cupsBitsPerColor = 1;
h->cupsColorOrder = CUPS_ORDER_CHUNKED;
h->cupsColorSpace = CUPS_CSPACE_K;
h->cupsBorderlessScalingFactor = 1.0f;
h->cupsPageSize[0] = 612.0f;
h->cupsPageSize[1] = 792.0f;
h->cupsImagingBBox[0] = 0.0f;
h->cupsImagingBBox[1] = 0.0f;
h->cupsImagingBBox[2] = 612.0f;
h->cupsImagingBBox[3] = 792.0f;
strlcpy(h->cupsPageSizeName, "Letter", sizeof(h->cupsPageSizeName));
#ifdef __APPLE__
/*
* cupsInteger0 is also used for the total page count on macOS; set an
* uncommon default value so we can tell if the driver is using cupsInteger0.
*/
h->cupsInteger[0] = 0x80000000;
#endif /* __APPLE__ */
/*
* Apply patches and options to the page header...
*/
status = 0;
preferred_bits = 0;
if (ppd)
{
/*
* Apply any patch code (used to override the defaults...)
*/
if (ppd->patches)
status |= _cupsRasterExecPS(h, &preferred_bits, ppd->patches);
/*
* Then apply printer options in the proper order...
*/
if ((code = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
{
status |= _cupsRasterExecPS(h, &preferred_bits, code);
free(code);
}
if ((code = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
{
status |= _cupsRasterExecPS(h, &preferred_bits, code);
free(code);
}
if ((code = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
{
status |= _cupsRasterExecPS(h, &preferred_bits, code);
free(code);
}
if ((code = ppdEmitString(ppd, PPD_ORDER_PAGE, 0.0)) != NULL)
{
status |= _cupsRasterExecPS(h, &preferred_bits, code);
free(code);
}
}
/*
* Allow option override for page scaling...
*/
if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options,
options)) != NULL)
{
double sc = atof(val); /* Scale factor */
if (sc >= 0.1 && sc <= 2.0)
h->cupsBorderlessScalingFactor = (float)sc;
}
/*
* Get the margins for the current size...
*/
if ((size = ppdPageSize(ppd, NULL)) != NULL)
{
/*
* Use the margins from the PPD file...
*/
left = size->left;
bottom = size->bottom;
right = size->right;
top = size->top;
strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName));
h->cupsPageSize[0] = size->width;
h->cupsPageSize[1] = size->length;
}
else
{
/*
* Use the default margins...
*/
left = 0.0f;
bottom = 0.0f;
right = 612.0f;
top = 792.0f;
}
/*
* Handle orientation...
*/
switch (h->Orientation)
{
case CUPS_ORIENT_0 :
default :
/* Do nothing */
break;
case CUPS_ORIENT_90 :
temp1 = h->cupsPageSize[0];
h->cupsPageSize[0] = h->cupsPageSize[1];
h->cupsPageSize[1] = temp1;
temp1 = left;
temp2 = right;
left = h->cupsPageSize[0] - top;
right = h->cupsPageSize[0] - bottom;
bottom = h->cupsPageSize[1] - temp1;
top = h->cupsPageSize[1] - temp2;
break;
case CUPS_ORIENT_180 :
temp1 = left;
temp2 = bottom;
left = h->cupsPageSize[0] - right;
right = h->cupsPageSize[0] - temp1;
bottom = h->cupsPageSize[1] - top;
top = h->cupsPageSize[1] - temp2;
break;
case CUPS_ORIENT_270 :
temp1 = h->cupsPageSize[0];
h->cupsPageSize[0] = h->cupsPageSize[1];
h->cupsPageSize[1] = temp1;
temp1 = left;
temp2 = right;
left = bottom;
right = top;
bottom = h->cupsPageSize[1] - temp2;
top = h->cupsPageSize[1] - temp1;
break;
}
if (left > right)
{
temp1 = left;
left = right;
right = temp1;
}
if (bottom > top)
{
temp1 = bottom;
bottom = top;
top = temp1;
}
h->PageSize[0] = (unsigned)(h->cupsPageSize[0] *
h->cupsBorderlessScalingFactor);
h->PageSize[1] = (unsigned)(h->cupsPageSize[1] *
h->cupsBorderlessScalingFactor);
h->Margins[0] = (unsigned)(left *
h->cupsBorderlessScalingFactor);
h->Margins[1] = (unsigned)(bottom *
h->cupsBorderlessScalingFactor);
h->ImagingBoundingBox[0] = (unsigned)(left *
h->cupsBorderlessScalingFactor);
h->ImagingBoundingBox[1] = (unsigned)(bottom *
h->cupsBorderlessScalingFactor);
h->ImagingBoundingBox[2] = (unsigned)(right *
h->cupsBorderlessScalingFactor);
h->ImagingBoundingBox[3] = (unsigned)(top *
h->cupsBorderlessScalingFactor);
h->cupsImagingBBox[0] = (float)left;
h->cupsImagingBBox[1] = (float)bottom;
h->cupsImagingBBox[2] = (float)right;
h->cupsImagingBBox[3] = (float)top;
/*
* Use the callback to validate the page header...
*/
if (func && (*func)(h, preferred_bits))
{
_cupsRasterAddError("Page header callback returned error.\n");
return (-1);
}
/*
* Check parameters...
*/
if (!h->HWResolution[0] || !h->HWResolution[1] ||
!h->PageSize[0] || !h->PageSize[1] ||
(h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 &&
h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8 &&
h->cupsBitsPerColor != 16) ||
h->cupsBorderlessScalingFactor < 0.1 ||
h->cupsBorderlessScalingFactor > 2.0)
{
_cupsRasterAddError("Page header uses unsupported values.\n");
return (-1);
}
/*
* Compute the bitmap parameters...
*/
h->cupsWidth = (unsigned)((right - left) * h->cupsBorderlessScalingFactor *
h->HWResolution[0] / 72.0f + 0.5f);
h->cupsHeight = (unsigned)((top - bottom) * h->cupsBorderlessScalingFactor *
h->HWResolution[1] / 72.0f + 0.5f);
switch (h->cupsColorSpace)
{
case CUPS_CSPACE_W :
case CUPS_CSPACE_K :
case CUPS_CSPACE_WHITE :
case CUPS_CSPACE_GOLD :
case CUPS_CSPACE_SILVER :
case CUPS_CSPACE_SW :
h->cupsNumColors = 1;
h->cupsBitsPerPixel = h->cupsBitsPerColor;
break;
default :
/*
* Ensure that colorimetric colorspaces use at least 8 bits per
* component...
*/
if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ &&
h->cupsBitsPerColor < 8)
h->cupsBitsPerColor = 8;
/*
* Figure out the number of bits per pixel...
*/
if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
{
if (h->cupsBitsPerColor >= 8)
h->cupsBitsPerPixel = h->cupsBitsPerColor * 3;
else
h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
}
else
h->cupsBitsPerPixel = h->cupsBitsPerColor;
h->cupsNumColors = 3;
break;
case CUPS_CSPACE_KCMYcm :
if (h->cupsBitsPerColor == 1)
{
if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
h->cupsBitsPerPixel = 8;
else
h->cupsBitsPerPixel = 1;
h->cupsNumColors = 6;
break;
}
/*
* Fall through to CMYK code...
*/
case CUPS_CSPACE_RGBA :
case CUPS_CSPACE_RGBW :
case CUPS_CSPACE_CMYK :
case CUPS_CSPACE_YMCK :
case CUPS_CSPACE_KCMY :
case CUPS_CSPACE_GMCK :
case CUPS_CSPACE_GMCS :
if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
else
h->cupsBitsPerPixel = h->cupsBitsPerColor;
h->cupsNumColors = 4;
break;
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 :
h->cupsNumColors = h->cupsColorSpace - CUPS_CSPACE_DEVICE1 + 1;
if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
h->cupsBitsPerPixel = h->cupsBitsPerColor * h->cupsNumColors;
else
h->cupsBitsPerPixel = h->cupsBitsPerColor;
break;
}
h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8;
if (h->cupsColorOrder == CUPS_ORDER_BANDED)
h->cupsBytesPerLine *= h->cupsNumColors;
return (status);
}