https://bugs.gentoo.org/927137 https://github.com/OpenPrinting/cups-filters/issues/578 https://github.com/OpenPrinting/libcupsfilters/commit/c6175a2f3f66dbf76bb35ec8d1ba0dc094c9dbac From c6175a2f3f66dbf76bb35ec8d1ba0dc094c9dbac Mon Sep 17 00:00:00 2001 From: Till Kamppeter Date: Wed, 29 Nov 2023 00:25:16 +0100 Subject: [PATCH] raster_base_header(): Several fixes on color space selection Fixes #38 The internal (static) funcrion raster_base_header() creates a CUPS or PWG Raster header from scratch, without using data of a PPD file by means of Raster header derived from the PPD. It solely uses IPP attributes or command line options. It distinguishes between CUPS Raster and PWG/Apple Raster headers. There were several bugs in selecting the correct color space and depth settings: - For PWG-Raster all attributes and options got ignored and standard 8-bit sRGB set. - Without any valid color space/depth setting attribute or "auto" always standard 8-bit sRGB got set as the default, regardless whether the printer is actually a color printer. - Color spaces for printing in color could be set on monochrome printers by options or atrributes. - Color spaces not valid on PWG Raster could be set on PWG Raster. - DeviceN modes could only be set by specifying a depth, like "Device4_8" not just "Device4". Now we use 8-bit SGray as default for monochrome printers and 8-bit RGB for color printers. We use the printer IPP attribute "color-supported" to check whether the printer is color. IPP ttributes or command line options setting a color mode on a monochrome printer are ignored now, also, if the output format is PWG Raster, setting a color space not supported by PWG Raster is ignored. Now for monochrome AirPrint (Apple Raster) printers, the Raster data sent should be actually monochrome (grayscale) and not color. --- cupsfilters/raster.c | 103 +++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/cupsfilters/raster.c b/cupsfilters/raster.c index 32a8b807..5e10f3bb 100644 --- a/cupsfilters/raster.c +++ b/cupsfilters/raster.c @@ -792,7 +792,7 @@ cfRasterSetColorSpace(cups_page_header_t *h, // I - Raster header static int // O - -1 on error, 0 on success -raster_base_header(cups_page_header2_t *h, // O - Raster header +raster_base_header(cups_page_header2_t *h, // O - Raster header cf_filter_data_t *data, // I - Filter data int pwg_raster) // I - 1 if PWG/Apple Raster { @@ -1420,41 +1420,46 @@ raster_base_header(cups_page_header_t *h, // O - Raster header // TODO - Support for MediaType number h->cupsMediaType = 0; - // Only for CUPS Raster, if we do not have a sample header from a PPD file - if (pwg_raster == 0 && - ((val = cupsGetOption("pwg-raster-document-type", num_options, - options)) != NULL || - (val = cupsGetOption("PwgRasterDocumentType", num_options, - options)) != NULL || - (val = cupsGetOption("color-space", num_options, options)) != NULL || - (val = cupsGetOption("ColorSpace", num_options, options)) != NULL || - (val = cupsGetOption("color-model", num_options, options)) != NULL || - (val = cupsGetOption("ColorModel", num_options, options)) != NULL || - (val = cupsGetOption("print-color-mode", num_options, options)) != - NULL || - (val = cupsGetOption("output-mode", num_options, options)) != NULL || - (val = cupsGetOption("OutputMode", num_options, options)) != NULL || - (val = cfIPPAttrEnumValForPrinter(data->printer_attrs, - data->job_attrs, - "print-color-mode")) != NULL)) + + // Do we have a color printer? + bool is_color = + ((attr = ippFindAttribute(data->printer_attrs, "color-supported", + IPP_TAG_BOOLEAN)) != NULL && + ippGetBoolean(attr, 0)); + + // Color modes + int numcolors = 0; // Number of colorants + if ((val = cupsGetOption("pwg-raster-document-type", num_options, + options)) != NULL || + (val = cupsGetOption("PwgRasterDocumentType", num_options, + options)) != NULL || + (val = cupsGetOption("color-space", num_options, options)) != NULL || + (val = cupsGetOption("ColorSpace", num_options, options)) != NULL || + (val = cupsGetOption("color-model", num_options, options)) != NULL || + (val = cupsGetOption("ColorModel", num_options, options)) != NULL || + (val = cupsGetOption("print-color-mode", num_options, options)) != + NULL || + (val = cupsGetOption("output-mode", num_options, options)) != NULL || + (val = cupsGetOption("OutputMode", num_options, options)) != NULL || + (val = cfIPPAttrEnumValForPrinter(data->printer_attrs, + data->job_attrs, + "print-color-mode")) != NULL) { int bitspercolor, // Bits per color bitsperpixel, // Bits per pixel - colorspace, // CUPS/PWG raster color space - numcolors; // Number of colorants + colorspace; // CUPS/PWG raster color space; const char *ptr; // Pointer into value ptr = NULL; - numcolors = 0; bitspercolor = 8; - if (!strncasecmp(val, "AdobeRgb", 8)) + if (is_color && !strncasecmp(val, "AdobeRgb", 8)) { if (*(val + 8) == '_' || *(val + 8) == '-') ptr = val + 9; colorspace = 20; numcolors = 3; } - else if (!strncasecmp(val, "adobe-rgb", 9)) + else if (is_color && !strncasecmp(val, "adobe-rgb", 9)) { if (*(val + 9) == '_' || *(val + 9) == '-') ptr = val + 10; @@ -1500,19 +1505,19 @@ raster_base_header(cups_page_header_t *h, // O - Raster header colorspace = 18; numcolors = 1; } - else if (!strcasecmp(val, "color")) + else if (is_color && !strcasecmp(val, "color")) { colorspace = 19; numcolors = 3; } - else if (!strncasecmp(val, "Cmyk", 4)) + else if (is_color && !strncasecmp(val, "Cmyk", 4)) { if (*(val + 4) == '_' || *(val + 4) == '-') ptr = val + 5; colorspace = 6; numcolors = 4; } - else if (!strncasecmp(val, "Cmy", 3)) + else if (!pwg_raster && is_color && !strncasecmp(val, "Cmy", 3)) { if (*(val + 3) == '_' || *(val + 3) == '-') ptr = val + 4; @@ -1524,10 +1529,9 @@ raster_base_header(cups_page_header_t *h, // O - Raster header ptr = val + 6; numcolors = strtol(ptr, (char **)&ptr, 10); if (*ptr == '_' || *ptr == '-') - { ptr ++; + if (numcolors > 0 && numcolors < 16) colorspace = 47 + numcolors; - } else { numcolors = 0; @@ -1548,21 +1552,21 @@ raster_base_header(cups_page_header_t *h, // O - Raster header colorspace = 18; numcolors = 1; } - else if (!strncasecmp(val, "Srgb", 4)) + else if (is_color && !strncasecmp(val, "Srgb", 4)) { if (*(val + 4) == '_' || *(val + 4) == '-') ptr = val + 5; colorspace = 19; numcolors = 3; } - else if (!strncasecmp(val, "Rgbw", 4)) + else if (!pwg_raster && is_color && !strncasecmp(val, "Rgbw", 4)) { if (*(val + 4) == '_' || *(val + 4) == '-') ptr = val + 5; colorspace = 17; numcolors = 4; } - else if (!strncasecmp(val, "Rgb", 3)) + else if (is_color && !strncasecmp(val, "Rgb", 3)) { if (*(val + 3) == '_' || *(val + 3) == '-') ptr = val + 4; @@ -1572,12 +1576,22 @@ raster_base_header(cups_page_header_t *h, // O - Raster header else if (!strcasecmp(val, "auto")) { // Let "auto" not look like an error - colorspace = 19; - numcolors = 3; + if (is_color) + { + colorspace = 19; + numcolors = 3; + } + else + { + colorspace = 18; + numcolors = 1; + } } + + // Color mode found if (numcolors > 0) { - if (ptr) + if (ptr && *ptr) bitspercolor = strtol(ptr, (char **)&ptr, 10); bitsperpixel = bitspercolor * numcolors; // In 1-bit-per-color RGB modes we add a forth bit to each pixel @@ -1590,20 +1604,25 @@ raster_base_header(cups_page_header_t *h, // O - Raster header h->cupsColorSpace = colorspace; h->cupsNumColors = numcolors; } - else + } + + // No color mode found + if (numcolors == 0) + { + if (is_color) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 24; h->cupsColorSpace = 19; h->cupsNumColors = 3; } - } - else - { - h->cupsBitsPerColor = 8; - h->cupsBitsPerPixel = 24; - h->cupsColorSpace = 19; - h->cupsNumColors = 3; + else + { + h->cupsBitsPerColor = 8; + h->cupsBitsPerPixel = 8; + h->cupsColorSpace = 18; + h->cupsNumColors = 1; + } } // TODO - Support for color orders 1 (banded) and 2 (planar)