static int setpagedevice()

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);
}