summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2019-10-15 12:24:12 +0200
committerThomas Deutschmann <whissi@gentoo.org>2020-08-13 11:26:55 +0200
commite088156d5b620e5e639580dacf85c6dc13823c74 (patch)
tree57f5c025e203279944da512166c20bc0521d8ccd /cups/gdevcups.c
downloadghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.gz
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.bz2
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.zip
Import Ghostscript 9.50ghostscript-9.50
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'cups/gdevcups.c')
-rw-r--r--cups/gdevcups.c6123
1 files changed, 6123 insertions, 0 deletions
diff --git a/cups/gdevcups.c b/cups/gdevcups.c
new file mode 100644
index 00000000..3df3f039
--- /dev/null
+++ b/cups/gdevcups.c
@@ -0,0 +1,6123 @@
+/*
+ *
+ * GNU Ghostscript raster output driver for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org/
+ *
+ * This code and any derivative of it may be used and distributed
+ * freely under the terms of the GNU General Public License when
+ * used with GNU Ghostscript or its derivatives. Use of the code
+ * (or any derivative of it) with software other than GNU
+ * GhostScript (or its derivatives) is governed by the CUPS license
+ * agreement.
+ *
+ * Contents:
+ *
+ * cups_close() - Close the output file.
+ * cups_decode_color() - Decode a color value.
+ * cups_encode_color() - Encode a color value.
+ * cups_get_color_comp_index()
+ * - Color component to index
+ * cups_get_color_mapping_procs()
+ * - Get the list of color mapping procedures.
+ * cups_get_matrix() - Generate the default page matrix.
+ * cups_get_params() - Get pagedevice parameters.
+ * cups_get_space_params() - Get space parameters from the RIP_CACHE env var.
+ * cups_map_cielab() - Map CIE Lab transformation...
+ * cups_map_cmyk() - Map a CMYK color value to device colors.
+ * cups_map_gray() - Map a grayscale value to device colors.
+ * cups_map_rgb() - Map a RGB color value to device colors.
+ * cups_map_cmyk_color() - Map a CMYK color to a color index.
+ * cups_map_color_rgb() - Map a color index to an RGB color.
+ * cups_map_rgb_color() - Map an RGB color to a color index. We map the
+ * RGB color to the output colorspace & bits (we
+ * figure out the format when we output a page).
+ * cups_open() - Open the output file and initialize things.
+ * cups_print_pages() - Send one or more pages to the output file.
+ * cups_put_params() - Set pagedevice parameters.
+ * cups_set_color_info() - Set the color information structure based on
+ * the required output.
+ * cups_sync_output() - Keep the user informed of our status...
+ * cups_print_chunked() - Print a page of chunked pixels.
+ * cups_print_banded() - Print a page of banded pixels.
+ * cups_print_planar() - Print a page of planar pixels.
+ */
+
+/* prevent gp.h redefining fopen */
+#define sprintf sprintf
+
+/*
+ * Include necessary headers...
+ */
+
+#include "std.h" /* to stop stdlib.h redefining types */
+#include "gdevprn.h"
+#include "gsparam.h"
+#include "gxdevsop.h"
+#include "arch.h"
+#include "gsicc_manage.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <cups/raster.h>
+#include <cups/ppd.h>
+#include <math.h>
+
+/* the extremely noisy DEBUG2 messages are now dependent on CUPS_DEBUG2 */
+/* this can be enabled during the 'make' or by uncommenting the following */
+/* #define CUPS_DEBUG2 */
+
+#undef private
+#define private
+
+#ifdef WIN32
+#define cbrt(arg) pow(arg, 1.0/3)
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#endif
+
+/* This should go into gdevprn.h, or, better yet, gdevprn should
+ acquire an API for changing resolution. */
+int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev,
+ gdev_prn_space_params *old_space,
+ int old_width, int old_height,
+ bool old_page_uses_transparency);
+
+/* Strings for cups_put/get_params */
+static const char * const cups_Integer_strings[] =
+{
+ "cupsInteger0",
+ "cupsInteger1",
+ "cupsInteger2",
+ "cupsInteger3",
+ "cupsInteger4",
+ "cupsInteger5",
+ "cupsInteger6",
+ "cupsInteger7",
+ "cupsInteger8",
+ "cupsInteger9",
+ "cupsInteger10",
+ "cupsInteger11",
+ "cupsInteger12",
+ "cupsInteger13",
+ "cupsInteger14",
+ "cupsInteger15",
+ NULL
+};
+
+static const char * const cups_Real_strings[] =
+{
+ "cupsReal0",
+ "cupsReal1",
+ "cupsReal2",
+ "cupsReal3",
+ "cupsReal4",
+ "cupsReal5",
+ "cupsReal6",
+ "cupsReal7",
+ "cupsReal8",
+ "cupsReal9",
+ "cupsReal10",
+ "cupsReal11",
+ "cupsReal12",
+ "cupsReal13",
+ "cupsReal14",
+ "cupsReal15",
+ NULL
+};
+
+static const char * const cups_String_strings[] =
+{
+ "cupsString0",
+ "cupsString1",
+ "cupsString2",
+ "cupsString3",
+ "cupsString4",
+ "cupsString5",
+ "cupsString6",
+ "cupsString7",
+ "cupsString8",
+ "cupsString9",
+ "cupsString10",
+ "cupsString11",
+ "cupsString12",
+ "cupsString13",
+ "cupsString14",
+ "cupsString15",
+ NULL
+};
+
+/*
+ * Check if we are compiling against CUPS 1.2. If so, enable
+ * certain extended attributes and use a different page header
+ * structure and write function...
+ */
+
+#ifdef CUPS_RASTER_SYNCv1
+# define cups_page_header_t cups_page_header2_t
+# define cupsRasterWriteHeader cupsRasterWriteHeader2
+#else
+/* The RGBW, SW, SRGB, and ADOBERGB colorspaces is not defined until
+ CUPS 1.2... */
+# define CUPS_CSPACE_RGBW 17
+# define CUPS_CSPACE_SW 18
+# define CUPS_CSPACE_SRGB 19
+# define CUPS_CSPACE_ADOBERGB 20
+#endif /* CUPS_RASTER_SYNCv1 */
+
+#if !defined(CUPS_RASTER_WRITE_PWG)
+ #define CUPS_RASTER_WRITE_PWG 3
+#endif
+
+/*
+ * CIE XYZ color constants...
+ */
+
+#define D65_X (0.412453 + 0.357580 + 0.180423)
+#define D65_Y (0.212671 + 0.715160 + 0.072169)
+#define D65_Z (0.019334 + 0.119193 + 0.950227)
+
+
+/*
+ * Size of a tile in pixels...
+ */
+
+#define CUPS_TILE_SIZE 256
+
+
+/*
+ * Size of profile LUTs...
+ */
+
+#ifdef dev_t_proc_encode_color
+# define CUPS_MAX_VALUE frac_1
+#else
+# define CUPS_MAX_VALUE gx_max_color_value
+#endif /* dev_t_proc_encode_color */
+
+
+/*
+ * Macros...
+ */
+
+#define x_dpi (pdev->HWResolution[0])
+#define y_dpi (pdev->HWResolution[1])
+#define cups ((gx_device_cups *)pdev)
+
+/*
+ * Macros from <macros.h>; we can't include <macros.h> because it also
+ * defines DEBUG, one of our flags to insert various debugging code.
+ */
+
+#ifndef max
+# define max(a,b) ((a)<(b) ? (b) : (a))
+#endif /* !max */
+
+#ifndef min
+# define min(a,b) ((a)>(b) ? (b) : (a))
+#endif /* !min */
+
+#ifndef abs
+# define abs(x) ((x)>=0 ? (x) : -(x))
+#endif /* !abs */
+
+
+/*
+ * Procedures
+ */
+
+private dev_proc_close_device(cups_close);
+private dev_proc_get_initial_matrix(cups_get_matrix);
+private int cups_get_params(gx_device *, gs_param_list *);
+private dev_proc_open_device(cups_open);
+private dev_proc_output_page(cups_output_page);
+private int cups_print_pages(gx_device_printer *, gp_file *, int);
+private int cups_put_params(gx_device *, gs_param_list *);
+private int cups_set_color_info(gx_device *);
+private dev_proc_sync_output(cups_sync_output);
+private prn_dev_proc_get_space_params(cups_get_space_params);
+private int cups_spec_op(gx_device *dev_, int op, void *data, int datasize);
+
+#ifdef dev_t_proc_encode_color
+private cm_map_proc_gray(cups_map_gray);
+private cm_map_proc_rgb(cups_map_rgb);
+private cm_map_proc_cmyk(cups_map_cmyk);
+private dev_proc_decode_color(cups_decode_color);
+private dev_proc_encode_color(cups_encode_color);
+private dev_proc_get_color_comp_index(cups_get_color_comp_index);
+private dev_proc_get_color_mapping_procs(cups_get_color_mapping_procs);
+
+static const gx_cm_color_map_procs cups_color_mapping_procs =
+{
+ cups_map_gray,
+ cups_map_rgb,
+ cups_map_cmyk
+};
+#else
+private dev_proc_map_cmyk_color(cups_map_cmyk_color);
+private dev_proc_map_color_rgb(cups_map_color_rgb);
+private dev_proc_map_rgb_color(cups_map_rgb_color);
+#endif /* dev_t_proc_encode_color */
+
+
+/*
+ * The device descriptors...
+ */
+
+typedef struct gx_device_cups_s
+{
+ gx_device_common; /* Standard GhostScript device stuff */
+ gx_prn_device_common; /* Standard printer device stuff */
+ int page; /* Page number */
+ cups_raster_t *stream; /* Raster stream */
+ cups_page_header_t header; /* PostScript page device info */
+ int landscape; /* Non-zero if this is landscape */
+ int lastpage;
+ int HaveProfile; /* Has a color profile been defined? */
+ char *Profile; /* Current simple color profile string */
+ ppd_file_t *PPD; /* PPD file for this device */
+ unsigned char RevLower1[16]; /* Lower 1-bit reversal table */
+ unsigned char RevUpper1[16]; /* Upper 1-bit reversal table */
+ unsigned char RevLower2[16]; /* Lower 2-bit reversal table */
+ unsigned char RevUpper2[16]; /* Upper 2-bit reversal table */
+#ifdef GX_COLOR_INDEX_TYPE
+ gx_color_value DecodeLUT[65536];/* Output color to RGB value LUT */
+#else
+ gx_color_value DecodeLUT[256]; /* Output color to RGB value LUT */
+#endif /* GX_COLOR_INDEX_TYPE */
+ unsigned short EncodeLUT[gx_max_color_value + 1];/* RGB value to output color LUT */
+ int Density[CUPS_MAX_VALUE + 1];/* Density LUT */
+ int Matrix[3][3][CUPS_MAX_VALUE + 1];/* Color transform matrix LUT */
+ int user_icc;
+ int cupsRasterVersion;
+ char pageSizeRequested[64];
+
+ /* Used by cups_put_params(): */
+} gx_device_cups;
+
+private gx_device_procs cups_procs =
+{
+ cups_open,
+ cups_get_matrix,
+ cups_sync_output,
+ cups_output_page,
+ cups_close,
+#ifdef dev_t_proc_encode_color
+ NULL, /* map_rgb_color */
+ NULL, /* map_color_rgb */
+#else
+ cups_map_rgb_color,
+ cups_map_color_rgb,
+#endif /* dev_t_proc_encode_color */
+ NULL, /* fill_rectangle */
+ NULL, /* tile_rectangle */
+ NULL, /* copy_mono */
+ NULL, /* copy_color */
+ NULL, /* draw_line */
+ gx_default_get_bits,
+ cups_get_params,
+ cups_put_params,
+#ifdef dev_t_proc_encode_color
+ NULL, /* map_cmyk_color */
+#else
+ cups_map_cmyk_color,
+#endif /* dev_t_proc_encode_color */
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device,
+ NULL, /* get_alpha_bits */
+ NULL, /* copy_alpha */
+ NULL, /* get_band */
+ NULL, /* copy_rop */
+ NULL, /* fill_path */
+ NULL, /* stroke_path */
+ NULL, /* fill_mask */
+ NULL, /* fill_trapezoid */
+ NULL, /* fill_parallelogram */
+ NULL, /* fill_triangle */
+ NULL, /* draw_thin_line */
+ NULL, /* begin_image */
+ NULL, /* image_data */
+ NULL, /* end_image */
+ NULL, /* strip_tile_rectangle */
+ NULL, /* strip_copy_rop */
+ NULL, /* get_clipping_box */
+ NULL, /* begin_typed_image */
+ NULL, /* get_bits_rectangle */
+ NULL, /* map_color_rgb_alpha */
+ NULL, /* create_compositor */
+ NULL, /* get_hardware_params */
+ NULL, /* text_begin */
+ NULL, /* finish_copydevice */
+ NULL, /* begin_transparency_group */
+ NULL, /* end_transparency_group */
+ NULL, /* begin_transparency_mask */
+ NULL, /* end_transparency_mask */
+ NULL, /* discard_transparency_layer */
+#ifdef dev_t_proc_encode_color
+ cups_get_color_mapping_procs,
+ cups_get_color_comp_index,
+ cups_encode_color,
+ cups_decode_color,
+#else
+ NULL, /* get_color_mapping_procs */
+ NULL, /* get_color_comp_index */
+ NULL, /* encode_color */
+ NULL, /* decode_color */
+#endif /* dev_t_proc_encode_color */
+ NULL, /* pattern_manage */
+ NULL, /* fill_rectangle_hl_color */
+ NULL, /* include_color_space */
+ NULL, /* fill_linear_color_scanline */
+ NULL, /* fill_linear_color_trapezoid */
+ NULL, /* fill_linear_color_triangle */
+ NULL, /* update_spot_equivalent_colors */
+ NULL, /* ret_devn_params */
+ NULL, /* fillpage */
+ NULL, /* push_transparency_state */
+ NULL, /* pop_transparency_state */
+ NULL, /* put_image */
+ cups_spec_op
+};
+
+#define prn_device_body_copies(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_pages)\
+ std_device_full_body_type(dtype, &procs, dname, &st_device_printer,\
+ (int)((long)(w10) * (xdpi) / 10),\
+ (int)((long)(h10) * (ydpi) / 10),\
+ xdpi, ydpi,\
+ ncomp, depth, mg, mc, dg, dc,\
+ -(lo) * (xdpi), -(to) * (ydpi),\
+ (lm) * 72.0, (bm) * 72.0,\
+ (rm) * 72.0, (tm) * 72.0\
+ ),\
+ prn_device_body_copies_rest_(print_pages)
+
+
+
+#ifdef CUPS_RASTER_SYNCv1
+#define RASTER_SYNCv1_ENTRIES \
+ ,\
+ 1, /* cupsNumColors */\
+ 1.0, /* cupsBorderlessScalingFactor */\
+ { 612.0, 792.0 }, /* cupsPageSize */\
+ { 0.0, 0.0, 612.0, 792.0 }, /* cupsImagingBBox */\
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* cupsInteger */\
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, /* cupsReal */\
+ { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },\
+ /* cupsString */\
+ "", /* cupsMarkerType */\
+ "", /* cupsRenderingIntent */\
+ "" /* cupsPageSizeName */
+#else
+#define RASTER_SYNCv1_ENTRIES
+#endif /* CUPS_RASTER_SYNCv1 */
+
+#define gs_xxx_device(dname, mediaclass)\
+ prn_device_body_copies(gx_device_cups,/* type */\
+ cups_procs, /* procedures */\
+ dname, /* device name */\
+ 85, /* initial width */\
+ 110, /* initial height */\
+ 100, /* initial x resolution */\
+ 100, /* initial y resolution */\
+ 0, /* initial left offset */\
+ 0, /* initial top offset */\
+ 0, /* initial left margin */\
+ 0, /* initial bottom margin */\
+ 0, /* initial right margin */\
+ 0, /* initial top margin */\
+ 1, /* number of color components */\
+ 1, /* number of color bits */\
+ 1, /* maximum gray value */\
+ 0, /* maximum color value */\
+ 2, /* number of gray values */\
+ 0, /* number of color values */\
+ cups_print_pages),\
+ /* print procedure */\
+ 0, /* page */\
+ NULL, /* stream */\
+ { /* header */\
+ mediaclass, /* MediaClass */\
+ "", /* MediaColor */\
+ "", /* MediaType */\
+ "", /* OutputType */\
+ 0, /* AdvanceDistance */\
+ CUPS_ADVANCE_NONE, /* AdvanceMedia */\
+ CUPS_FALSE, /* Collate */\
+ CUPS_CUT_NONE, /* CutMedia */\
+ CUPS_FALSE, /* Duplex */\
+ { 100, 100 }, /* HWResolution */\
+ { 0, 0, 612, 792 }, /* ImagingBoundingBox */\
+ CUPS_FALSE, /* InsertSheet */\
+ CUPS_JOG_NONE, /* Jog */\
+ CUPS_EDGE_TOP, /* LeadingEdge */\
+ { 0, 0 }, /* Margins */\
+ CUPS_FALSE, /* ManualFeed */\
+ 0, /* MediaPosition */\
+ 0, /* MediaWeight */\
+ CUPS_FALSE, /* MirrorPrint */\
+ CUPS_FALSE, /* NegativePrint */\
+ 1, /* NumCopies */\
+ CUPS_ORIENT_0, /* Orientation */\
+ CUPS_FALSE, /* OutputFaceUp */\
+ { 612, 792 }, /* PageSize */\
+ CUPS_FALSE, /* Separations */\
+ CUPS_FALSE, /* TraySwitch */\
+ CUPS_FALSE, /* Tumble */\
+ 850, /* cupsWidth */\
+ 1100, /* cupsHeight */\
+ 0, /* cupsMediaType */\
+ 1, /* cupsBitsPerColor */\
+ 1, /* cupsBitsPerPixel */\
+ 107, /* cupsBytesPerLine */\
+ CUPS_ORDER_CHUNKED, /* cupsColorOrder */\
+ CUPS_CSPACE_K, /* cupsColorSpace */\
+ 0, /* cupsCompression */\
+ 0, /* cupsRowCount */\
+ 0, /* cupsRowFeed */\
+ 0 /* cupsRowStep */\
+ RASTER_SYNCv1_ENTRIES, /* See above */\
+ },\
+ 0, /* landscape */\
+ 0, /* lastpage */\
+ 0, /* HaveProfile */\
+ NULL, /* Profile */\
+ NULL, /* PPD */\
+ { 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,\
+ 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f },/* RevLower1 */\
+ { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,\
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 },/* RevUpper1 */\
+ { 0x00, 0x04, 0x08, 0x0c, 0x01, 0x05, 0x09, 0x0d,\
+ 0x02, 0x06, 0x0a, 0x0e, 0x03, 0x07, 0x0b, 0x0f },/* RevLower2 */\
+ { 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,\
+ 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0 },/* RevUpper2 */\
+ {0x00}, /* DecodeLUT */\
+ {0x00}, /* EncodeLUT */\
+ {0x00}, /* Density */\
+ {{{0x00},{0x00},{0x00}},\
+ {{0x00},{0x00},{0x00}},\
+ {{0x00},{0x00},{0x00}}}, /* Matrix */\
+ 0, /* user_icc */\
+ 3, /* cupsRasterVersion */\
+ "" /* pageSizeRequested */
+
+gx_device_cups gs_cups_device = { gs_xxx_device("cups", "") };
+gx_device_cups gs_pwgraster_device = { gs_xxx_device("pwgraster",
+ "PwgRaster") };
+
+/*
+ * Local functions...
+ */
+
+static double cups_map_cielab(double, double);
+static int cups_print_chunked(gx_device_printer *, unsigned char *,
+ unsigned char *, int);
+static int cups_print_banded(gx_device_printer *, unsigned char *,
+ unsigned char *, int);
+static int cups_print_planar(gx_device_printer *, unsigned char *,
+ unsigned char *, int);
+
+/*static void cups_set_margins(gx_device *);*/
+
+
+/*
+ * 'cups_close()' - Close the output file.
+ */
+
+private int
+cups_close(gx_device *pdev) /* I - Device info */
+{
+#ifdef CUPS_DEBUG2
+ dmprintf1(pdev->memory, "DEBUG2: cups_close(%p)\n", pdev);
+#endif /* CUPS_DEBUG2 */
+
+ dmprintf(pdev->memory, "INFO: Rendering completed\n");
+
+ if (cups->stream != NULL)
+ {
+ cupsRasterClose(cups->stream);
+ cups->stream = NULL;
+ }
+
+#if 0 /* Can't do this here because put_params() might close the device */
+ if (cups->PPD != NULL)
+ {
+ ppdClose(cups->PPD);
+ cups->PPD = NULL;
+ }
+
+ if (cups->Profile != NULL)
+ {
+ free(cups->Profile);
+ cups->Profile = NULL;
+ }
+#endif /* 0 */
+
+ return (gdev_prn_close(pdev));
+}
+
+
+#ifdef dev_t_proc_encode_color
+/*
+ * 'cups_decode_color()' - Decode a color value.
+ */
+
+private int /* O - Status (0 = OK) */
+cups_decode_color(gx_device *pdev, /* I - Device info */
+ gx_color_index ci, /* I - Color index */
+ gx_color_value *cv) /* O - Colors */
+{
+ int i; /* Looping var */
+ int shift; /* Bits to shift */
+ int mask; /* Bits to mask */
+
+
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm &&
+ cups->header.cupsBitsPerColor == 1)
+ {
+ /*
+ * KCMYcm data is represented internally by Ghostscript as CMYK...
+ */
+
+ cv[0] = (ci & 0x20) ? frac_1 : frac_0;
+ cv[1] = (ci & 0x12) ? frac_1 : frac_0;
+ cv[2] = (ci & 0x09) ? frac_1 : frac_0;
+ cv[3] = (ci & 0x04) ? frac_1 : frac_0;
+ }
+ else
+ {
+ shift = cups->header.cupsBitsPerColor;
+ mask = (1 << shift) - 1;
+
+ for (i = cups->color_info.num_components - 1; i > 0; i --, ci >>= shift)
+ cv[i] = cups->DecodeLUT[ci & mask];
+
+ cv[0] = cups->DecodeLUT[ci & mask];
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cups_encode_color()' - Encode a color value.
+ */
+
+private gx_color_index /* O - Color index */
+cups_encode_color(gx_device *pdev,
+ /* I - Device info */
+ const gx_color_value *cv)
+ /* I - Colors */
+{
+ int i; /* Looping var */
+ gx_color_index ci; /* Color index */
+ int shift; /* Bits to shift */
+
+
+ /*
+ * Encode the color index...
+ */
+
+ shift = cups->header.cupsBitsPerColor;
+
+ for (ci = cups->EncodeLUT[cv[0]], i = 1;
+ i < cups->color_info.num_components;
+ i ++)
+ ci = (ci << shift) | cups->EncodeLUT[cv[i]];
+
+#ifdef CUPS_DEBUG2
+ dmprintf2(pdev->memory, "DEBUG2: cv[0]=%d -> %llx\n", cv[0], ci);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Handle 6-color output...
+ */
+
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm &&
+ cups->header.cupsBitsPerColor == 1)
+ {
+ /*
+ * Welcome to hackville, where we map CMYK data to the
+ * light inks in draft mode... Map blue to light magenta and
+ * cyan and green to light cyan and yellow...
+ */
+
+ ci <<= 2; /* Leave room for light inks */
+
+ if (ci == 0x18) /* Blue */
+ ci = 0x11; /* == cyan + light magenta */
+ else if (ci == 0x14) /* Green */
+ ci = 0x06; /* == light cyan + yellow */
+ }
+
+ /* The entire manner that cups does its color mapping needs some serious
+ rework. In the case of the output RGBW color space, it takes a source
+ CMYK value which gs maps to RGB, cups then maps the RGB to CMYK and then
+ from there to RGBW and finally it does an encode. Unfortunately, the
+ number of color values for RGBW is 3 since it is using an RGB ICC profile
+ this means that the W mapping value from cups is lost in cmap_rgb_direct
+ So here we ensure that the W is always set to on (else we end up with a
+ blue background cast). The ideal way
+ to fix this is to move some of these odd color spaces of cups to the
+ separation device model ensuring that things are handled properly. */
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_RGBW) {
+ ci = (ci << shift) | cups->EncodeLUT[gx_max_color_value];
+ }
+
+ /*
+ * Range check the return value...
+ */
+
+ if (ci == gx_no_color_index)
+ ci --;
+
+ /*
+ * Return the color index...
+ */
+
+ return (ci);
+}
+
+/*
+ * 'cups_get_color_comp_index()' - Color component to index
+ */
+
+#define compare_color_names(pname, name_size, name_str) \
+ (name_size == (int)strlen(name_str) && strncasecmp(pname, name_str, name_size) == 0)
+
+int /* O - Index of the named color in
+ the color space */
+cups_get_color_comp_index(gx_device * pdev, const char * pname,
+ int name_size, int component_type)
+{
+ switch (cups->header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_K :
+ if (compare_color_names(pname, name_size, "Black") ||
+ compare_color_names(pname, name_size, "Gray") ||
+ compare_color_names(pname, name_size, "Grey"))
+ return 0;
+ else
+ return -1; /* Indicate that the component name is "unknown" */
+ break;
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ case CUPS_CSPACE_WHITE :
+ if (compare_color_names(pname, name_size, "White") ||
+ compare_color_names(pname, name_size, "Luminance") ||
+ compare_color_names(pname, name_size, "Gray") ||
+ compare_color_names(pname, name_size, "Grey"))
+ return 0;
+ else
+ return -1;
+ break;
+ case CUPS_CSPACE_RGBA :
+ if (compare_color_names(pname, name_size, "Alpha") ||
+ compare_color_names(pname, name_size, "Transparent") ||
+ compare_color_names(pname, name_size, "Transparency"))
+ return 3;
+ /* fall through */
+ case CUPS_CSPACE_RGBW :
+ if (compare_color_names(pname, name_size, "Red"))
+ return 0;
+ if (compare_color_names(pname, name_size, "Green"))
+ return 1;
+ if (compare_color_names(pname, name_size, "Blue"))
+ return 2;
+ if (compare_color_names(pname, name_size, "White"))
+ return 3;
+ else
+ return -1;
+ break;
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ if (compare_color_names(pname, name_size, "Red"))
+ return 0;
+ if (compare_color_names(pname, name_size, "Green"))
+ return 1;
+ if (compare_color_names(pname, name_size, "Blue"))
+ return 2;
+ break;
+ case CUPS_CSPACE_CMYK :
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ if (compare_color_names(pname, name_size, "Black"))
+ return 3;
+ /* fall through */
+ case CUPS_CSPACE_CMY :
+ if (compare_color_names(pname, name_size, "Cyan"))
+ return 0;
+ if (compare_color_names(pname, name_size, "Magenta"))
+ return 1;
+ if (compare_color_names(pname, name_size, "Yellow"))
+ return 2;
+ else
+ return -1;
+ break;
+ case CUPS_CSPACE_GMCS :
+ if (compare_color_names(pname, name_size, "Silver") ||
+ compare_color_names(pname, name_size, "Silver Foil"))
+ return 3;
+ /* fall through */
+ case CUPS_CSPACE_GMCK :
+ if (compare_color_names(pname, name_size, "Gold") ||
+ compare_color_names(pname, name_size, "Gold Foil"))
+ return 0;
+ /* fall through */
+ case CUPS_CSPACE_YMCK :
+ if (compare_color_names(pname, name_size, "Black"))
+ return 3;
+ /* fall through */
+ case CUPS_CSPACE_YMC :
+ if (compare_color_names(pname, name_size, "Yellow"))
+ return 0;
+ if (compare_color_names(pname, name_size, "Magenta"))
+ return 1;
+ if (compare_color_names(pname, name_size, "Cyan"))
+ return 2;
+ else
+ return -1;
+ break;
+ case CUPS_CSPACE_KCMYcm :
+ if (compare_color_names(pname, name_size, "Light Cyan") ||
+ compare_color_names(pname, name_size, "Photo Cyan"))
+ return 4;
+ if (compare_color_names(pname, name_size, "Light Magenta") ||
+ compare_color_names(pname, name_size, "Photo Magenta"))
+ return 5;
+ case CUPS_CSPACE_KCMY :
+ if (compare_color_names(pname, name_size, "Black"))
+ return 0;
+ if (compare_color_names(pname, name_size, "Cyan"))
+ return 1;
+ if (compare_color_names(pname, name_size, "Magenta"))
+ return 2;
+ if (compare_color_names(pname, name_size, "Yellow"))
+ return 3;
+ else
+ return -1;
+ break;
+ case CUPS_CSPACE_GOLD :
+ if (compare_color_names(pname, name_size, "Gold") ||
+ compare_color_names(pname, name_size, "Gold Foil"))
+ return 0;
+ else
+ return -1;
+ break;
+ case CUPS_CSPACE_SILVER :
+ if (compare_color_names(pname, name_size, "Silver") ||
+ compare_color_names(pname, name_size, "Silver Foil"))
+ return 0;
+ else
+ return -1;
+ break;
+ default:
+ break;
+ }
+ return -1;
+}
+
+/*
+ * 'cups_get_color_mapping_procs()' - Get the list of color mapping procedures.
+ */
+
+private const gx_cm_color_map_procs * /* O - List of device procedures */
+cups_get_color_mapping_procs(const gx_device *pdev)
+ /* I - Device info */
+{
+ return (&cups_color_mapping_procs);
+}
+#endif /* dev_t_proc_encode_color */
+
+
+/*
+ * 'cups_get_matrix()' - Generate the default page matrix.
+ */
+
+private void
+cups_get_matrix(gx_device *pdev, /* I - Device info */
+ gs_matrix *pmat) /* O - Physical transform matrix */
+{
+#ifdef CUPS_DEBUG2
+ dmprintf2(pdev->memory, "DEBUG2: cups_get_matrix(%p, %p)\n", pdev, pmat);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Set the raster width and height...
+ */
+
+ cups->header.cupsWidth = cups->width;
+ cups->header.cupsHeight = cups->height;
+
+ /*
+ * Set the transform matrix...
+ */
+
+ if (cups->landscape)
+ {
+ /*
+ * Do landscape orientation...
+ */
+#ifdef CUPS_DEBUG2
+ dprintf("DEBUG2: Landscape matrix: XX=0 XY=+1 YX=+1 YY=0\n");
+#endif /* CUPS_DEBUG2 */
+ pmat->xx = 0.0;
+ pmat->xy = (float)cups->header.HWResolution[1] / 72.0;
+ pmat->yx = (float)cups->header.HWResolution[0] / 72.0;
+ pmat->yy = 0.0;
+ pmat->tx = -(float)cups->header.HWResolution[0] * pdev->HWMargins[1] / 72.0;
+ pmat->ty = -(float)cups->header.HWResolution[1] * pdev->HWMargins[0] / 72.0;
+ }
+ else
+ {
+ /*
+ * Do portrait orientation...
+ */
+#ifdef CUPS_DEBUG2
+ dmprintf(pdev->memory, "DEBUG2: Portrait matrix: XX=+1 XY=0 YX=0 YY=-1\n");
+#endif /* CUPS_DEBUG2 */
+ pmat->xx = (float)cups->header.HWResolution[0] / 72.0;
+ pmat->xy = 0.0;
+ pmat->yx = 0.0;
+ pmat->yy = -(float)cups->header.HWResolution[1] / 72.0;
+ pmat->tx = -(float)cups->header.HWResolution[0] * pdev->HWMargins[0] / 72.0;
+ pmat->ty = (float)cups->header.HWResolution[1] *
+ ((float)cups->header.PageSize[1] - pdev->HWMargins[3]) / 72.0;
+ }
+
+#ifdef CUPS_RASTER_SYNCv1
+ if (cups->header.cupsBorderlessScalingFactor > 1.0)
+ {
+ pmat->xx *= cups->header.cupsBorderlessScalingFactor;
+ pmat->xy *= cups->header.cupsBorderlessScalingFactor;
+ pmat->yx *= cups->header.cupsBorderlessScalingFactor;
+ pmat->yy *= cups->header.cupsBorderlessScalingFactor;
+ pmat->tx *= cups->header.cupsBorderlessScalingFactor;
+ pmat->ty *= cups->header.cupsBorderlessScalingFactor;
+ }
+#endif /* CUPS_RASTER_SYNCv1 */
+
+#ifdef CUPS_DEBUG2
+ dmprintf2(pdev->memory, "DEBUG2: width = %d, height = %d\n", cups->header.cupsWidth,
+ cups->header.cupsHeight);
+ dmprintf4(pdev->memory, "DEBUG2: PageSize = [ %d %d ], HWResolution = [ %d %d ]\n",
+ cups->header.PageSize[0], cups->header.PageSize[1],
+ cups->header.HWResolution[0], cups->header.HWResolution[1]);
+ dmprintf4(pdev->memory, "DEBUG2: HWMargins = [ %.3f %.3f %.3f %.3f ]\n",
+ pdev->HWMargins[0], pdev->HWMargins[1], pdev->HWMargins[2],
+ pdev->HWMargins[3]);
+ dmprintf6(pdev->memory, "DEBUG2: matrix = [ %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
+#endif /* CUPS_DEBUG2 */
+}
+
+
+/*
+ * 'cups_get_params()' - Get pagedevice parameters.
+ */
+
+private int /* O - Error status */
+cups_get_params(gx_device *pdev, /* I - Device info */
+ gs_param_list *plist) /* I - Parameter list */
+{
+ int code; /* Return code */
+ gs_param_string s; /* Temporary string value */
+ bool b; /* Temporary boolean value */
+#ifdef CUPS_RASTER_SYNCv1
+ int i; /* Looping var */
+#endif /* CUPS_RASTER_SYNCv1 */
+
+
+#ifdef CUPS_DEBUG2
+ dmprintf2(pdev->memory, "DEBUG2: cups_get_params(%p, %p)\n", pdev, plist);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * First process the "standard" page device parameters...
+ */
+
+#ifdef CUPS_DEBUG2
+ dmprintf(pdev->memory, "DEBUG2: before gdev_prn_get_params()\n");
+#endif /* CUPS_DEBUG2 */
+
+ if ((code = gdev_prn_get_params(pdev, plist)) < 0)
+ goto done;
+
+#ifdef CUPS_DEBUG2
+ dmprintf(pdev->memory, "DEBUG2: after gdev_prn_get_params()\n");
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Then write the CUPS parameters...
+ */
+
+ param_string_from_transient_string(s, cups->header.MediaClass);
+ if ((code = param_write_string(plist, "MediaClass", &s)) < 0)
+ goto done;
+
+ param_string_from_transient_string(s, cups->header.MediaColor);
+ if ((code = param_write_string(plist, "MediaColor", &s)) < 0)
+ goto done;
+
+ param_string_from_transient_string(s, cups->header.MediaType);
+ if ((code = param_write_string(plist, "MediaType", &s)) < 0)
+ goto done;
+
+ param_string_from_transient_string(s, cups->header.OutputType);
+ if ((code = param_write_string(plist, "OutputType", &s)) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "AdvanceDistance",
+ (int *)&(cups->header.AdvanceDistance))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "AdvanceMedia",
+ (int *)&(cups->header.AdvanceMedia))) < 0)
+ goto done;
+
+ b = cups->header.Collate;
+ if ((code = param_write_bool(plist, "Collate", &b)) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "CutMedia",
+ (int *)&(cups->header.CutMedia))) < 0)
+ goto done;
+
+ b = cups->header.Duplex;
+ if ((code = param_write_bool(plist, "Duplex", &b)) < 0)
+ goto done;
+
+ b = cups->header.InsertSheet;
+ if ((code = param_write_bool(plist, "InsertSheet", &b)) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "Jog",
+ (int *)&(cups->header.Jog))) < 0)
+ goto done;
+
+ b = cups->header.ManualFeed;
+ if ((code = param_write_bool(plist, "ManualFeed", &b)) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "MediaPosition",
+ (int *)&(cups->header.MediaPosition))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "MediaWeight",
+ (int *)&(cups->header.MediaWeight))) < 0)
+ goto done;
+
+ b = cups->header.MirrorPrint;
+ if ((code = param_write_bool(plist, "MirrorPrint", &b)) < 0)
+ goto done;
+
+ b = cups->header.NegativePrint;
+ if ((code = param_write_bool(plist, "NegativePrint", &b)) < 0)
+ goto done;
+
+ b = cups->header.OutputFaceUp;
+ if ((code = param_write_bool(plist, "OutputFaceUp", &b)) < 0)
+ goto done;
+
+ b = cups->header.Separations;
+ if ((code = param_write_bool(plist, "Separations", &b)) < 0)
+ goto done;
+
+ b = cups->header.TraySwitch;
+ if ((code = param_write_bool(plist, "TraySwitch", &b)) < 0)
+ goto done;
+
+ b = cups->header.Tumble;
+ if ((code = param_write_bool(plist, "Tumble", &b)) < 0)
+ goto done;
+
+#if 0 /* Don't include read-only parameters... */
+ if ((code = param_write_int(plist, "cupsWidth",
+ (int *)&(cups->header.cupsWidth))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsHeight",
+ (int *)&(cups->header.cupsHeight))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsBitsPerPixel",
+ (int *)&(cups->header.cupsBitsPerPixel))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsBytesPerLine",
+ (int *)&(cups->header.cupsBytesPerLine))) < 0)
+ goto done;
+#endif /* 0 */
+
+ if ((code = param_write_int(plist, "cupsMediaType",
+ (int *)&(cups->header.cupsMediaType))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsBitsPerColor",
+ (int *)&(cups->header.cupsBitsPerColor))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsColorOrder",
+ (int *)&(cups->header.cupsColorOrder))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsColorSpace",
+ (int *)&(cups->header.cupsColorSpace))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsCompression",
+ (int *)&(cups->header.cupsCompression))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsRowCount",
+ (int *)&(cups->header.cupsRowCount))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsRowFeed",
+ (int *)&(cups->header.cupsRowFeed))) < 0)
+ goto done;
+
+ if ((code = param_write_int(plist, "cupsRowStep",
+ (int *)&(cups->header.cupsRowStep))) < 0)
+ goto done;
+
+#ifdef CUPS_RASTER_SYNCv1
+#if 0 /* Don't include read-only parameters... */
+ if ((code = param_write_int(plist, "cupsNumColors",
+ (int *)&(cups->header.cupsNumColors))) < 0)
+ goto done;
+#endif /* 0 */
+
+ if ((code = param_write_float(plist, "cupsBorderlessScalingFactor",
+ &(cups->header.cupsBorderlessScalingFactor))) < 0)
+ goto done;
+
+ for (i = 0; cups_Integer_strings[i] != NULL; i ++)
+ {
+ if ((code = param_write_int(plist, cups_Integer_strings[i],
+ (int *)(cups->header.cupsInteger + i))) < 0)
+ goto done;
+ }
+
+ for (i = 0; cups_Real_strings[i] != NULL; i ++)
+ {
+ if ((code = param_write_float(plist, cups_Real_strings[i],
+ cups->header.cupsReal + i)) < 0)
+ goto done;
+ }
+
+ for (i = 0; cups_String_strings[i] != NULL; i ++)
+ {
+ param_string_from_transient_string(s, cups->header.cupsString[i]);
+ if ((code = param_write_string(plist, cups_String_strings[i], &s)) < 0)
+ goto done;
+ }
+
+ param_string_from_transient_string(s, cups->header.cupsMarkerType);
+ if ((code = param_write_string(plist, "cupsMarkerType", &s)) < 0)
+ goto done;
+
+ param_string_from_transient_string(s, cups->header.cupsRenderingIntent);
+ if ((code = param_write_string(plist, "cupsRenderingIntent", &s)) < 0)
+ goto done;
+
+ param_string_from_transient_string(s, cups->header.cupsPageSizeName);
+ if ((code = param_write_string(plist, "cupsPageSizeName", &s)) < 0)
+ goto done;
+#endif /* CUPS_RASTER_SYNCv1 */
+
+done:
+
+#ifdef CUPS_DEBUG2
+ dmprintf(pdev->memory, "DEBUG2: Leaving cups_get_params()\n");
+#endif /* CUPS_DEBUG2 */
+
+ return code;
+}
+
+
+/*
+ * 'cups_get_space_params()' - Get space parameters from the RIP_CACHE env var.
+ */
+
+void
+cups_get_space_params(const gx_device_printer *pdev,
+ /* I - Printer device */
+ gdev_prn_space_params *space_params)
+ /* O - Space parameters */
+{
+ float cache_size; /* Size of tile cache in bytes */
+ char *cache_env, /* Cache size environment variable */
+ cache_units[255]; /* Cache size units */
+
+
+#ifdef CUPS_DEBUG2
+ dmprintf2(pdev->memory, "DEBUG2: cups_get_space_params(%p, %p)\n", pdev, space_params);
+#endif /* CUPS_DEBUG2 */
+
+ if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL)
+ {
+ switch (sscanf(cache_env, "%f%254s", &cache_size, cache_units))
+ {
+ case 0 :
+ return;
+ case 1 :
+ cache_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
+ break;
+ case 2 :
+ if (tolower(cache_units[0]) == 'g')
+ cache_size *= 1024 * 1024 * 1024;
+ else if (tolower(cache_units[0]) == 'm')
+ cache_size *= 1024 * 1024;
+ else if (tolower(cache_units[0]) == 'k')
+ cache_size *= 1024;
+ else if (tolower(cache_units[0]) == 't')
+ cache_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
+ break;
+ }
+ }
+ else
+ return;
+
+ if (cache_size == 0)
+ return;
+
+#ifdef CUPS_DEBUG2
+ dmprintf1(pdev->memory, "DEBUG2: cache_size = %.0f\n", cache_size);
+#endif /* CUPS_DEBUG2 */
+
+ space_params->MaxBitmap = (long)cache_size;
+ space_params->BufferSpace = (long)cache_size;
+}
+
+
+/*
+ * 'cups_map_cielab()' - Map CIE Lab transformation...
+ */
+
+static double /* O - Adjusted color value */
+cups_map_cielab(double x, /* I - Raw color value */
+ double xn) /* I - Whitepoint color value */
+{
+ double x_xn; /* Fraction of whitepoint */
+
+
+ x_xn = x / xn;
+
+ if (x_xn > 0.008856)
+ return (cbrt(x_xn));
+ else
+ return (7.787 * x_xn + 16.0 / 116.0);
+}
+
+
+#ifdef dev_t_proc_encode_color
+/*
+ * 'cups_map_cmyk()' - Map a CMYK color value to device colors.
+ */
+
+private void
+cups_map_cmyk(gx_device *pdev, /* I - Device info */
+ frac c, /* I - Cyan value */
+ frac m, /* I - Magenta value */
+ frac y, /* I - Yellow value */
+ frac k, /* I - Black value */
+ frac *out) /* O - Device colors */
+{
+ int c0 = 0, c1 = 0,
+ c2 = 0, c3 = 0; /* Temporary color values */
+ float rr, rg, rb, /* Real RGB colors */
+ ciex, ciey, ciez, /* CIE XYZ colors */
+ ciey_yn, /* Normalized luminance */
+ ciel, ciea, cieb; /* CIE Lab colors */
+
+
+#ifdef CUPS_DEBUG2
+ dmprintf6(pdev->memory, "DEBUG2: cups_map_cmyk(%p, %d, %d, %d, %d, %p)\n",
+ pdev, c, m, y, k, out);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Convert the CMYK color to the destination colorspace...
+ */
+
+ switch (cups->header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ c0 = (c * 31 + m * 61 + y * 8) / 100 + k;
+
+ if (c0 < 0)
+ c0 = 0;
+ else if (c0 > frac_1)
+ c0 = frac_1;
+ out[0] = frac_1 - (frac)cups->Density[c0];
+ break;
+
+ case CUPS_CSPACE_RGBA :
+ out[3] = frac_1;
+
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ case CUPS_CSPACE_RGBW :
+ c0 = c + k;
+ c1 = m + k;
+ c2 = y + k;
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_RGBW) {
+ if ((k >= frac_1 - 1) ||
+ ((c0 >= frac_1) && (c1 >= frac_1) && (c2 >= frac_1))) {
+ c0 = frac_1;
+ c1 = frac_1;
+ c2 = frac_1;
+ c3 = frac_1;
+ } else
+ c3 = 0;
+ }
+
+ if (c0 < 0)
+ c0 = 0;
+ else if (c0 > frac_1)
+ c0 = frac_1;
+ out[0] = frac_1 - (frac)cups->Density[c0];
+
+ if (c1 < 0)
+ c1 = 0;
+ else if (c1 > frac_1)
+ c1 = frac_1;
+ out[1] = frac_1 - (frac)cups->Density[c1];
+
+ if (c2 < 0)
+ c2 = 0;
+ else if (c2 > frac_1)
+ c2 = frac_1;
+ out[2] = frac_1 - (frac)cups->Density[c2];
+
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_RGBW) {
+ if (c3 == 0)
+ out[3] = frac_1;
+ else if (c3 == frac_1)
+ out[3] = 0;
+ }
+ break;
+
+ default :
+ case CUPS_CSPACE_K :
+ c0 = (c * 31 + m * 61 + y * 8) / 100 + k;
+
+ if (c0 < 0)
+ out[0] = 0;
+ else if (c0 > frac_1)
+ out[0] = (frac)cups->Density[frac_1];
+ else
+ out[0] = (frac)cups->Density[c0];
+ break;
+
+ case CUPS_CSPACE_CMY :
+ c0 = c + k;
+ c1 = m + k;
+ c2 = y + k;
+
+ if (c0 < 0)
+ out[0] = 0;
+ else if (c0 > frac_1)
+ out[0] = (frac)cups->Density[frac_1];
+ else
+ out[0] = (frac)cups->Density[c0];
+
+ if (c1 < 0)
+ out[1] = 0;
+ else if (c1 > frac_1)
+ out[1] = (frac)cups->Density[frac_1];
+ else
+ out[1] = (frac)cups->Density[c1];
+
+ if (c2 < 0)
+ out[2] = 0;
+ else if (c2 > frac_1)
+ out[2] = (frac)cups->Density[frac_1];
+ else
+ out[2] = (frac)cups->Density[c2];
+ break;
+
+ case CUPS_CSPACE_YMC :
+ c0 = y + k;
+ c1 = m + k;
+ c2 = c + k;
+
+ if (c0 < 0)
+ out[0] = 0;
+ else if (c0 > frac_1)
+ out[0] = (frac)cups->Density[frac_1];
+ else
+ out[0] = (frac)cups->Density[c0];
+
+ if (c1 < 0)
+ out[1] = 0;
+ else if (c1 > frac_1)
+ out[1] = (frac)cups->Density[frac_1];
+ else
+ out[1] = (frac)cups->Density[c1];
+
+ if (c2 < 0)
+ out[2] = 0;
+ else if (c2 > frac_1)
+ out[2] = (frac)cups->Density[frac_1];
+ else
+ out[2] = (frac)cups->Density[c2];
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ if (c < 0)
+ out[0] = 0;
+ else if (c > frac_1)
+ out[0] = (frac)cups->Density[frac_1];
+ else
+ out[0] = (frac)cups->Density[c];
+
+ if (m < 0)
+ out[1] = 0;
+ else if (m > frac_1)
+ out[1] = (frac)cups->Density[frac_1];
+ else
+ out[1] = (frac)cups->Density[m];
+
+ if (y < 0)
+ out[2] = 0;
+ else if (y > frac_1)
+ out[2] = (frac)cups->Density[frac_1];
+ else
+ out[2] = (frac)cups->Density[y];
+
+ if (k < 0)
+ out[3] = 0;
+ else if (k > frac_1)
+ out[3] = (frac)cups->Density[frac_1];
+ else
+ out[3] = (frac)cups->Density[k];
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ if (y < 0)
+ out[0] = 0;
+ else if (y > frac_1)
+ out[0] = (frac)cups->Density[frac_1];
+ else
+ out[0] = (frac)cups->Density[y];
+
+ if (m < 0)
+ out[1] = 0;
+ else if (m > frac_1)
+ out[1] = (frac)cups->Density[frac_1];
+ else
+ out[1] = (frac)cups->Density[m];
+
+ if (c < 0)
+ out[2] = 0;
+ else if (c > frac_1)
+ out[2] = (frac)cups->Density[frac_1];
+ else
+ out[2] = (frac)cups->Density[c];
+
+ if (k < 0)
+ out[3] = 0;
+ else if (k > frac_1)
+ out[3] = (frac)cups->Density[frac_1];
+ else
+ out[3] = (frac)cups->Density[k];
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ case CUPS_CSPACE_KCMY :
+ if (k < 0)
+ out[0] = 0;
+ else if (k > frac_1)
+ out[0] = (frac)cups->Density[frac_1];
+ else
+ out[0] = (frac)cups->Density[k];
+
+ if (c < 0)
+ out[1] = 0;
+ else if (c > frac_1)
+ out[1] = (frac)cups->Density[frac_1];
+ else
+ out[1] = (frac)cups->Density[c];
+
+ if (m < 0)
+ out[2] = 0;
+ else if (m > frac_1)
+ out[2] = (frac)cups->Density[frac_1];
+ else
+ out[2] = (frac)cups->Density[m];
+
+ if (y < 0)
+ out[3] = 0;
+ else if (y > frac_1)
+ out[3] = (frac)cups->Density[frac_1];
+ else
+ out[3] = (frac)cups->Density[y];
+ break;
+
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ /*
+ * Convert CMYK to sRGB...
+ */
+
+ c0 = frac_1 - c - k;
+ c1 = frac_1 - m - k;
+ c2 = frac_1 - y - k;
+
+ if (c0 < 0)
+ c0 = 0;
+
+ if (c1 < 0)
+ c1 = 0;
+
+ if (c2 < 0)
+ c2 = 0;
+
+ /*
+ * Convert sRGB to linear RGB...
+ */
+
+ rr = pow(((double)c0 / (double)frac_1 + 0.055) / 1.055, 2.4);
+ rg = pow(((double)c1 / (double)frac_1 + 0.055) / 1.055, 2.4);
+ rb = pow(((double)c2 / (double)frac_1 + 0.055) / 1.055, 2.4);
+
+ /*
+ * Convert to CIE XYZ...
+ */
+
+ ciex = 0.412453 * rr + 0.357580 * rg + 0.180423 * rb;
+ ciey = 0.212671 * rr + 0.715160 * rg + 0.072169 * rb;
+ ciez = 0.019334 * rr + 0.119193 * rg + 0.950227 * rb;
+
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_CIEXYZ)
+ {
+ /*
+ * Convert to an integer XYZ color value...
+ */
+
+ if (cups->header.cupsBitsPerColor == 8)
+ {
+ if (ciex <= 0.0f)
+ c0 = 0;
+ else if (ciex < 1.1)
+ c0 = (int)(ciex * 231.8181 + 0.5);
+ else
+ c0 = 255;
+
+ if (ciey <= 0.0f)
+ c1 = 0;
+ else if (ciey < 1.1)
+ c1 = (int)(ciey * 231.8181 + 0.5);
+ else
+ c1 = 255;
+
+ if (ciez <= 0.0f)
+ c2 = 0;
+ else if (ciez < 1.1)
+ c2 = (int)(ciez * 231.8181 + 0.5);
+ else
+ c2 = 255;
+ }
+ else
+ {
+ if (ciex <= 0.0f)
+ c0 = 0;
+ else if (ciex < 1.1)
+ c0 = (int)(ciex * 59577.2727 + 0.5);
+ else
+ c0 = 65535;
+
+ if (ciey <= 0.0f)
+ c1 = 0;
+ else if (ciey < 1.1)
+ c1 = (int)(ciey * 59577.2727 + 0.5);
+ else
+ c1 = 65535;
+
+ if (ciez <= 0.0f)
+ c2 = 0;
+ else if (ciez < 1.1)
+ c2 = (int)(ciez * 59577.2727 + 0.5);
+ else
+ c2 = 65535;
+ }
+ }
+ else
+ {
+ /*
+ * Convert CIE XYZ to Lab...
+ */
+
+ ciey_yn = ciey / D65_Y;
+
+ if (ciey_yn > 0.008856)
+ ciel = 116 * cbrt(ciey_yn) - 16;
+ else
+ ciel = 903.3 * ciey_yn;
+
+ ciea = 500 * (cups_map_cielab(ciex, D65_X) -
+ cups_map_cielab(ciey, D65_Y));
+ cieb = 200 * (cups_map_cielab(ciey, D65_Y) -
+ cups_map_cielab(ciez, D65_Z));
+
+ if (cups->header.cupsBitsPerColor == 8)
+ {
+ /*
+ * Scale the L value and bias the a and b values by 128
+ * so that all values are in the range of 0 to 255.
+ */
+
+ ciel = ciel * 2.55 + 0.5;
+ ciea += 128.5;
+ cieb += 128.5;
+
+ if (ciel <= 0.0)
+ c0 = 0;
+ else if (ciel < 255.0)
+ c0 = (int)ciel;
+ else
+ c0 = 255;
+
+ if (ciea <= 0.0)
+ c1 = 0;
+ else if (ciea < 255.0)
+ c1 = (int)ciea;
+ else
+ c1 = 255;
+
+ if (cieb <= 0.0)
+ c2 = 0;
+ else if (cieb < 255.0)
+ c2 = (int)cieb;
+ else
+ c2 = 255;
+ }
+ else
+ {
+ /*
+ * Scale the L value and bias the a and b values by 128 so that all
+ * numbers are from 0 to 65535.
+ */
+
+ ciel = ciel * 655.35 + 0.5;
+ ciea = (ciea + 128.0) * 256.0 + 0.5;
+ cieb = (cieb + 128.0) * 256.0 + 0.5;
+
+ /*
+ * Output 16-bit values...
+ */
+
+ if (ciel <= 0.0)
+ c0 = 0;
+ else if (ciel < 65535.0)
+ c0 = (int)ciel;
+ else
+ c0 = 65535;
+
+ if (ciea <= 0.0)
+ c1 = 0;
+ else if (ciea < 65535.0)
+ c1 = (int)ciea;
+ else
+ c1 = 65535;
+
+ if (cieb <= 0.0)
+ c2 = 0;
+ else if (cieb < 65535.0)
+ c2 = (int)cieb;
+ else
+ c2 = 65535;
+ }
+ }
+
+ out[0] = cups->DecodeLUT[c0];
+ out[1] = cups->DecodeLUT[c1];
+ out[2] = cups->DecodeLUT[c2];
+ break;
+# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ }
+
+#ifdef CUPS_DEBUG2
+ switch (cups->color_info.num_components)
+ {
+ default :
+ case 1 :
+ dmprintf1(pdev->memory, "DEBUG2: \\=== COLOR %d\n", out[0]);
+ break;
+
+ case 3 :
+ dmprintf3(pdev->memory, "DEBUG2: \\=== COLOR %d, %d, %d\n",
+ out[0], out[1], out[2]);
+ break;
+
+ case 4 :
+ dmprintf4(pdev->memory, "DEBUG2: \\=== COLOR %d, %d, %d, %d\n",
+ out[0], out[1], out[2], out[3]);
+ break;
+ }
+#endif /* CUPS_DEBUG2 */
+}
+
+
+/*
+ * 'cups_map_gray()' - Map a grayscale value to device colors.
+ */
+
+private void
+cups_map_gray(gx_device *pdev, /* I - Device info */
+ frac g, /* I - Grayscale value */
+ frac *out) /* O - Device colors */
+{
+#ifdef CUPS_DEBUG22
+ dmprintf3(pdev->memory, "DEBUG2: cups_map_gray(%p, %d, %p)\n",
+ pdev, g, out);
+#endif /* CUPS_DEBUG22 */
+
+ /*
+ * Just use the CMYK mapper...
+ */
+
+ cups_map_cmyk(pdev, 0, 0, 0, frac_1 - g, out);
+}
+
+
+/*
+ * 'cups_map_rgb()' - Map a RGB color value to device colors.
+ */
+
+private void
+cups_map_rgb(gx_device *pdev,
+ /* I - Device info */
+ const gs_gstate *pgs,/* I - Device state */
+ frac r, /* I - Red value */
+ frac g, /* I - Green value */
+ frac b, /* I - Blue value */
+ frac *out)/* O - Device colors */
+{
+ frac c, m, y, k; /* CMYK values */
+ frac mk; /* Maximum K value */
+ int tc, tm, ty; /* Temporary color values */
+
+
+#ifdef CUPS_DEBUG2
+ dmprintf6(pdev->memory, "DEBUG2: cups_map_rgb(%p, %p, %d, %d, %d, %p)\n",
+ pdev, pgs, r, g, b, out);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Compute CMYK values...
+ */
+
+ c = frac_1 - r;
+ m = frac_1 - g;
+ y = frac_1 - b;
+ k = min(c, min(m, y));
+
+ if ((mk = max(c, max(m, y))) > k)
+ k = (int)((float)k * (float)k * (float)k / ((float)mk * (float)mk));
+
+ c -= k;
+ m -= k;
+ y -= k;
+
+ /*
+ * Do color correction as needed...
+ */
+
+ if (cups->HaveProfile)
+ {
+ /*
+ * Color correct CMY...
+ */
+
+ tc = cups->Matrix[0][0][c] +
+ cups->Matrix[0][1][m] +
+ cups->Matrix[0][2][y];
+ tm = cups->Matrix[1][0][c] +
+ cups->Matrix[1][1][m] +
+ cups->Matrix[1][2][y];
+ ty = cups->Matrix[2][0][c] +
+ cups->Matrix[2][1][m] +
+ cups->Matrix[2][2][y];
+
+ if (tc < 0)
+ c = 0;
+ else if (tc > frac_1)
+ c = frac_1;
+ else
+ c = (frac)tc;
+
+ if (tm < 0)
+ m = 0;
+ else if (tm > frac_1)
+ m = frac_1;
+ else
+ m = (frac)tm;
+
+ if (ty < 0)
+ y = 0;
+ else if (ty > frac_1)
+ y = frac_1;
+ else
+ y = (frac)ty;
+ }
+
+ /*
+ * Use the CMYK mapping function to produce the device colors...
+ */
+
+ cups_map_cmyk(pdev, c, m, y, k, out);
+}
+#else
+/*
+ * 'cups_map_cmyk_color()' - Map a CMYK color to a color index.
+ *
+ * This function is only called when a 4 or 6 color colorspace is
+ * selected for output. CMYK colors are *not* corrected but *are*
+ * density adjusted.
+ */
+
+private gx_color_index /* O - Color index */
+cups_map_cmyk_color(gx_device *pdev,
+ /* I - Device info */
+ const gx_color_value cv[4])/* I - CMYK color values */
+{
+ gx_color_index i; /* Temporary index */
+ gx_color_value c, m, y, k;
+ gx_color_value ic, im, iy, ik; /* Integral CMYK values */
+
+ c = cv[0];
+ m = cv[1];
+ y = cv[2];
+ k = cv[3];
+
+#ifdef CUPS_DEBUG2
+ dmprintf5(pdev->memory, "DEBUG2: cups_map_cmyk_color(%p, %d, %d, %d, %d)\n",
+ pdev, c, m, y, k);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Setup the color info data as needed...
+ */
+
+ if (pdev->color_info.num_components == 0) {
+ if (cups_set_color_info(pdev) < 0)
+ return(gx_no_color_index);
+ }
+
+ /*
+ * Density correct...
+ */
+
+ if (cups->HaveProfile)
+ {
+ c = cups->Density[c];
+ m = cups->Density[m];
+ y = cups->Density[y];
+ k = cups->Density[k];
+ }
+
+ ic = cups->EncodeLUT[c];
+ im = cups->EncodeLUT[m];
+ iy = cups->EncodeLUT[y];
+ ik = cups->EncodeLUT[k];
+
+ /*
+ * Convert the CMYK color to a color index...
+ */
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((ic << 1) | im) << 1) | iy) << 1) | ik;
+ break;
+ case 2 :
+ i = (((((ic << 2) | im) << 2) | iy) << 2) | ik;
+ break;
+ case 4 :
+ i = (((((ic << 4) | im) << 4) | iy) << 4) | ik;
+ break;
+ case 8 :
+ i = (((((ic << 8) | im) << 8) | iy) << 8) | ik;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((ic << 16) | im) << 16) | iy) << 16) | ik;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((iy << 1) | im) << 1) | ic) << 1) | ik;
+ break;
+ case 2 :
+ i = (((((iy << 2) | im) << 2) | ic) << 2) | ik;
+ break;
+ case 4 :
+ i = (((((iy << 4) | im) << 4) | ic) << 4) | ik;
+ break;
+ case 8 :
+ i = (((((iy << 8) | im) << 8) | ic) << 8) | ik;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((iy << 16) | im) << 16) | ic) << 16) | ik;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ if (cups->header.cupsBitsPerColor == 1)
+ {
+ if (ik)
+ i = 32;
+ else
+ i = 0;
+
+ if (ic && im)
+ i |= 17;
+ else if (ic && iy)
+ i |= 6;
+ else if (im && iy)
+ i |= 12;
+ else if (ic)
+ i |= 16;
+ else if (im)
+ i |= 8;
+ else if (iy)
+ i |= 4;
+ break;
+ }
+
+ case CUPS_CSPACE_KCMY :
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((ik << 1) | ic) << 1) | im) << 1) | iy;
+ break;
+ case 2 :
+ i = (((((ik << 2) | ic) << 2) | im) << 2) | iy;
+ break;
+ case 4 :
+ i = (((((ik << 4) | ic) << 4) | im) << 4) | iy;
+ break;
+ case 8 :
+ i = (((((ik << 8) | ic) << 8) | im) << 8) | iy;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((ik << 16) | ic) << 16) | im) << 16) | iy;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+ }
+
+#ifdef CUPS_DEBUG2
+ dmprintf9(pdev->memory, "DEBUG2: CMYK (%d,%d,%d,%d) -> CMYK %08x (%d,%d,%d,%d)\n",
+ c, m, y, k, (unsigned)i, ic, im, iy, ik);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Make sure we don't get a CMYK color of 255, 255, 255, 255...
+ */
+
+ if (i == gx_no_color_index)
+ i --;
+
+ return (i);
+}
+
+
+/*
+ * 'cups_map_color_rgb()' - Map a color index to an RGB color.
+ */
+
+private int
+cups_map_color_rgb(gx_device *pdev,/* I - Device info */
+ gx_color_index color,/* I - Color index */
+ gx_color_value prgb[3])
+ /* O - RGB values */
+{
+ unsigned char c0, c1, c2, c3; /* Color index components */
+ gx_color_value c, m, y, k, divk; /* Colors, Black & divisor */
+
+
+#ifdef CUPS_DEBUG2
+ dmprintf3(pdev->memory, "DEBUG2: cups_map_color_rgb(%p, %d, %p)\n", pdev,
+ (unsigned)color, prgb);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Setup the color info data as needed...
+ */
+
+ if (pdev->color_info.num_components == 0) {
+ if (cups_set_color_info(pdev) < 0)
+ return(gx_no_color_index);
+ }
+
+#ifdef CUPS_DEBUG2
+ dmprintf1(pdev->memory, "DEBUG2: COLOR %08x = ", (unsigned)color);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Extract the color components from the color index...
+ */
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ c3 = color & 1;
+ color >>= 1;
+ c2 = color & 1;
+ color >>= 1;
+ c1 = color & 1;
+ color >>= 1;
+ c0 = color;
+ break;
+ case 2 :
+ c3 = color & 3;
+ color >>= 2;
+ c2 = color & 3;
+ color >>= 2;
+ c1 = color & 3;
+ color >>= 2;
+ c0 = color;
+ break;
+ case 4 :
+ c3 = color & 15;
+ color >>= 4;
+ c2 = color & 15;
+ color >>= 4;
+ c1 = color & 15;
+ color >>= 4;
+ c0 = color;
+ break;
+ case 8 :
+ c3 = color & 255;
+ color >>= 8;
+ c2 = color & 255;
+ color >>= 8;
+ c1 = color & 255;
+ color >>= 8;
+ c0 = color;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ c3 = color & 0xffff;
+ color >>= 16;
+ c2 = color & 0xffff;
+ color >>= 16;
+ c1 = color & 0xffff;
+ color >>= 16;
+ c0 = color;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+
+ /*
+ * Convert the color components to RGB...
+ */
+
+ switch (cups->header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ prgb[0] =
+ prgb[1] =
+ prgb[2] = cups->DecodeLUT[c3];
+ break;
+
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ prgb[0] =
+ prgb[1] =
+ prgb[2] = cups->DecodeLUT[c3];
+ break;
+
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ prgb[0] = cups->DecodeLUT[c1];
+ prgb[1] = cups->DecodeLUT[c2];
+ prgb[2] = cups->DecodeLUT[c3];
+ break;
+
+ case CUPS_CSPACE_RGBA :
+ prgb[0] = cups->DecodeLUT[c0];
+ prgb[1] = cups->DecodeLUT[c1];
+ prgb[2] = cups->DecodeLUT[c2];
+ break;
+
+ case CUPS_CSPACE_CMY :
+ prgb[0] = cups->DecodeLUT[c1];
+ prgb[1] = cups->DecodeLUT[c2];
+ prgb[2] = cups->DecodeLUT[c3];
+ break;
+
+ case CUPS_CSPACE_YMC :
+ prgb[0] = cups->DecodeLUT[c3];
+ prgb[1] = cups->DecodeLUT[c2];
+ prgb[2] = cups->DecodeLUT[c1];
+ break;
+
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ k = cups->DecodeLUT[c0];
+ divk = gx_max_color_value - k;
+ if (divk == 0)
+ {
+ prgb[0] = 0;
+ prgb[1] = 0;
+ prgb[2] = 0;
+ }
+ else
+ {
+ prgb[0] = gx_max_color_value + divk -
+ gx_max_color_value * c1 / divk;
+ prgb[1] = gx_max_color_value + divk -
+ gx_max_color_value * c2 / divk;
+ prgb[2] = gx_max_color_value + divk -
+ gx_max_color_value * c3 / divk;
+ }
+ break;
+
+ case CUPS_CSPACE_RGBW :
+ /*
+ * cups->DecodeLUT actually maps to RGBW, not CMYK...
+ */
+
+ if (c3 == 0) {
+ c = 0;
+ m = 0;
+ y = 0;
+ } else {
+ c = cups->DecodeLUT[c0];
+ m = cups->DecodeLUT[c1];
+ y = cups->DecodeLUT[c2];
+ }
+
+ if (c > gx_max_color_value)
+ prgb[0] = gx_max_color_value;
+ else if (c < 0)
+ prgb[0] = 0;
+ else
+ prgb[0] = c;
+
+ if (m > gx_max_color_value)
+ prgb[1] = gx_max_color_value;
+ else if (m < 0)
+ prgb[1] = 0;
+ else
+ prgb[1] = m;
+
+ if (y > gx_max_color_value)
+ prgb[2] = gx_max_color_value;
+ else if (y < 0)
+ prgb[2] = 0;
+ else
+ prgb[2] = y;
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ k = cups->DecodeLUT[c3];
+ divk = gx_max_color_value - k;
+ if (divk == 0)
+ {
+ prgb[0] = 0;
+ prgb[1] = 0;
+ prgb[2] = 0;
+ }
+ else
+ {
+ prgb[0] = gx_max_color_value + divk -
+ gx_max_color_value * c0 / divk;
+ prgb[1] = gx_max_color_value + divk -
+ gx_max_color_value * c1 / divk;
+ prgb[2] = gx_max_color_value + divk -
+ gx_max_color_value * c2 / divk;
+ }
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ k = cups->DecodeLUT[c3];
+ divk = gx_max_color_value - k;
+ if (divk == 0)
+ {
+ prgb[0] = 0;
+ prgb[1] = 0;
+ prgb[2] = 0;
+ }
+ else
+ {
+ prgb[0] = gx_max_color_value + divk -
+ gx_max_color_value * c2 / divk;
+ prgb[1] = gx_max_color_value + divk -
+ gx_max_color_value * c1 / divk;
+ prgb[2] = gx_max_color_value + divk -
+ gx_max_color_value * c0 / divk;
+ }
+ break;
+
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ break;
+# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ }
+
+#ifdef CUPS_DEBUG2
+ dmprintf3(pdev->memory, "DEBUG2: RGB values: %d,%d,%d\n",
+ prgb[0], prgb[1], prgb[2]);
+#endif /* CUPS_DEBUG2 */
+
+ return (0);
+}
+
+
+/*
+ * 'cups_map_rgb_color()' - Map an RGB color to a color index. We map the
+ * RGB color to the output colorspace & bits (we
+ * figure out the format when we output a page).
+ */
+
+private gx_color_index /* O - Color index */
+cups_map_rgb_color(gx_device *pdev,/* I - Device info */
+ const gx_color_value cv[3])/* I - RGB color values */
+{
+ gx_color_index i; /* Temporary index */
+ gx_color_value r, g, b;
+ gx_color_value ic, im, iy, ik; /* Integral CMYK values */
+ gx_color_value mk; /* Maximum K value */
+ int tc, tm, ty; /* Temporary color values */
+ float rr, rg, rb, /* Real RGB colors */
+ ciex, ciey, ciez,
+ /* CIE XYZ colors */
+ ciey_yn, /* Normalized luminance */
+ ciel, ciea, cieb;
+ /* CIE Lab colors */
+
+ r = cv[0];
+ g = cv[1];
+ b = cv[2];
+
+#ifdef CUPS_DEBUG2
+ dmprintf4(pdev->memory, "DEBUG2: cups_map_rgb_color(%p, %d, %d, %d)\n",
+ pdev, r, g, b);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Setup the color info data as needed...
+ */
+
+ if (pdev->color_info.num_components == 0) {
+ if (cups_set_color_info(pdev) < 0)
+ return(gx_no_color_index);
+ }
+
+ /*
+ * Do color correction as needed...
+ */
+
+ if (cups->HaveProfile)
+ {
+ /*
+ * Compute CMYK values...
+ */
+
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik / ((float)mk * (float)mk));
+
+ ic -= ik;
+ im -= ik;
+ iy -= ik;
+
+ /*
+ * Color correct CMY...
+ */
+
+ tc = cups->Matrix[0][0][ic] +
+ cups->Matrix[0][1][im] +
+ cups->Matrix[0][2][iy] +
+ ik;
+ tm = cups->Matrix[1][0][ic] +
+ cups->Matrix[1][1][im] +
+ cups->Matrix[1][2][iy] +
+ ik;
+ ty = cups->Matrix[2][0][ic] +
+ cups->Matrix[2][1][im] +
+ cups->Matrix[2][2][iy] +
+ ik;
+
+ /*
+ * Density correct combined CMYK...
+ */
+
+ if (tc < 0)
+ r = gx_max_color_value;
+ else if (tc > gx_max_color_value)
+ r = gx_max_color_value - cups->Density[gx_max_color_value];
+ else
+ r = gx_max_color_value - cups->Density[tc];
+
+ if (tm < 0)
+ g = gx_max_color_value;
+ else if (tm > gx_max_color_value)
+ g = gx_max_color_value - cups->Density[gx_max_color_value];
+ else
+ g = gx_max_color_value - cups->Density[tm];
+
+ if (ty < 0)
+ b = gx_max_color_value;
+ else if (ty > gx_max_color_value)
+ b = gx_max_color_value - cups->Density[gx_max_color_value];
+ else
+ b = gx_max_color_value - cups->Density[ty];
+ }
+
+ /*
+ * Convert the RGB color to a color index...
+ */
+
+ switch (cups->header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ i = cups->EncodeLUT[(r * 31 + g * 61 + b * 8) / 100];
+ break;
+
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ ic = cups->EncodeLUT[r];
+ im = cups->EncodeLUT[g];
+ iy = cups->EncodeLUT[b];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((ic << 1) | im) << 1) | iy;
+ break;
+ case 2 :
+ i = (((ic << 2) | im) << 2) | iy;
+ break;
+ case 4 :
+ i = (((ic << 4) | im) << 4) | iy;
+ break;
+ case 8 :
+ i = (((ic << 8) | im) << 8) | iy;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((ic << 16) | im) << 16) | iy;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+ case CUPS_CSPACE_RGBW :
+ if (!r && !g && !b)
+ {
+ /*
+ * Map black to W...
+ */
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = 0x00;
+ break;
+ case 2 :
+ i = 0x00;
+ break;
+ case 4 :
+ i = 0x0000;
+ break;
+ case 8 :
+ i = 0x00000000;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = 0x0000000000000000;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+ }
+
+ case CUPS_CSPACE_RGBA :
+ ic = cups->EncodeLUT[r];
+ im = cups->EncodeLUT[g];
+ iy = cups->EncodeLUT[b];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((ic << 1) | im) << 1) | iy) << 1) | 0x01;
+ break;
+ case 2 :
+ i = (((((ic << 2) | im) << 2) | iy) << 2) | 0x03;
+ break;
+ case 4 :
+ i = (((((ic << 4) | im) << 4) | iy) << 4) | 0x0f;
+ break;
+ case 8 :
+ i = (((((ic << 8) | im) << 8) | iy) << 8) | 0xff;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((ic << 16) | im) << 16) | iy) << 16) | 0xffff;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+ default :
+ i = cups->EncodeLUT[gx_max_color_value - (r * 31 + g * 61 + b * 8) / 100];
+ break;
+
+ case CUPS_CSPACE_CMY :
+ ic = cups->EncodeLUT[gx_max_color_value - r];
+ im = cups->EncodeLUT[gx_max_color_value - g];
+ iy = cups->EncodeLUT[gx_max_color_value - b];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((ic << 1) | im) << 1) | iy;
+ break;
+ case 2 :
+ i = (((ic << 2) | im) << 2) | iy;
+ break;
+ case 4 :
+ i = (((ic << 4) | im) << 4) | iy;
+ break;
+ case 8 :
+ i = (((ic << 8) | im) << 8) | iy;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((ic << 16) | im) << 16) | iy;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+ case CUPS_CSPACE_YMC :
+ ic = cups->EncodeLUT[gx_max_color_value - r];
+ im = cups->EncodeLUT[gx_max_color_value - g];
+ iy = cups->EncodeLUT[gx_max_color_value - b];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((iy << 1) | im) << 1) | ic;
+ break;
+ case 2 :
+ i = (((iy << 2) | im) << 2) | ic;
+ break;
+ case 4 :
+ i = (((iy << 4) | im) << 4) | ic;
+ break;
+ case 8 :
+ i = (((iy << 8) | im) << 8) | ic;
+ break;
+ }
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)mk));
+
+ ic = cups->EncodeLUT[ic - ik];
+ im = cups->EncodeLUT[im - ik];
+ iy = cups->EncodeLUT[iy - ik];
+ ik = cups->EncodeLUT[ik];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((ic << 1) | im) << 1) | iy) << 1) | ik;
+ break;
+ case 2 :
+ i = (((((ic << 2) | im) << 2) | iy) << 2) | ik;
+ break;
+ case 4 :
+ i = (((((ic << 4) | im) << 4) | iy) << 4) | ik;
+ break;
+ case 8 :
+ i = (((((ic << 8) | im) << 8) | iy) << 8) | ik;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((ic << 16) | im) << 16) | iy) << 16) | ik;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+
+#ifdef CUPS_DEBUG2
+ dmprintf8(pdev->memory, "DEBUG2: CMY (%d,%d,%d) -> CMYK %08x (%d,%d,%d,%d)\n",
+ r, g, b, (unsigned)i, ic, im, iy, ik);
+#endif /* CUPS_DEBUG2 */
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)mk));
+
+ ic = cups->EncodeLUT[ic - ik];
+ im = cups->EncodeLUT[im - ik];
+ iy = cups->EncodeLUT[iy - ik];
+ ik = cups->EncodeLUT[ik];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((iy << 1) | im) << 1) | ic) << 1) | ik;
+ break;
+ case 2 :
+ i = (((((iy << 2) | im) << 2) | ic) << 2) | ik;
+ break;
+ case 4 :
+ i = (((((iy << 4) | im) << 4) | ic) << 4) | ik;
+ break;
+ case 8 :
+ i = (((((iy << 8) | im) << 8) | ic) << 8) | ik;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((iy << 16) | im) << 16) | ic) << 16) | ik;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ if (cups->header.cupsBitsPerColor == 1)
+ {
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)mk));
+
+ ic = cups->EncodeLUT[ic - ik];
+ im = cups->EncodeLUT[im - ik];
+ iy = cups->EncodeLUT[iy - ik];
+ ik = cups->EncodeLUT[ik];
+ if (ik)
+ i = 32;
+ else if (ic && im)
+ i = 17;
+ else if (ic && iy)
+ i = 6;
+ else if (im && iy)
+ i = 12;
+ else if (ic)
+ i = 16;
+ else if (im)
+ i = 8;
+ else if (iy)
+ i = 4;
+ else
+ i = 0;
+ break;
+ }
+
+ case CUPS_CSPACE_KCMY :
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)mk));
+
+ ic = cups->EncodeLUT[ic - ik];
+ im = cups->EncodeLUT[im - ik];
+ iy = cups->EncodeLUT[iy - ik];
+ ik = cups->EncodeLUT[ik];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((ik << 1) | ic) << 1) | im) << 1) | iy;
+ break;
+ case 2 :
+ i = (((((ik << 2) | ic) << 2) | im) << 2) | iy;
+ break;
+ case 4 :
+ i = (((((ik << 4) | ic) << 4) | im) << 4) | iy;
+ break;
+ case 8 :
+ i = (((((ik << 8) | ic) << 8) | im) << 8) | iy;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((((ik << 16) | ic) << 16) | im) << 16) | iy;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ /*
+ * Convert sRGB to linear RGB...
+ */
+
+ rr = pow(((double)r / (double)gx_max_color_value + 0.055) / 1.055, 2.4);
+ rg = pow(((double)g / (double)gx_max_color_value + 0.055) / 1.055, 2.4);
+ rb = pow(((double)b / (double)gx_max_color_value + 0.055) / 1.055, 2.4);
+
+ /*
+ * Convert to CIE XYZ...
+ */
+
+ ciex = 0.412453 * rr + 0.357580 * rg + 0.180423 * rb;
+ ciey = 0.212671 * rr + 0.715160 * rg + 0.072169 * rb;
+ ciez = 0.019334 * rr + 0.119193 * rg + 0.950227 * rb;
+
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_CIEXYZ)
+ {
+ /*
+ * Convert to an integer XYZ color value...
+ */
+
+ if (ciex > 1.1)
+ ic = 255;
+ else if (ciex > 0.0)
+ ic = (int)(ciex / 1.1 * 255.0 + 0.5);
+ else
+ ic = 0;
+
+ if (ciey > 1.1)
+ im = 255;
+ else if (ciey > 0.0)
+ im = (int)(ciey / 1.1 * 255.0 + 0.5);
+ else
+ im = 0;
+
+ if (ciez > 1.1)
+ iy = 255;
+ else if (ciez > 0.0)
+ iy = (int)(ciez / 1.1 * 255.0 + 0.5);
+ else
+ iy = 0;
+ }
+ else
+ {
+ /*
+ * Convert CIE XYZ to Lab...
+ */
+
+ ciey_yn = ciey / D65_Y;
+
+ if (ciey_yn > 0.008856)
+ ciel = 116 * cbrt(ciey_yn) - 16;
+ else
+ ciel = 903.3 * ciey_yn;
+
+ ciea = 500 * (cups_map_cielab(ciex, D65_X) -
+ cups_map_cielab(ciey, D65_Y));
+ cieb = 200 * (cups_map_cielab(ciey, D65_Y) -
+ cups_map_cielab(ciez, D65_Z));
+
+ /*
+ * Scale the L value and bias the a and b values by 128
+ * so that all values are in the range of 0 to 255.
+ */
+
+ ciel = ciel * 2.55 + 0.5;
+ ciea += 128.5;
+ cieb += 128.5;
+
+ /*
+ * Convert to 8-bit values...
+ */
+
+ if (ciel < 0.0)
+ ic = 0;
+ else if (ciel < 255.0)
+ ic = (int)ciel;
+ else
+ ic = 255;
+
+ if (ciea < 0.0)
+ im = 0;
+ else if (ciea < 255.0)
+ im = (int)ciea;
+ else
+ im = 255;
+
+ if (cieb < 0.0)
+ iy = 0;
+ else if (cieb < 255.0)
+ iy = (int)cieb;
+ else
+ iy = 255;
+ }
+
+ /*
+ * Put the final color value together...
+ */
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((ic << 1) | im) << 1) | iy;
+ break;
+ case 2 :
+ i = (((ic << 2) | im) << 2) | iy;
+ break;
+ case 4 :
+ i = (((ic << 4) | im) << 4) | iy;
+ break;
+ case 8 :
+ i = (((ic << 8) | im) << 8) | iy;
+ break;
+#ifdef GX_COLOR_INDEX_TYPE
+ case 16 :
+ i = (((ic << 16) | im) << 16) | iy;
+ break;
+#endif /* GX_COLOR_INDEX_TYPE */
+ }
+ break;
+# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ }
+
+#ifdef CUPS_DEBUG2
+ dmprintf4(pdev->memory, "DEBUG2: RGB %d,%d,%d = %08x\n",
+ r, g, b, (unsigned)i);
+#endif /* CUPS_DEBUG2 */
+
+ return (i);
+}
+#endif /* dev_t_proc_encode_color */
+
+
+/*
+ * 'cups_open()' - Open the output file and initialize things.
+ */
+
+private int /* O - Error status */
+cups_open(gx_device *pdev) /* I - Device info */
+{
+ int code; /* Return status */
+
+#ifdef CUPS_DEBUG2
+ dmprintf1(pdev->memory, "DEBUG2: cups_open(%p)\n", pdev);
+#endif /* CUPS_DEBUG2 */
+
+ dmprintf(pdev->memory, "INFO: Start rendering...\n");
+ cups->printer_procs.get_space_params = cups_get_space_params;
+
+ if (cups->page == 0)
+ {
+ dmprintf(pdev->memory, "INFO: Processing page 1...\n");
+ cups->page = 1;
+ }
+
+ if ((code = cups_set_color_info(pdev)) < 0) {
+ return(code);
+ }
+
+ /* Establish the default LeadingEdge in the cups header */
+ cups->header.LeadingEdge = (cups_edge_t)(pdev->LeadingEdge & LEADINGEDGE_MASK);
+
+ if ((code = gdev_prn_open(pdev)) != 0)
+ return(code);
+
+ if (cups->PPD == NULL)
+ cups->PPD = ppdOpenFile(getenv("PPD"));
+
+ if (cups->pageSizeRequested[0] == '\0') {
+ strncpy(cups->pageSizeRequested, cups->header.cupsPageSizeName, 64);
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG: Page size requested: %s\n",
+ cups->header.cupsPageSizeName);
+#endif /* CUPS_DEBUG */
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cups_output_page()' - Send one or more pages to the output file.
+ * The changes to the cups->page are done here for background printing
+ * but testing shows some regressions, so BGPrint is not used for now.
+ */
+
+private int /* O - 0 if everything is OK */
+cups_output_page(gx_device *pdev, int num_copies, int flush)
+{
+ int code = 0; /* Error code */
+
+ /* FIXME: We would like to support BGPrint=true and call gdev_prn_bg_output_page */
+ /* but there must still be other things that prevent this. */
+ if ((code = gdev_prn_output_page(pdev, num_copies, flush)) < 0)
+ return code;
+
+ cups->page ++;
+ dmprintf1(pdev->memory, "INFO: Processing page %d...\n", cups->page);
+
+ return (0);
+}
+
+
+/*
+ * 'cups_print_pages()' - Send one or more pages to the output file.
+ */
+
+private int /* O - 0 if everything is OK */
+cups_print_pages(gx_device_printer *pdev,
+ /* I - Device info */
+ gp_file *fp, /* I - Output file */
+ int num_copies)
+ /* I - Number of copies */
+{
+ int code = 0; /* Error code */
+ int copy; /* Copy number */
+ int srcbytes; /* Byte width of scanline */
+ unsigned char *src, /* Scanline data */
+ *dst; /* Bitmap data */
+ ppd_attr_t *RasterVersion = NULL; /* CUPS Raster version read from PPD
+ file */
+
+ (void)fp; /* reference unused file pointer to prevent compiler warning */
+
+#ifdef CUPS_DEBUG2
+ dmprintf3(pdev->memory, "DEBUG2: cups_print_pages(%p, %p, %d)\n", pdev, fp,
+ num_copies);
+#endif /* CUPS_DEBUG2 */
+
+ /*
+ * Figure out the number of bytes per line...
+ */
+
+ switch (cups->header.cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerPixel *
+ cups->header.cupsWidth + 7) / 8;
+ break;
+
+ case CUPS_ORDER_BANDED :
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm &&
+ cups->header.cupsBitsPerColor == 1)
+ cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerColor *
+ cups->header.cupsWidth + 7) / 8 * 6;
+ else
+ cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerColor *
+ cups->header.cupsWidth + 7) / 8 *
+ cups->color_info.num_components;
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerColor *
+ cups->header.cupsWidth + 7) / 8;
+ break;
+ }
+
+ /*
+ * Compute the width of a scanline and allocate input/output buffers...
+ */
+
+ srcbytes = gdev_prn_raster(pdev);
+
+#ifdef CUPS_DEBUG2
+ dmprintf4(pdev->memory, "DEBUG2: cupsBitsPerPixel = %d, cupsWidth = %d, cupsBytesPerLine = %d, srcbytes = %d\n",
+ cups->header.cupsBitsPerPixel, cups->header.cupsWidth,
+ cups->header.cupsBytesPerLine, srcbytes);
+#endif /* CUPS_DEBUG2 */
+
+ src = (unsigned char *)gs_malloc(pdev->memory->non_gc_memory, srcbytes, 1, "cups_print_pages");
+
+ if (src == NULL) /* can't allocate input buffer */
+ return_error(gs_error_VMerror);
+
+ memset(src, 0, srcbytes);
+
+ /*
+ * Need an output buffer, too...
+ */
+
+ dst = (unsigned char *)gs_malloc(pdev->memory->non_gc_memory, cups->header.cupsBytesPerLine, 2,
+ "cups_print_pages");
+
+ if (dst == NULL) /* can't allocate working area */
+ return_error(gs_error_VMerror);
+
+ memset(dst, 0, 2 * cups->header.cupsBytesPerLine);
+
+ /*
+ * See if the stream has been initialized yet...
+ */
+
+ if (cups->stream == NULL)
+ {
+ RasterVersion = ppdFindAttr(cups->PPD, "cupsRasterVersion", NULL);
+ if (RasterVersion) {
+#ifdef CUPS_DEBUG2
+ dmprintf1(pdev->memory, "DEBUG2: cupsRasterVersion = %s\n",
+ RasterVersion->value);
+#endif /* CUPS_DEBUG2 */
+ cups->cupsRasterVersion = atoi(RasterVersion->value);
+ if ((cups->cupsRasterVersion != 2) &&
+ (cups->cupsRasterVersion != 3)) {
+ dmprintf1(pdev->memory, "ERROR: Unsupported CUPS Raster Version: %s",
+ RasterVersion->value);
+ return_error(gs_error_unknownerror);
+ }
+ }
+ /* NOTE: PWG Raster output is only available with shared CUPS CUPS and
+ CUPS image libraries as the built-in libraries of Ghostscript do not
+ contain the new code needed for PWG Raster output. This conditional
+ is a temporary workaround for the time being until up-to-date CUPS
+ libraries get included. */
+ if ((cups->stream = cupsRasterOpen(fileno(gp_get_file(cups->file)),
+#if defined(CUPS_RASTER_HAVE_PWGRASTER)
+ (strcasecmp(cups->header.MediaClass,
+ "PwgRaster") == 0 ?
+ CUPS_RASTER_WRITE_PWG :
+ (cups->cupsRasterVersion == 3 ?
+ CUPS_RASTER_WRITE :
+ CUPS_RASTER_WRITE_COMPRESSED)))) ==
+ NULL)
+#else
+ (cups->cupsRasterVersion == 3 ?
+ CUPS_RASTER_WRITE :
+ CUPS_RASTER_WRITE_COMPRESSED))) == NULL)
+#endif
+ {
+ perror("ERROR: Unable to open raster stream - ");
+ return_error(gs_error_ioerror);
+ }
+ }
+
+ /*
+ * Output a page of graphics...
+ */
+
+ if (num_copies < 1)
+ num_copies = 1;
+
+ if (cups->PPD != NULL && !cups->PPD->manual_copies)
+ {
+ cups->header.NumCopies = num_copies;
+ num_copies = 1;
+ }
+
+#ifdef CUPS_DEBUG
+ dmprintf3(pdev->memory, "DEBUG2: cupsWidth = %d, cupsHeight = %d, cupsBytesPerLine = %d\n",
+ cups->header.cupsWidth, cups->header.cupsHeight,
+ cups->header.cupsBytesPerLine);
+#endif /* CUPS_DEBUG */
+
+ for (copy = num_copies; copy > 0; copy --)
+ {
+ cupsRasterWriteHeader(cups->stream, &(cups->header));
+
+ if (pdev->color_info.num_components == 1)
+ code = cups_print_chunked(pdev, src, dst, srcbytes);
+ else
+ switch (cups->header.cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ code = cups_print_chunked(pdev, src, dst, srcbytes);
+ break;
+ case CUPS_ORDER_BANDED :
+ code = cups_print_banded(pdev, src, dst, srcbytes);
+ break;
+ case CUPS_ORDER_PLANAR :
+ code = cups_print_planar(pdev, src, dst, srcbytes);
+ break;
+ }
+ if (code < 0)
+ break;
+ }
+
+ /*
+ * Free temporary storage and return...
+ */
+
+ gs_free(pdev->memory->non_gc_memory, (char *)src, srcbytes, 1, "cups_print_pages");
+ gs_free(pdev->memory->non_gc_memory, (char *)dst, cups->header.cupsBytesPerLine, 1, "cups_print_pages");
+
+ return (code);
+}
+
+
+/*
+ * 'cups_put_params()' - Set pagedevice parameters.
+ */
+
+private int /* O - Error status */
+cups_put_params(gx_device *pdev, /* I - Device info */
+ gs_param_list *plist) /* I - Parameter list */
+{
+ int i; /* Looping var */
+ float mediasize[2]; /* Physical size of print */
+ float margins[4]; /* Physical margins of print */
+ float cups_mediasize[2]; /* Media size to use in Raster */
+ float cups_margins[4]; /* Margins to use in Raster */
+ ppd_size_t *size; /* Page size */
+ int code; /* Error code */
+ int intval; /* Integer value */
+ bool boolval; /* Boolean value */
+ float floatval; /* Floating point value */
+ gs_param_string stringval; /* String value */
+ gs_param_float_array arrayval; /* Float array value */
+ int margins_set; /* Were the margins set? */
+ int size_set; /* Was the size set? */
+ int color_set; /* Were the color attrs set? */
+ gdev_prn_space_params sp_old; /* Space parameter data */
+ int width, /* New width of page */
+ height, /* New height of page */
+ width_old = 0, /* Previous width of page */
+ height_old = 0; /* Previous height of page */
+ bool transp_old = 0; /* Previous transparency usage state */
+ ppd_attr_t *backside = NULL,
+ *backsiderequiresflippedmargins = NULL;
+ float swap;
+ int xflip = 0,
+ yflip = 0;
+ int found = 0;
+ long best_score = -1,
+ score = 0;
+ ppd_size_t *best_size = NULL;
+ int size_matched = 0,
+ margins_matched = 0,
+ imageable_area_matched = 0,
+ name_requested_matched = 0;
+ float long_edge_mismatch, short_edge_mismatch;
+ gs_param_string icc_pro_dummy;
+ int old_cmps = cups->color_info.num_components;
+ int old_depth = cups->color_info.depth;
+#ifdef CUPS_RASTER_SYNCv1
+ float sf; /* cupsBorderlessScalingFactor */
+#endif /* CUPS_RASTER_SYNCv1 */
+
+#ifdef CUPS_DEBUG
+ dmprintf2(pdev->memory, "DEBUG2: cups_put_params(%p, %p)\n", pdev, plist);
+#endif /* CUPS_DEBUG */
+
+ /*
+ * Process other options for CUPS...
+ */
+
+#define stringoption(name, sname) \
+ if ((code = param_read_string(plist, sname, &stringval)) < 0) \
+ { \
+ dmprintf1(pdev->memory, "ERROR: Error setting %s...\n", sname); \
+ param_signal_error(plist, sname, code); \
+ goto done; \
+ } \
+ else if (code == 0) \
+ { \
+ strncpy(cups->header.name, (const char *)(stringval.data), \
+ stringval.size); \
+ cups->header.name[stringval.size] = '\0'; \
+ }
+
+#define intoption(name, sname, type) \
+ if ((code = param_read_int(plist, sname, &intval)) < 0) \
+ { \
+ dmprintf1(pdev->memory, "ERROR: Error setting %s ...\n", sname); \
+ param_signal_error(plist, sname, code); \
+ goto done; \
+ } \
+ else if (code == 0) \
+ { \
+ cups->header.name = (type)intval; \
+ }
+
+#define floatoption(name, sname) \
+ if ((code = param_read_float(plist, sname, &floatval)) < 0) \
+ { \
+ dmprintf1(pdev->memory, "ERROR: Error setting %s ...\n", sname); \
+ param_signal_error(plist, sname, code); \
+ goto done; \
+ } \
+ else if (code == 0) \
+ { \
+ cups->header.name = (float)floatval; \
+ }
+
+#define booloption(name, sname) \
+ if ((code = param_read_bool(plist, sname, &boolval)) < 0) \
+ { \
+ if ((code = param_read_null(plist, sname)) < 0) \
+ { \
+ dmprintf1(pdev->memory, "ERROR: Error setting %s ...\n", sname); \
+ param_signal_error(plist, sname, code); \
+ goto done; \
+ } \
+ if (code == 0) \
+ cups->header.name = CUPS_FALSE; \
+ } \
+ else if (code == 0) \
+ { \
+ cups->header.name = (cups_bool_t)boolval; \
+ }
+
+#define arrayoption(name, sname, count) \
+ if ((code = param_read_float_array(plist, sname, &arrayval)) < 0) \
+ { \
+ if ((code = param_read_null(plist, sname)) < 0) \
+ { \
+ dmprintf1(pdev->memory, "ERROR: Error setting %s...\n", sname); \
+ param_signal_error(plist, sname, code); \
+ goto done; \
+ } \
+ if (code == 0) \
+ { \
+ for (i = 0; i < count; i ++) \
+ cups->header.name[i] = 0; \
+ } \
+ } \
+ else if (code == 0) \
+ { \
+ for (i = 0; i < count; i ++) { \
+ cups->header.name[i] = (unsigned)(arrayval.data[i]); \
+ } \
+ }
+
+ sp_old = ((gx_device_printer *)pdev)->space_params;
+ width_old = pdev->width;
+ height_old = pdev->height;
+ transp_old = cups->page_uses_transparency;
+ size_set = param_read_float_array(plist, ".MediaSize", &arrayval) == 0 ||
+ param_read_float_array(plist, "PageSize", &arrayval) == 0;
+ margins_set = param_read_float_array(plist, "Margins", &arrayval) == 0;
+ color_set = param_read_int(plist, "cupsColorSpace", &intval) == 0 ||
+ param_read_int(plist, "cupsBitsPerColor", &intval) == 0;
+
+ if (!cups->user_icc) {
+ cups->user_icc = param_read_string(plist, "OutputICCProfile", &icc_pro_dummy) == 0;
+ }
+
+ /* We also recompute page size and margins if we simply get onto a new
+ page without necessarily having a page size change in the PostScript
+ code, as for some printers margins have to be flipped on the back sides of
+ the sheets (even pages) when printing duplex */
+ if (cups->page != cups->lastpage) {
+ size_set = 1;
+ cups->lastpage = cups->page;
+ }
+
+ stringoption(MediaClass, "MediaClass")
+ stringoption(MediaColor, "MediaColor")
+ stringoption(MediaType, "MediaType")
+ stringoption(OutputType, "OutputType")
+ intoption(AdvanceDistance, "AdvanceDistance", unsigned)
+ intoption(AdvanceMedia, "AdvanceMedia", cups_adv_t)
+ booloption(Collate, "Collate")
+ intoption(CutMedia, "CutMedia", cups_cut_t)
+ booloption(Duplex, "Duplex")
+ arrayoption(ImagingBoundingBox, "ImagingBoundingBox", 4)
+ booloption(InsertSheet, "InsertSheet")
+ intoption(Jog, "Jog", cups_jog_t)
+ arrayoption(Margins, "Margins", 2)
+ booloption(ManualFeed, "ManualFeed")
+ intoption(MediaPosition, "cupsMediaPosition", unsigned) /* Compatibility */
+ intoption(MediaPosition, "MediaPosition", unsigned)
+ intoption(MediaWeight, "MediaWeight", unsigned)
+ booloption(MirrorPrint, "MirrorPrint")
+ booloption(NegativePrint, "NegativePrint")
+ intoption(Orientation, "Orientation", cups_orient_t)
+ booloption(OutputFaceUp, "OutputFaceUp")
+ booloption(Separations, "Separations")
+ booloption(TraySwitch, "TraySwitch")
+ booloption(Tumble, "Tumble")
+ intoption(cupsMediaType, "cupsMediaType", unsigned)
+ intoption(cupsBitsPerColor, "cupsBitsPerColor", unsigned)
+ intoption(cupsColorOrder, "cupsColorOrder", cups_order_t)
+ intoption(cupsColorSpace, "cupsColorSpace", cups_cspace_t)
+ intoption(cupsCompression, "cupsCompression", unsigned)
+ intoption(cupsRowCount, "cupsRowCount", unsigned)
+ intoption(cupsRowFeed, "cupsRowFeed", unsigned)
+ intoption(cupsRowStep, "cupsRowStep", unsigned)
+
+#ifdef GX_COLOR_INDEX_TYPE
+ /*
+ * Support cupsPreferredBitsPerColor - basically, allows you to
+ * request 16-bits per color in a backwards-compatible way...
+ */
+
+ if (!param_read_int(plist, "cupsPreferredBitsPerColor", &intval))
+ if (intval > cups->header.cupsBitsPerColor && intval <= 16)
+ cups->header.cupsBitsPerColor = intval;
+#endif /* GX_COLOR_INDEX_TYPE */
+
+#ifdef CUPS_RASTER_SYNCv1
+ floatoption(cupsBorderlessScalingFactor, "cupsBorderlessScalingFactor");
+
+ for (i = 0; cups_Integer_strings[i] != NULL; i ++)
+ {
+ intoption(cupsInteger[i], cups_Integer_strings[i], unsigned)
+ }
+
+ for (i = 0; cups_Real_strings[i] != NULL; i ++)
+ {
+ floatoption(cupsReal[i], cups_Real_strings[i])
+ }
+
+ for (i = 0; cups_String_strings[i] != NULL; i ++)
+ {
+ stringoption(cupsString[i], cups_String_strings[i])
+ }
+
+ stringoption(cupsMarkerType, "cupsMarkerType");
+ stringoption(cupsRenderingIntent, "cupsRenderingIntent");
+ stringoption(cupsPageSizeName, "cupsPageSizeName");
+#endif /* CUPS_RASTER_SYNCv1 */
+
+ if ((code = param_read_string(plist, "cupsProfile", &stringval)) < 0)
+ {
+ param_signal_error(plist, "cupsProfile", code);
+ goto done;
+ }
+ else if (code == 0)
+ {
+ if (cups->Profile != NULL)
+ free(cups->Profile);
+
+ cups->Profile = strdup((char *)stringval.data);
+ }
+
+ if ((code = cups_set_color_info(pdev)) < 0) {
+ goto done;
+ }
+
+ /*
+ * Then process standard page device options...
+ */
+
+ if ((code = gdev_prn_put_params(pdev, plist)) < 0)
+ goto done;
+
+ cups->header.LeadingEdge = (cups_edge_t)(pdev->LeadingEdge & LEADINGEDGE_MASK);
+
+ /* If cups_set_color_info() changed the color model of the device we want to
+ * force the raster memory to be recreated/reinitialized
+ */
+ if (cups->color_info.num_components != old_cmps || cups->color_info.depth != old_depth) {
+ width_old = 0;
+ height_old = 0;
+ }
+ else {
+ /* pdev->width/height may have been changed by the call to
+ * gdev_prn_put_params()
+ */
+ width_old = pdev->width;
+ height_old = pdev->height;
+ }
+ /*
+ * Update margins/sizes as needed...
+ */
+
+ if (size_set)
+ {
+ /*
+ * Compute the page margins...
+ */
+
+#ifdef CUPS_DEBUG
+ dmprintf2(pdev->memory, "DEBUG: Updating PageSize to [%.0f %.0f]...\n",
+ cups->MediaSize[0], cups->MediaSize[1]);
+#endif /* CUPS_DEBUG */
+
+ memset(margins, 0, sizeof(margins));
+
+ cups->landscape = 0;
+
+ if (cups->PPD != NULL)
+ {
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.Duplex = %d\n", cups->header.Duplex);
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.Tumble = %d\n", cups->header.Tumble);
+ dmprintf1(pdev->memory, "DEBUG2: cups->page = %d\n", cups->page);
+ dmprintf1(pdev->memory, "DEBUG2: cups->PPD = %p\n", cups->PPD);
+#endif /* CUPS_DEBUG */
+
+ backside = ppdFindAttr(cups->PPD, "cupsBackSide", NULL);
+ if (backside) {
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cupsBackSide = %s\n", backside->value);
+#endif /* CUPS_DEBUG */
+ cups->PPD->flip_duplex = 0;
+ }
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cups->PPD->flip_duplex = %d\n", cups->PPD->flip_duplex);
+#endif /* CUPS_DEBUG */
+
+ backsiderequiresflippedmargins =
+ ppdFindAttr(cups->PPD, "APDuplexRequiresFlippedMargin", NULL);
+#ifdef CUPS_DEBUG
+ if (backsiderequiresflippedmargins)
+ dmprintf1(pdev->memory, "DEBUG2: APDuplexRequiresFlippedMargin = %s\n",
+ backsiderequiresflippedmargins->value);
+#endif /* CUPS_DEBUG */
+
+ if (cups->header.Duplex &&
+ (cups->header.Tumble &&
+ (backside && !strcasecmp(backside->value, "Flipped"))) &&
+ !(cups->page & 1))
+ {
+ xflip = 1;
+ if (backsiderequiresflippedmargins &&
+ !strcasecmp(backsiderequiresflippedmargins->value, "False")) {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (1) Flip: X=1 Y=0\n");
+#endif /* CUPS_DEBUG */
+ yflip = 0;
+ } else {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (1) Flip: X=1 Y=1\n");
+#endif /* CUPS_DEBUG */
+ yflip = 1;
+ }
+ }
+ else if (cups->header.Duplex &&
+ (!cups->header.Tumble &&
+ (backside && !strcasecmp(backside->value, "Flipped"))) &&
+ !(cups->page & 1))
+ {
+ xflip = 0;
+ if (backsiderequiresflippedmargins &&
+ !strcasecmp(backsiderequiresflippedmargins->value, "False")) {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (2) Flip: X=0 Y=1\n");
+#endif /* CUPS_DEBUG */
+ yflip = 1;
+ } else {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (2) Flip: X=0 Y=0\n");
+#endif /* CUPS_DEBUG */
+ yflip = 0;
+ }
+ }
+ else if (cups->header.Duplex &&
+ ((!cups->header.Tumble &&
+ (cups->PPD->flip_duplex ||
+ (backside && !strcasecmp(backside->value, "Rotated")))) ||
+ (cups->header.Tumble &&
+ (backside && !strcasecmp(backside->value, "ManualTumble")))) &&
+ !(cups->page & 1))
+ {
+ xflip = 1;
+ if (backsiderequiresflippedmargins &&
+ !strcasecmp(backsiderequiresflippedmargins->value, "True")) {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (3) Flip: X=1 Y=0\n");
+#endif /* CUPS_DEBUG */
+ yflip = 0;
+ } else {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (3) Flip: X=1 Y=1\n");
+#endif /* CUPS_DEBUG */
+ yflip = 1;
+ }
+ }
+ else
+ {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG2: (4) Flip: X=0 Y=0\n");
+#endif /* CUPS_DEBUG */
+ xflip = 0;
+ yflip = 0;
+ }
+
+#ifdef CUPS_RASTER_SYNCv1
+ /*
+ * Chack whether cupsPageSizeName has a valid value
+ */
+
+ if (strlen(cups->header.cupsPageSizeName) != 0) {
+ found = 0;
+ for (i = cups->PPD->num_sizes, size = cups->PPD->sizes;
+ i > 0;
+ i --, size ++)
+ if (strcasecmp(cups->header.cupsPageSizeName, size->name) == 0) {
+ found = 1;
+ break;
+ }
+ if (found == 0) cups->header.cupsPageSizeName[0] = '\0';
+ }
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.cupsPageSizeName = %s\n",
+ cups->header.cupsPageSizeName);
+#endif /* CUPS_DEBUG */
+#endif /* CUPS_RASTER_SYNCv1 */
+
+ /*
+ * Find the matching page size...
+ */
+
+#define LONG_EDGE_LENGTH_MATCH_LIMIT 0.01
+#define SHORT_EDGE_LENGTH_MATCH_LIMIT 0.01
+#define PAGESIZE_SCORE_SIZE_MARGINS 2
+#define PAGESIZE_SCORE_SIZE 1
+
+ best_score = -1;
+ best_size = NULL;
+ for (i = cups->PPD->num_sizes, size = cups->PPD->sizes;
+ i > 0;
+ i --, size ++)
+ {
+ if (size->length == 0 || size->width == 0) continue;
+
+ score = 0;
+ size_matched = 0;
+ margins_matched = 0;
+ imageable_area_matched = 0;
+ name_requested_matched = 0;
+
+ long_edge_mismatch =
+ fabs(cups->MediaSize[1] - size->length)/size->length +
+ LONG_EDGE_LENGTH_MATCH_LIMIT / 100;
+ short_edge_mismatch =
+ fabs(cups->MediaSize[0] - size->width)/size->width +
+ SHORT_EDGE_LENGTH_MATCH_LIMIT / 100;
+ if (size->length < size->width)
+ {
+ swap = long_edge_mismatch;
+ long_edge_mismatch = short_edge_mismatch;
+ short_edge_mismatch = swap;
+ }
+
+ if (long_edge_mismatch < LONG_EDGE_LENGTH_MATCH_LIMIT &&
+ short_edge_mismatch < SHORT_EDGE_LENGTH_MATCH_LIMIT)
+ {
+ size_matched = 1;
+ /* If two sizes match within the limits, take the one with less
+ mismatch */
+ score = (long)(9999.0 -
+ long_edge_mismatch * short_edge_mismatch * 9999.0 /
+ LONG_EDGE_LENGTH_MATCH_LIMIT /
+ SHORT_EDGE_LENGTH_MATCH_LIMIT);
+ if (score < 0) score = 0;
+ /* We check whether all 4 margins match with the margin info
+ of the page size in the PPD. Here we check also for swapped
+ left/right and top/bottom margins as the cups->HWMargins
+ info can be from the previous page and there the margins
+ can be swapped due to duplex printing requirements */
+ if (!margins_set ||
+ (((fabs(cups->HWMargins[0] - size->left) < 1.0 &&
+ fabs(cups->HWMargins[2] - size->width + size->right) < 1.0) ||
+ (fabs(cups->HWMargins[0] - size->width + size->right) < 1.0 &&
+ fabs(cups->HWMargins[2] - size->left) < 1.0)) &&
+ ((fabs(cups->HWMargins[1] - size->bottom) < 1.0 &&
+ fabs(cups->HWMargins[3] - size->length + size->top) < 1.0) ||
+ (fabs(cups->HWMargins[1] - size->length + size->top) < 1.0 &&
+ fabs(cups->HWMargins[3] - size->bottom) < 1.0))))
+ margins_matched = 1;
+ } else {
+ /* Compare the dimensions of the imageable area against the
+ the input page size */
+ long_edge_mismatch =
+ fabs(cups->MediaSize[1] - size->top + size->bottom)/size->length +
+ LONG_EDGE_LENGTH_MATCH_LIMIT / 100;
+ short_edge_mismatch =
+ fabs(cups->MediaSize[0] - size->right + size->left)/size->width +
+ SHORT_EDGE_LENGTH_MATCH_LIMIT / 100;
+ if (size->length < size->width)
+ {
+ swap = long_edge_mismatch;
+ long_edge_mismatch = short_edge_mismatch;
+ short_edge_mismatch = swap;
+ }
+
+ if (long_edge_mismatch < LONG_EDGE_LENGTH_MATCH_LIMIT &&
+ short_edge_mismatch < SHORT_EDGE_LENGTH_MATCH_LIMIT)
+ {
+ imageable_area_matched = 1;
+ /* If two sizes match within the limits, take the one with less
+ mismatch */
+ score = (long)(4999.0 -
+ long_edge_mismatch * short_edge_mismatch * 4999.0 /
+ LONG_EDGE_LENGTH_MATCH_LIMIT /
+ SHORT_EDGE_LENGTH_MATCH_LIMIT);
+ if (score < 0) score = 0;
+ }
+ }
+
+ if (margins_matched)
+ score += PAGESIZE_SCORE_SIZE_MARGINS * 10000;
+ else if (size_matched)
+ score += PAGESIZE_SCORE_SIZE * 10000;
+
+ if (size_matched || imageable_area_matched) {
+ if (!strcasecmp(cups->pageSizeRequested, size->name))
+ name_requested_matched = 1;
+ else
+ score -= 1000;
+ }
+
+ if (score > best_score)
+ {
+ best_score = score;
+ if (score > 0)
+ best_size = size;
+ }
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: Checking against PPD page size (portrait): %s\n",
+ size->name);
+ dmprintf2(pdev->memory, "DEBUG2: Width: %.2f; Height: %.2f\n",
+ size->width, size->length);
+ dmprintf4(pdev->memory, "DEBUG2: Margins: Left: %.2f; Right: %.2f; Top: %.2f; Bottom: %.2f\n",
+ size->left, size->right, size->top, size->bottom);
+ dmprintf4(pdev->memory, "DEBUG2: Size mismatch: Long Edge (%.3f): %.5f; Short Edge (%.3f): %.5f\n",
+ LONG_EDGE_LENGTH_MATCH_LIMIT, long_edge_mismatch,
+ SHORT_EDGE_LENGTH_MATCH_LIMIT, short_edge_mismatch);
+ dmprintf4(pdev->memory, "DEBUG2: Match: Size: %d; Margins: %d; Imageable Area: %d; Name requested: %d\n",
+ size_matched, margins_matched, imageable_area_matched,
+ name_requested_matched);
+ dmprintf2(pdev->memory, "DEBUG2: Score: %ld; Best Score: %ld\n",
+ score, best_score);
+#endif /* CUPS_DEBUG */
+ }
+
+ if (best_size)
+ {
+ /*
+ * Standard size...
+ */
+
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG: size = %s\n", best_size->name);
+#endif /* CUPS_DEBUG */
+
+ mediasize[0] = best_size->width;
+ mediasize[1] = best_size->length;
+
+ cups->landscape = 0;
+
+#ifdef CUPS_RASTER_SYNCv1
+ strncpy(cups->header.cupsPageSizeName, best_size->name,
+ sizeof(cups->header.cupsPageSizeName));
+ cups->header.cupsPageSizeName[sizeof(cups->header.cupsPageSizeName) - 1] =
+ '\0';
+
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+#endif
+ margins[0] = best_size->left / 72.0;
+ margins[1] = best_size->bottom / 72.0;
+ margins[2] = (best_size->width - best_size->right) / 72.0;
+ margins[3] = (best_size->length - best_size->top) / 72.0;
+ if (xflip == 1)
+ {
+ swap = margins[0]; margins[0] = margins[2]; margins[2] = swap;
+ }
+ if (yflip == 1)
+ {
+ swap = margins[1]; margins[1] = margins[3]; margins[3] = swap;
+ }
+#ifdef CUPS_RASTER_SYNCv1
+ }
+ else
+ {
+ margins[0] = 0.0;
+ margins[1] = 0.0;
+ margins[2] = 0.0;
+ margins[3] = 0.0;
+ }
+#endif
+ }
+ else
+ {
+ /*
+ * No matching portrait size; look for a matching size in
+ * landscape orientation...
+ */
+
+ best_score = -1;
+ best_size = NULL;
+ for (i = cups->PPD->num_sizes, size = cups->PPD->sizes;
+ i > 0;
+ i --, size ++)
+ {
+ if (size->length == 0 || size->width == 0) continue;
+
+ score = 0;
+ size_matched = 0;
+ margins_matched = 0;
+ imageable_area_matched = 0;
+ name_requested_matched = 0;
+
+ long_edge_mismatch =
+ fabs(cups->MediaSize[0] - size->length)/size->length +
+ LONG_EDGE_LENGTH_MATCH_LIMIT / 100;
+ short_edge_mismatch =
+ fabs(cups->MediaSize[1] - size->width)/size->width +
+ SHORT_EDGE_LENGTH_MATCH_LIMIT / 100;
+ if (size->length < size->width)
+ {
+ swap = long_edge_mismatch;
+ long_edge_mismatch = short_edge_mismatch;
+ short_edge_mismatch = swap;
+ }
+
+ if (long_edge_mismatch < LONG_EDGE_LENGTH_MATCH_LIMIT &&
+ short_edge_mismatch < SHORT_EDGE_LENGTH_MATCH_LIMIT)
+ {
+ size_matched = 1;
+ /* If two sizes match within the limits, take the one with less
+ mismatch */
+ score = (long)(9999.0 -
+ long_edge_mismatch * short_edge_mismatch * 9999.0 /
+ LONG_EDGE_LENGTH_MATCH_LIMIT /
+ SHORT_EDGE_LENGTH_MATCH_LIMIT);
+ if (score < 0) score = 0;
+ /* We check whether all 4 margins match with the margin info
+ of the page size in the PPD. Here we check also for swapped
+ left/right and top/bottom margins as the cups->HWMargins
+ info can be from the previous page and there the margins
+ can be swapped due to duplex printing requirements */
+ if (!margins_set ||
+ (((fabs(cups->HWMargins[1] - size->left) < 1.0 &&
+ fabs(cups->HWMargins[3] - size->width + size->right) < 1.0)||
+ (fabs(cups->HWMargins[1] - size->width + size->right) < 1.0 &&
+ fabs(cups->HWMargins[3] - size->left) < 1.0)) &&
+ ((fabs(cups->HWMargins[0] - size->bottom) < 1.0 &&
+ fabs(cups->HWMargins[2] - size->length + size->top) < 1.0) ||
+ (fabs(cups->HWMargins[0] - size->length + size->top) < 1.0 &&
+ fabs(cups->HWMargins[2] - size->bottom) < 1.0))))
+ margins_matched = 1;
+ } else {
+ /* Compare the dimensions of the imageable area against the
+ the input page size */
+ long_edge_mismatch =
+ fabs(cups->MediaSize[0] - size->top + size->bottom)/size->length +
+ LONG_EDGE_LENGTH_MATCH_LIMIT / 100;
+ short_edge_mismatch =
+ fabs(cups->MediaSize[1] - size->right + size->left)/size->width +
+ SHORT_EDGE_LENGTH_MATCH_LIMIT / 100;
+ if (size->length < size->width)
+ {
+ swap = long_edge_mismatch;
+ long_edge_mismatch = short_edge_mismatch;
+ short_edge_mismatch = swap;
+ }
+
+ if (long_edge_mismatch < LONG_EDGE_LENGTH_MATCH_LIMIT &&
+ short_edge_mismatch < SHORT_EDGE_LENGTH_MATCH_LIMIT)
+ {
+ imageable_area_matched = 1;
+ /* If two sizes match within the limits, take the one with less
+ mismatch */
+ score = (long)(4999.0 -
+ long_edge_mismatch * short_edge_mismatch * 4999.0 /
+ LONG_EDGE_LENGTH_MATCH_LIMIT /
+ SHORT_EDGE_LENGTH_MATCH_LIMIT);
+ if (score < 0) score = 0;
+ }
+ }
+
+ if (margins_matched)
+ score += PAGESIZE_SCORE_SIZE_MARGINS * 10000;
+ else if (size_matched)
+ score += PAGESIZE_SCORE_SIZE * 10000;
+
+ if (size_matched || imageable_area_matched) {
+ if (!strcasecmp(cups->pageSizeRequested, size->name))
+ name_requested_matched = 1;
+ else
+ score -= 1000;
+ }
+
+ if (score > best_score)
+ {
+ best_score = score;
+ if (score > 0)
+ best_size = size;
+ }
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: Checking against PPD page size (landscape): %s\n",
+ size->name);
+ dmprintf2(pdev->memory, "DEBUG2: Width: %.2f; Height: %.2f\n",
+ size->width, size->length);
+ dmprintf4(pdev->memory, "DEBUG2: Margins: Left: %.2f; Right: %.2f; Top: %.2f; Bottom: %.2f\n",
+ size->left, size->right, size->top, size->bottom);
+ dmprintf4(pdev->memory, "DEBUG2: Size mismatch: Long Edge (%.3f): %.5f; Short Edge (%.3f): %.5f\n",
+ LONG_EDGE_LENGTH_MATCH_LIMIT, long_edge_mismatch,
+ SHORT_EDGE_LENGTH_MATCH_LIMIT, short_edge_mismatch);
+ dmprintf4(pdev->memory, "DEBUG2: Match: Size: %d; Margins: %d; Imageable Area: %d; Name requested: %d\n",
+ size_matched, margins_matched, imageable_area_matched,
+ name_requested_matched);
+ dmprintf2(pdev->memory, "DEBUG2: Score: %ld; Best Score: %ld\n",
+ score, best_score);
+#endif /* CUPS_DEBUG */
+ }
+
+ if (best_size)
+ {
+ /*
+ * Standard size in landscape orientation...
+ */
+
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG: landscape size = %s\n", best_size->name);
+#endif /* CUPS_DEBUG */
+
+ mediasize[0] = best_size->length;
+ mediasize[1] = best_size->width;
+
+ cups->landscape = 1;
+
+#ifdef CUPS_RASTER_SYNCv1
+ strncpy(cups->header.cupsPageSizeName, best_size->name,
+ sizeof(cups->header.cupsPageSizeName));
+ cups->header.cupsPageSizeName[sizeof(cups->header.cupsPageSizeName) - 1] =
+ '\0';
+
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+#endif
+ margins[0] = (best_size->length - best_size->top) / 72.0;
+ margins[1] = best_size->left / 72.0;
+ margins[2] = best_size->bottom / 72.0;
+ margins[3] = (best_size->width - best_size->right) / 72.0;
+ if (xflip == 1)
+ {
+ swap = margins[1]; margins[1] = margins[3]; margins[3] = swap;
+ }
+ if (yflip == 1)
+ {
+ swap = margins[0]; margins[0] = margins[2]; margins[2] = swap;
+ }
+#ifdef CUPS_RASTER_SYNCv1
+ }
+ else
+ {
+ margins[0] = 0.0;
+ margins[1] = 0.0;
+ margins[2] = 0.0;
+ margins[3] = 0.0;
+ }
+#endif
+ }
+ else
+ {
+ /*
+ * Custom size...
+ */
+
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG: size = Custom\n");
+#endif /* CUPS_DEBUG */
+
+#ifdef CUPS_RASTER_SYNCv1
+ snprintf(cups->header.cupsPageSizeName,
+ sizeof(cups->header.cupsPageSizeName),
+ "Custom.%.2fx%.2f",
+ cups->MediaSize[0], cups->MediaSize[1]);
+#endif
+
+ /* Rotate page if it only fits into the printer's dimensions
+ when rotated */
+ if (((cups->MediaSize[0] > cups->PPD->custom_max[0]) ||
+ (cups->MediaSize[1] > cups->PPD->custom_max[1])) &&
+ ((cups->MediaSize[0] <= cups->PPD->custom_max[1]) &&
+ (cups->MediaSize[1] <= cups->PPD->custom_max[0]))) {
+ /* Rotate */
+ mediasize[0] = cups->MediaSize[1];
+ mediasize[1] = cups->MediaSize[0];
+
+ cups->landscape = 1;
+
+#ifdef CUPS_RASTER_SYNCv1
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+#endif
+ margins[0] = cups->PPD->custom_margins[3] / 72.0;
+ margins[1] = cups->PPD->custom_margins[0] / 72.0;
+ margins[2] = cups->PPD->custom_margins[1] / 72.0;
+ margins[3] = cups->PPD->custom_margins[2] / 72.0;
+ if (xflip == 1)
+ {
+ swap = margins[1]; margins[1] = margins[3]; margins[3] = swap;
+ }
+ if (yflip == 1)
+ {
+ swap = margins[0]; margins[0] = margins[2]; margins[2] = swap;
+ }
+#ifdef CUPS_RASTER_SYNCv1
+ }
+ else
+ {
+ margins[0] = 0.0;
+ margins[1] = 0.0;
+ margins[2] = 0.0;
+ margins[3] = 0.0;
+ }
+#endif
+ }
+ else
+ {
+ /* Do not rotate */
+ mediasize[0] = cups->MediaSize[0];
+ mediasize[1] = cups->MediaSize[1];
+
+ cups->landscape = 0;
+
+#ifdef CUPS_RASTER_SYNCv1
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+#endif
+ for (i = 0; i < 4; i ++)
+ margins[i] = cups->PPD->custom_margins[i] / 72.0;
+ if (xflip == 1)
+ {
+ swap = margins[0]; margins[0] = margins[2]; margins[2] = swap;
+ }
+ if (yflip == 1)
+ {
+ swap = margins[1]; margins[1] = margins[3]; margins[3] = swap;
+ }
+#ifdef CUPS_RASTER_SYNCv1
+ }
+ else
+ {
+ margins[0] = 0.0;
+ margins[1] = 0.0;
+ margins[2] = 0.0;
+ margins[3] = 0.0;
+ }
+#endif
+ }
+ }
+ }
+
+#ifdef CUPS_DEBUG
+ dmprintf4(pdev->memory, "DEBUG: margins[] = [ %f %f %f %f ]\n",
+ margins[0], margins[1], margins[2], margins[3]);
+#endif /* CUPS_DEBUG */
+ }
+ else
+ {
+ /* No PPD file available */
+ mediasize[0] = cups->MediaSize[0];
+ mediasize[1] = cups->MediaSize[1];
+#ifdef CUPS_RASTER_SYNCv1
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+#endif
+ /* If we do not have a PPD file, make sure that margins given via the
+ input file or via something like
+ "-c '<</.HWMargins[12 12 12 12] /Margins[0 0]>>setpagedevice'"
+ on the command line are conserved */
+ margins[0] = pdev->HWMargins[0] / 72.0;
+ margins[1] = pdev->HWMargins[1] / 72.0;
+ margins[2] = pdev->HWMargins[2] / 72.0;
+ margins[3] = pdev->HWMargins[3] / 72.0;
+#ifdef CUPS_RASTER_SYNCv1
+ }
+ else
+ {
+ margins[0] = 0.0;
+ margins[1] = 0.0;
+ margins[2] = 0.0;
+ margins[3] = 0.0;
+ }
+#endif
+ }
+
+ /*
+ * Set the media size and margins to update the bitmap size...
+ */
+
+ for (i = 0; i < 2; i ++)
+ cups_mediasize[i] = mediasize[i];
+ for (i = 0; i < 4; i ++)
+ cups_margins[i] = margins[i] * 72.0;
+ if (best_score > 0 && best_score < 5000) {
+#ifdef CUPS_DEBUG
+ dmputs(pdev->memory, "DEBUG: Imageable area fit!\n");
+#endif /* CUPS_DEBUG */
+ /* Page size matched by imageable area */
+ for (i = 0; i < 2; i ++)
+ mediasize[i] = cups->MediaSize[i];
+ for (i = 0; i < 4; i ++)
+ margins[i] = 0.0;
+ }
+ gx_device_set_media_size(pdev, mediasize[0], mediasize[1]);
+ gx_device_set_margins(pdev, margins, false);
+ } else {
+ /* No size change, use the current size in CUPS Raster header */
+ for (i = 0; i < 2; i ++)
+ cups_mediasize[i] = pdev->MediaSize[i];
+ for (i = 0; i < 4; i ++)
+ cups_margins[i] = pdev->HWMargins[i];
+ }
+
+ /*
+ * Reallocate memory if the size or color depth was changed...
+ */
+
+ if (color_set || size_set)
+ {
+ /*
+ * Make sure the page image is the correct size - current Ghostscript
+ * does not keep track of the margins in the bitmap size...
+ */
+
+ if (cups->landscape)
+ {
+ width = (pdev->MediaSize[1] - pdev->HWMargins[1] - pdev->HWMargins[3]) *
+ pdev->HWResolution[0] / 72.0f + 0.499f;
+ height = (pdev->MediaSize[0] - pdev->HWMargins[0] - pdev->HWMargins[2]) *
+ pdev->HWResolution[1] / 72.0f + 0.499f;
+ }
+ else
+ {
+ width = (pdev->MediaSize[0] - pdev->HWMargins[0] - pdev->HWMargins[2]) *
+ pdev->HWResolution[0] / 72.0f + 0.499f;
+ height = (pdev->MediaSize[1] - pdev->HWMargins[1] - pdev->HWMargins[3]) *
+ pdev->HWResolution[1] / 72.0f + 0.499f;
+ }
+
+ if (width <= 0 || height <= 0) {
+ dmprintf(pdev->memory, "ERROR: page margins overlap\n");
+ return_error(gs_error_rangecheck);
+ }
+
+#ifdef CUPS_RASTER_SYNCv1
+ if (cups->header.cupsBorderlessScalingFactor > 1.0)
+ {
+ width *= cups->header.cupsBorderlessScalingFactor;
+ height *= cups->header.cupsBorderlessScalingFactor;
+ }
+#endif /* CUPS_RASTER_SYNCv1 */
+
+ pdev->width = width;
+ pdev->height = height;
+
+ /*
+ * Don't reallocate memory unless the device has been opened...
+ * Also reallocate only if the size has actually changed...
+ */
+
+ if (pdev->is_open)
+ {
+
+ /*
+ * Device is open and size has changed, so reallocate...
+ */
+
+#ifdef CUPS_DEBUG
+ dmprintf4(pdev->memory, "DEBUG2: Reallocating memory, [%.0f %.0f] = %dx%d pixels...\n",
+ pdev->MediaSize[0], pdev->MediaSize[1], width, height);
+#endif /* CUPS_DEBUG */
+
+ if ((code = gdev_prn_maybe_realloc_memory((gx_device_printer *)pdev,
+ &sp_old,
+ width_old, height_old,
+ transp_old))
+ < 0)
+ goto done;
+#ifdef CUPS_DEBUG
+ dmprintf4(pdev->memory, "DEBUG2: Reallocated memory, [%.0f %.0f] = %dx%d pixels...\n",
+ pdev->MediaSize[0], pdev->MediaSize[1], width, height);
+#endif /* CUPS_DEBUG */
+ }
+ else
+ {
+ /*
+ * Device isn't yet open, so just save the new width and height...
+ */
+
+#ifdef CUPS_DEBUG
+ dmprintf4(pdev->memory, "DEBUG: Setting initial media size, [%.0f %.0f] = %dx%d pixels...\n",
+ pdev->MediaSize[0], pdev->MediaSize[1], width, height);
+#endif /* CUPS_DEBUG */
+
+ pdev->width = width;
+ pdev->height = height;
+ }
+ }
+
+ /*
+ * Set CUPS raster header values...
+ */
+
+ cups->header.HWResolution[0] = pdev->HWResolution[0];
+ cups->header.HWResolution[1] = pdev->HWResolution[1];
+
+#ifdef CUPS_RASTER_SYNCv1
+
+ if (cups->landscape)
+ {
+ cups->header.cupsPageSize[0] = cups_mediasize[1];
+ cups->header.cupsPageSize[1] = cups_mediasize[0];
+
+ if ((sf = cups->header.cupsBorderlessScalingFactor) < 1.0)
+ sf = 1.0;
+
+ cups->header.PageSize[0] = (cups_mediasize[1] * sf) + 0.5;
+ cups->header.PageSize[1] = (cups_mediasize[0] * sf) + 0.5;
+
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+ cups->header.Margins[0] = (cups_margins[1] * sf) + 0.5;
+ cups->header.Margins[1] = (cups_margins[2] * sf) + 0.5;
+ cups->header.ImagingBoundingBox[0] = (cups_margins[1] * sf) + 0.5;
+ cups->header.ImagingBoundingBox[1] = (cups_margins[2] * sf) + 0.5;
+ cups->header.ImagingBoundingBox[2] = ((cups_mediasize[1] -
+ cups_margins[3]) * sf) + 0.5;
+ cups->header.ImagingBoundingBox[3] = ((cups_mediasize[0] -
+ cups_margins[0]) * sf) + 0.5;
+ cups->header.cupsImagingBBox[0] = cups_margins[1];
+ cups->header.cupsImagingBBox[1] = cups_margins[2];
+ cups->header.cupsImagingBBox[2] = cups_mediasize[1] - cups_margins[3];
+ cups->header.cupsImagingBBox[3] = cups_mediasize[0] - cups_margins[0];
+ }
+ else
+ {
+ for (i = 0; i < 2; i ++)
+ cups->header.Margins[i] = 0;
+ for (i = 0; i < 4; i ++)
+ {
+ cups->header.ImagingBoundingBox[i] = 0;
+ cups->header.cupsImagingBBox[i] = 0.0;
+ }
+ }
+ }
+ else
+ {
+ cups->header.cupsPageSize[0] = cups_mediasize[0];
+ cups->header.cupsPageSize[1] = cups_mediasize[1];
+
+ if ((sf = cups->header.cupsBorderlessScalingFactor) < 1.0)
+ sf = 1.0;
+
+ cups->header.PageSize[0] = (cups_mediasize[0] * sf) + 0.5;
+ cups->header.PageSize[1] = (cups_mediasize[1] * sf) + 0.5;
+
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+ cups->header.Margins[0] = (cups_margins[0] * sf) + 0.5;
+ cups->header.Margins[1] = (cups_margins[1] * sf) + 0.5;
+ cups->header.ImagingBoundingBox[0] = (cups_margins[0] * sf) + 0.5;
+ cups->header.ImagingBoundingBox[1] = (cups_margins[1] * sf) + 0.5;
+ cups->header.ImagingBoundingBox[2] = ((cups_mediasize[0] -
+ cups_margins[2]) * sf) + 0.5;
+ cups->header.ImagingBoundingBox[3] = ((cups_mediasize[1] -
+ cups_margins[3]) * sf) + 0.5;
+ cups->header.cupsImagingBBox[0] = cups_margins[0];
+ cups->header.cupsImagingBBox[1] = cups_margins[1];
+ cups->header.cupsImagingBBox[2] = cups_mediasize[0] - cups_margins[2];
+ cups->header.cupsImagingBBox[3] = cups_mediasize[1] - cups_margins[3];
+ }
+ else
+ {
+ for (i = 0; i < 2; i ++)
+ cups->header.Margins[i] = 0;
+ for (i = 0; i < 4; i ++)
+ {
+ cups->header.ImagingBoundingBox[i] = 0;
+ cups->header.cupsImagingBBox[i] = 0.0;
+ }
+ }
+ }
+
+#else
+
+ if (cups->landscape)
+ {
+ cups->header.PageSize[0] = cups_mediasize[1] + 0.5;
+ cups->header.PageSize[1] = cups_mediasize[0] + 0.5;
+
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+ cups->header.Margins[0] = (cups_margins[1]) + 0.5;
+ cups->header.Margins[1] = (cups_margins[2]) + 0.5;
+ cups->header.ImagingBoundingBox[0] = (cups_margins[1]) + 0.5;
+ cups->header.ImagingBoundingBox[1] = (cups_margins[0]) + 0.5;
+ cups->header.ImagingBoundingBox[2] = (cups_mediasize[1] -
+ cups_margins[3]) + 0.5;
+ cups->header.ImagingBoundingBox[3] = (cups_mediasize[0] -
+ cups_margins[2]) + 0.5;
+ }
+ else
+ {
+ for (i = 0; i < 2; i ++)
+ cups->header.Margins[i] = 0;
+ for (i = 0; i < 4; i ++)
+ cups->header.ImagingBoundingBox[i] = 0;
+ }
+ }
+ else
+ {
+ cups->header.PageSize[0] = cups_mediasize[0] + 0.5;
+ cups->header.PageSize[1] = cups_mediasize[1] + 0.5;
+
+ if (strcasecmp(cups->header.MediaClass, "PwgRaster") != 0)
+ {
+ cups->header.Margins[0] = (cups_margins[0]) + 0.5;
+ cups->header.Margins[1] = (cups_margins[1]) + 0.5;
+ cups->header.ImagingBoundingBox[0] = (cups_margins[0]) + 0.5;
+ cups->header.ImagingBoundingBox[1] = (cups_margins[3]) + 0.5;
+ cups->header.ImagingBoundingBox[2] = (cups_mediasize[0] -
+ cups_margins[2]) + 0.5;
+ cups->header.ImagingBoundingBox[3] = (cups_mediasize[1] -
+ cups_margins[1]) + 0.5;
+ }
+ else
+ {
+ for (i = 0; i < 2; i ++)
+ cups->header.Margins[i] = 0;
+ for (i = 0; i < 4; i ++)
+ cups->header.ImagingBoundingBox[i] = 0;
+ }
+ }
+
+#endif /* CUPS_RASTER_SYNCv1 */
+ cups->header.cupsWidth = cups->width;
+ cups->header.cupsHeight = cups->height;
+
+#ifdef CUPS_DEBUG
+ if (size_set) {
+ dmprintf2(pdev->memory, "DEBUG2: mediasize = [ %.3f %.3f ]\n",
+ mediasize[0], mediasize[1]);
+ dmprintf4(pdev->memory, "DEBUG2: margins = [ %.3f %.3f %.3f %.3f ]\n",
+ margins[0], margins[1], margins[2], margins[3]);
+ }
+ dmprintf2(pdev->memory, "DEBUG2: cups_mediasize = [ %.3f %.3f ]\n",
+ cups_mediasize[0], cups_mediasize[1]);
+ dmprintf4(pdev->memory, "DEBUG2: cups_margins = [ %.3f %.3f %.3f %.3f ]\n",
+ cups_margins[0], cups_margins[1], cups_margins[2], cups_margins[3]);
+ dmprintf1(pdev->memory, "DEBUG2: ppd = %p\n", cups->PPD);
+ dmprintf2(pdev->memory, "DEBUG2: PageSize = [ %.3f %.3f ]\n",
+ pdev->MediaSize[0], pdev->MediaSize[1]);
+ dmprintf2(pdev->memory, "DEBUG2: HWResolution = [ %.3f %.3f ]\n",
+ pdev->HWResolution[0], pdev->HWResolution[1]);
+ dmprintf2(pdev->memory, "DEBUG2: width = %d, height = %d\n",
+ pdev->width, pdev->height);
+ dmprintf4(pdev->memory, "DEBUG2: HWMargins = [ %.3f %.3f %.3f %.3f ]\n",
+ pdev->HWMargins[0], pdev->HWMargins[1],
+ pdev->HWMargins[2], pdev->HWMargins[3]);
+ dmprintf2(pdev->memory, "DEBUG2: cups->header.cupsWidth = %d, cups->header.cupsHeight = %d\n",
+ cups->header.cupsWidth, cups->header.cupsHeight);
+ dmprintf2(pdev->memory, "DEBUG2: cups->header.PageSize[0] = %d, cups->header.PageSize[1] = %d\n",
+ cups->header.PageSize[0], cups->header.PageSize[1]);
+ dmprintf4(pdev->memory, "DEBUG2: cups->header.ImagingBoundingBox = [ %d %d %d %d ]\n",
+ cups->header.ImagingBoundingBox[0],
+ cups->header.ImagingBoundingBox[1],
+ cups->header.ImagingBoundingBox[2],
+ cups->header.ImagingBoundingBox[3]);
+#ifdef CUPS_RASTER_SYNCv1
+ dmprintf2(pdev->memory, "DEBUG2: cups->header.cupsPageSize[0] = %.3f, cups->header.cupsPageSize[1] = %.3f\n",
+ cups->header.cupsPageSize[0], cups->header.cupsPageSize[1]);
+ dmprintf4(pdev->memory, "DEBUG2: cups->header.cupsImagingBBox = [ %.3f %.3f %.3f %.3f ]\n",
+ cups->header.cupsImagingBBox[0], cups->header.cupsImagingBBox[1],
+ cups->header.cupsImagingBBox[2], cups->header.cupsImagingBBox[3]);
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.cupsBorderlessScalingFactor = %.3f\n",
+ cups->header.cupsBorderlessScalingFactor);
+#endif /* CUPS_RASTER_SYNCv1 */
+#endif /* CUPS_DEBUG */
+
+done:
+ return code;
+}
+
+/*
+ * 'cups_set_color_info()' - Set the color information structure based on
+ * the required output.
+ */
+
+private int
+cups_set_color_info(gx_device *pdev) /* I - Device info */
+{
+ int i, j, k; /* Looping vars */
+ int max_lut; /* Maximum LUT value */
+ float d, g; /* Density and gamma correction */
+ float m[3][3]; /* Color correction matrix */
+ char resolution[41]; /* Resolution string */
+ ppd_profile_t *profile; /* Color profile information */
+ int code = 0;
+
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cups_set_color_info(%p)\n", pdev);
+#endif /* CUPS_DEBUG */
+
+#ifndef GX_COLOR_INDEX_TYPE
+ if (cups->header.cupsBitsPerColor > 8)
+ cups->header.cupsBitsPerColor = 8;
+#endif /* !GX_COLOR_INDEX_TYPE */
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+#ifdef CUPS_RASTER_SYNCv1
+ cups->header.cupsNumColors = 1;
+#endif /* CUPS_RASTER_SYNCv1 */
+ cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor;
+ cups->color_info.depth = cups->header.cupsBitsPerPixel;
+ cups->color_info.num_components = 1;
+ cups->color_info.dither_grays = 1L << cups->header.cupsBitsPerColor;
+ cups->color_info.dither_colors = 1L << cups->header.cupsBitsPerColor;
+ cups->color_info.max_gray = cups->color_info.dither_grays - 1;
+ cups->color_info.max_color = cups->color_info.dither_grays - 1;
+ break;
+
+ case CUPS_CSPACE_CMY :
+ case CUPS_CSPACE_YMC :
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+#ifdef CUPS_RASTER_SYNCv1
+ cups->header.cupsNumColors = 3;
+#endif /* CUPS_RASTER_SYNCv1 */
+ if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED)
+ cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor;
+ else if (cups->header.cupsBitsPerColor < 8)
+ cups->header.cupsBitsPerPixel = 4 * cups->header.cupsBitsPerColor;
+ else
+ cups->header.cupsBitsPerPixel = 3 * cups->header.cupsBitsPerColor;
+
+ if (cups->header.cupsBitsPerColor < 8)
+ cups->color_info.depth = 4 * cups->header.cupsBitsPerColor;
+ else
+ cups->color_info.depth = 3 * cups->header.cupsBitsPerColor;
+
+ cups->color_info.num_components = 3;
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ if (cups->header.cupsBitsPerColor == 1)
+ {
+#ifdef CUPS_RASTER_SYNCv1
+ cups->header.cupsNumColors = 6;
+#endif /* CUPS_RASTER_SYNCv1 */
+ cups->header.cupsBitsPerPixel = 8;
+ cups->color_info.depth = 8;
+ cups->color_info.num_components = 4;
+ break;
+ }
+
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+#ifdef CUPS_RASTER_SYNCv1
+ cups->header.cupsNumColors = 4;
+#endif /* CUPS_RASTER_SYNCv1 */
+ if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED)
+ cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor;
+ else
+ cups->header.cupsBitsPerPixel = 4 * cups->header.cupsBitsPerColor;
+
+ cups->color_info.depth = 4 * cups->header.cupsBitsPerColor;
+ cups->color_info.num_components = 3;
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+#ifdef CUPS_RASTER_SYNCv1
+ cups->header.cupsNumColors = 4;
+#endif /* CUPS_RASTER_SYNCv1 */
+ if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED)
+ cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor;
+ else
+ cups->header.cupsBitsPerPixel = 4 * cups->header.cupsBitsPerColor;
+
+ cups->color_info.depth = 4 * cups->header.cupsBitsPerColor;
+ cups->color_info.num_components = 4;
+ break;
+
+#ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ /*
+ * Colorimetric color spaces currently are implemented as 24-bit
+ * mapping to XYZ or Lab, which are then converted as needed to
+ * the final representation...
+ *
+ * This code enforces a minimum output depth of 8 bits per
+ * component...
+ */
+
+#ifdef CUPS_RASTER_SYNCv1
+ cups->header.cupsNumColors = 3;
+#endif /* CUPS_RASTER_SYNCv1 */
+
+ if (cups->header.cupsBitsPerColor < 8)
+ cups->header.cupsBitsPerColor = 8;
+
+ if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED)
+ cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor;
+ else
+ cups->header.cupsBitsPerPixel = 3 * cups->header.cupsBitsPerColor;
+
+ cups->color_info.depth = 24;
+ cups->color_info.num_components = 3;
+ break;
+#endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ }
+
+#ifdef dev_t_proc_encode_color
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ cups->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
+ break;
+
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ case CUPS_CSPACE_KCMYcm :
+ case CUPS_CSPACE_KCMY :
+ cups->color_info.gray_index = 0;
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ cups->color_info.gray_index = 3;
+ break;
+ }
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ case CUPS_CSPACE_RGBA :
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ cups->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
+ break;
+
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ case CUPS_CSPACE_CMY :
+ case CUPS_CSPACE_YMC :
+ case CUPS_CSPACE_KCMYcm :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ cups->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
+ break;
+ }
+
+ cups->color_info.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
+#endif /* dev_t_proc_encode_color */
+
+ i = cups->header.cupsBitsPerColor;
+ max_lut = (1 << i) - 1;
+
+ switch (cups->color_info.num_components)
+ {
+ default :
+ case 1 :
+ cups->color_info.max_gray = max_lut;
+ cups->color_info.max_color = 0;
+ cups->color_info.dither_grays = max_lut + 1;
+ cups->color_info.dither_colors = 0;
+ break;
+
+ case 3 :
+ cups->color_info.max_gray = 0;
+ cups->color_info.max_color = max_lut;
+ cups->color_info.dither_grays = 0;
+ cups->color_info.dither_colors = max_lut + 1;
+ break;
+
+ case 4 :
+ cups->color_info.max_gray = max_lut;
+ cups->color_info.max_color = max_lut;
+ cups->color_info.dither_grays = max_lut + 1;
+ cups->color_info.dither_colors = max_lut + 1;
+ break;
+ }
+
+ /*
+ * Enable/disable CMYK color support...
+ */
+
+#ifdef dev_t_proc_encode_color
+ cups->color_info.max_components = cups->color_info.num_components;
+#endif /* dev_t_proc_encode_color */
+
+ /*
+ * Tell Ghostscript to forget any colors it has cached...
+ */
+
+ gx_device_decache_colors(pdev);
+
+ /*
+ * Compute the lookup tables...
+ */
+
+ for (i = 0; i <= gx_max_color_value; i ++)
+ {
+ j = (max_lut * i + gx_max_color_value / 2) / gx_max_color_value;
+
+#if !ARCH_IS_BIG_ENDIAN
+ if (max_lut > 255)
+ j = ((j & 255) << 8) | ((j >> 8) & 255);
+#endif /* !ARCH_IS_BIG_ENDIAN */
+
+ cups->EncodeLUT[i] = j;
+
+#ifdef CUPS_DEBUG2
+ if (i == 0 || cups->EncodeLUT[i] != cups->EncodeLUT[i - 1])
+ dmprintf2(pdev->memory, "DEBUG2: cups->EncodeLUT[%d] = %d\n", i,
+ (int)cups->EncodeLUT[i]);
+#endif /* CUPS_DEBUG2 */
+ }
+
+#ifdef CUPS_DEBUG2
+ dmprintf1(pdev->memory, "DEBUG2: cups->EncodeLUT[0] = %d\n", (int)cups->EncodeLUT[0]);
+ dmprintf2(pdev->memory, "DEBUG2: cups->EncodeLUT[%d] = %d\n", gx_max_color_value,
+ (int)cups->EncodeLUT[gx_max_color_value]);
+#endif /* CUPS_DEBUG2 */
+
+ for (i = 0; i < cups->color_info.dither_grays; i ++) {
+ j = i;
+#if !ARCH_IS_BIG_ENDIAN
+ if (max_lut > 255)
+ j = ((j & 255) << 8) | ((j >> 8) & 255);
+#endif /* !ARCH_IS_BIG_ENDIAN */
+ cups->DecodeLUT[i] = gx_max_color_value * j / max_lut;
+ }
+
+#ifdef CUPS_DEBUG
+ dmprintf2(pdev->memory, "DEBUG: num_components = %d, depth = %d\n",
+ cups->color_info.num_components, cups->color_info.depth);
+ dmprintf2(pdev->memory, "DEBUG: cupsColorSpace = %d, cupsColorOrder = %d\n",
+ cups->header.cupsColorSpace, cups->header.cupsColorOrder);
+ dmprintf2(pdev->memory, "DEBUG: cupsBitsPerPixel = %d, cupsBitsPerColor = %d\n",
+ cups->header.cupsBitsPerPixel, cups->header.cupsBitsPerColor);
+ dmprintf2(pdev->memory, "DEBUG: max_gray = %d, dither_grays = %d\n",
+ cups->color_info.max_gray, cups->color_info.dither_grays);
+ dmprintf2(pdev->memory, "DEBUG: max_color = %d, dither_colors = %d\n",
+ cups->color_info.max_color, cups->color_info.dither_colors);
+#endif /* CUPS_DEBUG */
+
+ /*
+ * Set the color profile as needed...
+ */
+
+ cups->HaveProfile = 0;
+
+#ifdef dev_t_proc_encode_color
+ if (cups->Profile)
+#else
+ if (cups->Profile && cups->header.cupsBitsPerColor == 8)
+#endif /* dev_t_proc_encode_color */
+ {
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG: Using user-defined profile \"%s\"...\n", cups->Profile);
+#endif /* CUPS_DEBUG */
+
+ if (sscanf(cups->Profile, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &d, &g,
+ m[0] + 0, m[0] + 1, m[0] + 2,
+ m[1] + 0, m[1] + 1, m[1] + 2,
+ m[2] + 0, m[2] + 1, m[2] + 2) != 11)
+ dmprintf(pdev->memory, "ERROR: User-defined profile does not contain 11 integers!\n");
+ else
+ {
+ cups->HaveProfile = 1;
+
+ d *= 0.001f;
+ g *= 0.001f;
+ m[0][0] *= 0.001f;
+ m[0][1] *= 0.001f;
+ m[0][2] *= 0.001f;
+ m[1][0] *= 0.001f;
+ m[1][1] *= 0.001f;
+ m[1][2] *= 0.001f;
+ m[2][0] *= 0.001f;
+ m[2][1] *= 0.001f;
+ m[2][2] *= 0.001f;
+ }
+ }
+#ifdef dev_t_proc_encode_color
+ else if (cups->PPD)
+#else
+ else if (cups->PPD && cups->header.cupsBitsPerColor == 8)
+#endif /* dev_t_proc_encode_color */
+ {
+ /*
+ * Find the appropriate color profile...
+ */
+
+ if (pdev->HWResolution[0] != pdev->HWResolution[1])
+ sprintf(resolution, "%.0fx%.0fdpi", pdev->HWResolution[0],
+ pdev->HWResolution[1]);
+ else
+ sprintf(resolution, "%.0fdpi", pdev->HWResolution[0]);
+
+ for (i = 0, profile = cups->PPD->profiles;
+ i < cups->PPD->num_profiles;
+ i ++, profile ++)
+ if ((strcmp(profile->resolution, resolution) == 0 ||
+ profile->resolution[0] == '-') &&
+ (strcmp(profile->media_type, cups->header.MediaType) == 0 ||
+ profile->media_type[0] == '-'))
+ break;
+
+ /*
+ * If we found a color profile, use it!
+ */
+
+ if (i < cups->PPD->num_profiles)
+ {
+#ifdef CUPS_DEBUG
+ dmprintf(pdev->memory, "DEBUG: Using color profile in PPD file!\n");
+#endif /* CUPS_DEBUG */
+
+ cups->HaveProfile = 1;
+
+ d = profile->density;
+ g = profile->gamma;
+
+ memcpy(m, profile->matrix, sizeof(m));
+ }
+ }
+
+ if (cups->HaveProfile)
+ {
+ for (i = 0; i < 3; i ++)
+ for (j = 0; j < 3; j ++)
+ for (k = 0; k <= CUPS_MAX_VALUE; k ++)
+ {
+ cups->Matrix[i][j][k] = (int)((float)k * m[i][j] + 0.5);
+
+#ifdef CUPS_DEBUG
+ if ((k & 4095) == 0)
+ dmprintf4(pdev->memory, "DEBUG2: cups->Matrix[%d][%d][%d] = %d\n",
+ i, j, k, cups->Matrix[i][j][k]);
+#endif /* CUPS_DEBUG */
+ }
+
+
+ for (k = 0; k <= CUPS_MAX_VALUE; k ++)
+ {
+ cups->Density[k] = (int)((float)CUPS_MAX_VALUE * d *
+ pow((float)k / (float)CUPS_MAX_VALUE, g) +
+ 0.5);
+
+#ifdef CUPS_DEBUG
+ if ((k & 4095) == 0)
+ dmprintf2(pdev->memory, "DEBUG2: cups->Density[%d] = %d\n", k, cups->Density[k]);
+#endif /* CUPS_DEBUG */
+ }
+ }
+ else
+ {
+ for (k = 0; k <= CUPS_MAX_VALUE; k ++)
+ cups->Density[k] = k;
+ }
+ if (!cups->user_icc) {
+ /* Set up the ICC profile for ghostscript to use based upon the color space.
+ This is different than the PPD profile above which appears to be some sort
+ of matrix based TRC profile */
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_CMY :
+ case CUPS_CSPACE_YMC :
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */
+ if (!pdev->icc_struct || (pdev->icc_struct &&
+ pdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsRGB)) {
+
+ if (pdev->icc_struct) {
+ rc_decrement(pdev->icc_struct, "cups_set_color_info");
+ }
+ pdev->icc_struct = gsicc_new_device_profile_array(pdev->memory);
+
+ code = gsicc_set_device_profile(pdev, pdev->memory,
+ (char *)DEFAULT_RGB_ICC, gsDEFAULTPROFILE);
+ }
+ break;
+
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ if (!pdev->icc_struct || (pdev->icc_struct &&
+ pdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsGRAY)) {
+
+ if (pdev->icc_struct) {
+ rc_decrement(pdev->icc_struct, "cups_set_color_info");
+ }
+ pdev->icc_struct = gsicc_new_device_profile_array(pdev->memory);
+
+ code = gsicc_set_device_profile(pdev, pdev->memory->non_gc_memory,
+ (char *)DEFAULT_GRAY_ICC, gsDEFAULTPROFILE);
+ }
+ break;
+ case CUPS_CSPACE_KCMYcm :
+# ifdef CUPS_RASTER_HAVE_COLORIMETRIC
+ case CUPS_CSPACE_CIEXYZ :
+#endif
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ if (!pdev->icc_struct || (pdev->icc_struct &&
+ pdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsCMYK)) {
+
+ if (pdev->icc_struct) {
+ rc_decrement(pdev->icc_struct, "cups_set_color_info");
+ }
+ pdev->icc_struct = gsicc_new_device_profile_array(pdev->memory);
+
+ code = gsicc_set_device_profile(pdev, pdev->memory,
+ (char *)DEFAULT_CMYK_ICC, gsDEFAULTPROFILE);
+ }
+ break;
+ }
+ }
+ return(code);
+}
+
+/*
+ * 'cups_sync_output()' - Keep the user informed of our status...
+ */
+
+private int /* O - Error status */
+cups_sync_output(gx_device *pdev) /* I - Device info */
+{
+ dmprintf1(pdev->memory, "INFO: Processing page %d...\n", cups->page);
+
+ return (0);
+}
+
+
+/*
+ * 'cups_print_chunked()' - Print a page of chunked pixels.
+ */
+
+static int
+cups_print_chunked(gx_device_printer *pdev,
+ /* I - Printer device */
+ unsigned char *src,
+ /* I - Scanline buffer */
+ unsigned char *dst,
+ /* I - Bitmap buffer */
+ int srcbytes)
+ /* I - Number of bytes in src */
+{
+ int y; /* Looping var */
+ unsigned char *srcptr, /* Pointer to data */
+ *dstptr; /* Pointer to bits */
+ int count; /* Count for loop */
+ int xflip, /* Flip scanline? */
+#ifdef CUPS_DEBUG
+ yflip, /* Reverse scanline order? */
+#endif
+ ystart, yend, ystep; /* Loop control for scanline order */
+ ppd_attr_t *backside = NULL;
+
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.Duplex = %d\n", cups->header.Duplex);
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.Tumble = %d\n", cups->header.Tumble);
+ dmprintf1(pdev->memory, "DEBUG2: cups->page = %d\n", cups->page);
+ dmprintf1(pdev->memory, "DEBUG2: cups->PPD = %p\n", cups->PPD);
+#endif /* CUPS_DEBUG */
+
+ if (cups->PPD) {
+ backside = ppdFindAttr(cups->PPD, "cupsBackSide", NULL);
+ if (backside) {
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cupsBackSide = %s\n", backside->value);
+#endif /* CUPS_DEBUG */
+ cups->PPD->flip_duplex = 0;
+ }
+ }
+ if (cups->header.Duplex && cups->PPD &&
+ ((!cups->header.Tumble &&
+ (cups->PPD->flip_duplex ||
+ (backside && !strcasecmp(backside->value, "Rotated")))) ||
+ (cups->header.Tumble &&
+ (backside && (!strcasecmp(backside->value, "Flipped") ||
+ !strcasecmp(backside->value, "ManualTumble"))))) &&
+ !(cups->page & 1))
+ xflip = 1;
+ else
+ xflip = 0;
+ if (cups->header.Duplex && cups->PPD &&
+ ((!cups->header.Tumble &&
+ (cups->PPD->flip_duplex ||
+ (backside && (!strcasecmp(backside->value, "Flipped") ||
+ !strcasecmp(backside->value, "Rotated"))))) ||
+ (cups->header.Tumble &&
+ (backside && !strcasecmp(backside->value, "ManualTumble")))) &&
+ !(cups->page & 1)) {
+#ifdef CUPS_DEBUG
+ yflip = 1;
+#endif
+ ystart = cups->height - 1;
+ yend = -1;
+ ystep = -1;
+ } else {
+#ifdef CUPS_DEBUG
+ yflip = 0;
+#endif
+ ystart = 0;
+ yend = cups->height;
+ ystep = 1;
+ }
+
+#ifdef CUPS_DEBUG
+ dmprintf3(pdev->memory, "DEBUG: cups_print_chunked: xflip = %d, yflip = %d, height = %d\n",
+ xflip, yflip, cups->height);
+#endif /* CUPS_DEBUG */
+
+ /*
+ * Loop through the page bitmap and write chunked pixels, reversing as
+ * needed...
+ */
+ for (y = ystart; y != yend; y += ystep)
+ {
+ /*
+ * Grab the scanline data...
+ */
+
+ if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0)
+ {
+ dmprintf1(pdev->memory, "ERROR: Unable to get scanline %d!\n", y);
+ return_error(gs_error_unknownerror);
+ }
+
+ if (xflip)
+ {
+ /*
+ * Flip the raster data before writing it...
+ */
+
+ if (srcptr[0] == 0 && memcmp(srcptr, srcptr + 1, srcbytes - 1) == 0)
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+ else
+ {
+ dstptr = dst;
+ count = srcbytes;
+
+ switch (cups->color_info.depth)
+ {
+ case 1 : /* B&W bitmap */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ {
+ *dstptr = cups->RevUpper1[*srcptr & 15] |
+ cups->RevLower1[*srcptr >> 4];
+ }
+ break;
+
+ case 2 : /* 2-bit W/K image */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ {
+ *dstptr = cups->RevUpper2[*srcptr & 15] |
+ cups->RevLower2[*srcptr >> 4];
+ }
+ break;
+
+ case 4 : /* 1-bit RGB/CMY/CMYK bitmap or 4-bit W/K image */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ *dstptr = (*srcptr >> 4) | (*srcptr << 4);
+ break;
+
+ case 8 : /* 2-bit RGB/CMY/CMYK or 8-bit W/K image */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ *dstptr = *srcptr;
+ break;
+
+ case 16 : /* 4-bit RGB/CMY/CMYK or 16-bit W/K image */
+ for (srcptr += srcbytes - 2;
+ count > 0;
+ count -= 2, srcptr -= 2, dstptr += 2)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ }
+ break;
+
+ case 24 : /* 8-bit RGB or CMY image */
+ for (srcptr += srcbytes - 3;
+ count > 0;
+ count -= 3, srcptr -= 3, dstptr += 3)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ dstptr[2] = srcptr[2];
+ }
+ break;
+
+ case 32 : /* 8-bit CMYK image */
+ for (srcptr += srcbytes - 4;
+ count > 0;
+ count -= 4, srcptr -= 4, dstptr += 4)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ dstptr[2] = srcptr[2];
+ dstptr[3] = srcptr[3];
+ }
+ break;
+
+ case 48 : /* 16-bit RGB or CMY image */
+ for (srcptr += srcbytes - 6;
+ count > 0;
+ count -= 6, srcptr -= 6, dstptr += 6)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ dstptr[2] = srcptr[2];
+ dstptr[3] = srcptr[3];
+ dstptr[4] = srcptr[4];
+ dstptr[5] = srcptr[5];
+ }
+ break;
+
+ case 64 : /* 16-bit CMYK image */
+ for (srcptr += srcbytes - 8;
+ count > 0;
+ count -= 8, srcptr -= 8, dstptr += 8)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ dstptr[2] = srcptr[2];
+ dstptr[3] = srcptr[3];
+ dstptr[4] = srcptr[4];
+ dstptr[5] = srcptr[5];
+ dstptr[6] = srcptr[6];
+ dstptr[7] = srcptr[7];
+ }
+ break;
+ }
+ }
+
+ /*
+ * Write the bitmap data to the raster stream...
+ */
+
+ cupsRasterWritePixels(cups->stream, dst, cups->header.cupsBytesPerLine);
+ }
+ else
+ {
+ /*
+ * Write the scanline data to the raster stream...
+ */
+
+ cupsRasterWritePixels(cups->stream, srcptr, cups->header.cupsBytesPerLine);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * 'cups_print_banded()' - Print a page of banded pixels.
+ */
+
+static int
+cups_print_banded(gx_device_printer *pdev,
+ /* I - Printer device */
+ unsigned char *src,
+ /* I - Scanline buffer */
+ unsigned char *dst,
+ /* I - Bitmap buffer */
+ int srcbytes)
+ /* I - Number of bytes in src */
+{
+ int x; /* Looping var */
+ int y; /* Looping var */
+ int bandbytes; /* Bytes per band */
+ unsigned char bit; /* Current bit */
+ unsigned char temp; /* Temporary variable */
+ unsigned char *srcptr; /* Pointer to data */
+ unsigned char *cptr, *mptr, *yptr, /* Pointer to components */
+ *kptr, *lcptr, *lmptr; /* ... */
+ int xflip, /* Flip scanline? */
+#ifdef CUPS_DEBUG
+ yflip, /* Reverse scanline order? */
+#endif
+ ystart, yend, ystep; /* Loop control for scanline order */
+ ppd_attr_t *backside = NULL;
+
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.Duplex = %d\n", cups->header.Duplex);
+ dmprintf1(pdev->memory, "DEBUG2: cups->header.Tumble = %d\n", cups->header.Tumble);
+ dmprintf1(pdev->memory, "DEBUG2: cups->page = %d\n", cups->page);
+ dmprintf1(pdev->memory, "DEBUG2: cups->PPD = %p\n", cups->PPD);
+#endif /* CUPS_DEBUG */
+
+ if (cups->PPD) {
+ backside = ppdFindAttr(cups->PPD, "cupsBackSide", NULL);
+ if (backside) {
+#ifdef CUPS_DEBUG
+ dmprintf1(pdev->memory, "DEBUG2: cupsBackSide = %s\n", backside->value);
+#endif /* CUPS_DEBUG */
+ cups->PPD->flip_duplex = 0;
+ }
+ }
+ if (cups->header.Duplex && cups->PPD &&
+ ((!cups->header.Tumble &&
+ (cups->PPD->flip_duplex ||
+ (backside && !strcasecmp(backside->value, "Rotated")))) ||
+ (cups->header.Tumble &&
+ (backside && (!strcasecmp(backside->value, "Flipped") ||
+ !strcasecmp(backside->value, "ManualTumble"))))) &&
+ !(cups->page & 1))
+ xflip = 1;
+ else
+ xflip = 0;
+ if (cups->header.Duplex && cups->PPD &&
+ ((!cups->header.Tumble &&
+ (cups->PPD->flip_duplex ||
+ (backside && (!strcasecmp(backside->value, "Flipped") ||
+ !strcasecmp(backside->value, "Rotated"))))) ||
+ (cups->header.Tumble &&
+ (backside && !strcasecmp(backside->value, "ManualTumble")))) &&
+ !(cups->page & 1)) {
+#ifdef CUPS_DEBUG
+ yflip = 1;
+#endif
+ ystart = cups->height - 1;
+ yend = -1;
+ ystep = -1;
+ } else {
+#ifdef CUPS_DEBUG
+ yflip = 0;
+#endif
+ ystart = 0;
+ yend = cups->height;
+ ystep = 1;
+ }
+
+#ifdef CUPS_DEBUG
+ dmprintf3(pdev->memory, "DEBUG: cups_print_chunked: xflip = %d, yflip = %d, height = %d\n",
+ xflip, yflip, cups->height);
+#endif /* CUPS_DEBUG */
+
+ /*
+ * Loop through the page bitmap and write banded pixels... We have
+ * to separate each chunked color as needed...
+ */
+
+#ifdef CUPS_RASTER_SYNCv1
+ bandbytes = cups->header.cupsBytesPerLine / cups->header.cupsNumColors;
+#else
+ if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm &&
+ cups->header.cupsBitsPerColor == 1)
+ bandbytes = cups->header.cupsBytesPerLine / 6;
+ else
+ bandbytes = cups->header.cupsBytesPerLine / cups->color_info.num_components;
+#endif /* CUPS_RASTER_SYNCv1 */
+
+ for (y = ystart; y != yend; y += ystep)
+ {
+ /*
+ * Grab the scanline data...
+ */
+
+ if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0)
+ {
+ dmprintf1(pdev->memory, "ERROR: Unable to get scanline %d!\n", y);
+ return_error(gs_error_unknownerror);
+ }
+
+ /*
+ * Separate the chunked colors into their components...
+ */
+
+ if (srcptr[0] == 0 && memcmp(srcptr, srcptr + 1, srcbytes - 1) == 0)
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+ else
+ {
+ if (xflip)
+ cptr = dst + bandbytes - 1;
+ else
+ cptr = dst;
+
+ mptr = cptr + bandbytes;
+ yptr = mptr + bandbytes;
+ kptr = yptr + bandbytes;
+ lcptr = kptr + bandbytes;
+ lmptr = lcptr + bandbytes;
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (x = cups->width, bit = xflip ? 1 << (x & 7) : 128;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if (*srcptr & 0x40)
+ *cptr |= bit;
+ if (*srcptr & 0x20)
+ *mptr |= bit;
+ if (*srcptr & 0x10)
+ *yptr |= bit;
+
+ if (xflip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ bit = 1;
+ }
+ }
+ else
+ bit >>= 1;
+
+ x --;
+ if (x == 0)
+ break;
+
+ if (*srcptr & 0x4)
+ *cptr |= bit;
+ if (*srcptr & 0x2)
+ *mptr |= bit;
+ if (*srcptr & 0x1)
+ *yptr |= bit;
+
+ if (xflip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ bit = 1;
+ }
+ }
+ else if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ bit = 128;
+ }
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ for (x = cups->width, bit = xflip ? 1 << (x & 7) : 128;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if (*srcptr & 0x80)
+ *cptr |= bit;
+ if (*srcptr & 0x40)
+ *mptr |= bit;
+ if (*srcptr & 0x20)
+ *yptr |= bit;
+ if (*srcptr & 0x10)
+ *kptr |= bit;
+
+ if (xflip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ bit = 1;
+ }
+ }
+ else
+ bit >>= 1;
+
+ x --;
+ if (x == 0)
+ break;
+
+ if (*srcptr & 0x8)
+ *cptr |= bit;
+ if (*srcptr & 0x4)
+ *mptr |= bit;
+ if (*srcptr & 0x2)
+ *yptr |= bit;
+ if (*srcptr & 0x1)
+ *kptr |= bit;
+
+ if (xflip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ bit = 1;
+ }
+ }
+ else if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ bit = 128;
+ }
+ }
+ break;
+ case CUPS_CSPACE_KCMYcm :
+ for (x = cups->width, bit = xflip ? 1 << (x & 7) : 128;
+ x > 0;
+ x --, srcptr ++)
+ {
+ /*
+ * Note: Because of the way the pointers are setup,
+ * the following code is correct even though
+ * the names don't match...
+ */
+
+ if (*srcptr & 0x20)
+ *cptr |= bit;
+ if (*srcptr & 0x10)
+ *mptr |= bit;
+ if (*srcptr & 0x08)
+ *yptr |= bit;
+ if (*srcptr & 0x04)
+ *kptr |= bit;
+ if (*srcptr & 0x02)
+ *lcptr |= bit;
+ if (*srcptr & 0x01)
+ *lmptr |= bit;
+
+ if (xflip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ lcptr --;
+ lmptr --;
+ bit = 1;
+ }
+ }
+ else if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ lcptr ++;
+ lmptr ++;
+ bit = 128;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 2 :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (x = cups->width, bit = xflip ? 3 << (2 * (x & 3)) : 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ switch (bit)
+ {
+ case 0xc0 :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp << 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp << 4;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp << 6;
+
+ if (xflip)
+ {
+ bit = 0x03;
+ cptr --;
+ mptr --;
+ yptr --;
+ }
+ else
+ bit = 0x30;
+ break;
+ case 0x30 :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp << 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp << 4;
+
+ if (xflip)
+ bit = 0xc0;
+ else
+ bit = 0x0c;
+ break;
+ case 0x0c :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp >> 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp << 2;
+
+ if (xflip)
+ bit = 0x30;
+ else
+ bit = 0x03;
+ break;
+ case 0x03 :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp >> 4;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp >> 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp;
+
+ if (xflip)
+ bit = 0x0c;
+ else
+ {
+ bit = 0xc0;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ break;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ for (x = cups->width, bit = xflip ? 3 << (2 * (x & 3)) : 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ switch (bit)
+ {
+ case 0xc0 :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp << 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp << 4;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp << 6;
+
+ if (xflip)
+ {
+ bit = 0x03;
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ }
+ else
+ bit = 0x30;
+ break;
+ case 0x30 :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp >> 2;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp << 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp << 4;
+
+ if (xflip)
+ bit = 0xc0;
+ else
+ bit = 0x0c;
+ break;
+ case 0x0c :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp >> 4;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp >> 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp << 2;
+
+ if (xflip)
+ bit = 0x30;
+ else
+ bit = 0x03;
+ break;
+ case 0x03 :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp >> 6;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp >> 4;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp >> 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp;
+
+ if (xflip)
+ bit = 0x0c;
+ else
+ {
+ bit = 0xc0;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 4 :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (x = cups->width, bit = xflip && (x & 1) ? 0xf0 : 0x0f;
+ x > 0;
+ x --, srcptr += 2)
+ switch (bit)
+ {
+ case 0xf0 :
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *cptr |= temp << 4;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *mptr |= temp;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *yptr |= temp << 4;
+
+ bit = 0x0f;
+
+ if (xflip)
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ }
+ break;
+ case 0x0f :
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *cptr |= temp;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *mptr |= temp >> 4;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *yptr |= temp;
+
+ bit = 0xf0;
+
+ if (!xflip)
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ break;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ for (x = cups->width, bit = xflip && (x & 1) ? 0xf0 : 0x0f;
+ x > 0;
+ x --, srcptr += 2)
+ switch (bit)
+ {
+ case 0xf0 :
+ if ((temp = srcptr[0] & 0xf0) != 0)
+ *cptr |= temp;
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *mptr |= temp << 4;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *yptr |= temp;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *kptr |= temp << 4;
+
+ bit = 0x0f;
+
+ if (xflip)
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ }
+ break;
+ case 0x0f :
+ if ((temp = srcptr[0] & 0xf0) != 0)
+ *cptr |= temp >> 4;
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *mptr |= temp;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *yptr |= temp >> 4;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *kptr |= temp;
+
+ bit = 0xf0;
+
+ if (!xflip)
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 8 :
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ if (xflip)
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr-- = *srcptr++;
+ *mptr-- = *srcptr++;
+ *yptr-- = *srcptr++;
+ }
+ else
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ if (xflip)
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr-- = *srcptr++;
+ *mptr-- = *srcptr++;
+ *yptr-- = *srcptr++;
+ *kptr-- = *srcptr++;
+ }
+ else
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ *kptr++ = *srcptr++;
+ }
+ break;
+ }
+ break;
+
+ case 16 :
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ if (xflip)
+ for (x = cups->width; x > 0; x --, srcptr += 6)
+ {
+ *cptr-- = srcptr[1];
+ *cptr-- = srcptr[0];
+ *mptr-- = srcptr[3];
+ *mptr-- = srcptr[2];
+ *yptr-- = srcptr[5];
+ *yptr-- = srcptr[4];
+ }
+ else
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr++ = *srcptr++;
+ *cptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ if (xflip)
+ for (x = cups->width; x > 0; x --, srcptr += 8)
+ {
+ *cptr-- = srcptr[1];
+ *cptr-- = srcptr[0];
+ *mptr-- = srcptr[3];
+ *mptr-- = srcptr[2];
+ *yptr-- = srcptr[5];
+ *yptr-- = srcptr[4];
+ *kptr-- = srcptr[7];
+ *kptr-- = srcptr[6];
+ }
+ else
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr++ = *srcptr++;
+ *cptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ *kptr++ = *srcptr++;
+ *kptr++ = *srcptr++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Write the bitmap data to the raster stream...
+ */
+
+ cupsRasterWritePixels(cups->stream, dst, cups->header.cupsBytesPerLine);
+ }
+ return (0);
+}
+
+
+/*
+ * 'cups_print_planar()' - Print a page of planar pixels.
+ */
+
+static int
+cups_print_planar(gx_device_printer *pdev,
+ /* I - Printer device */
+ unsigned char *src,
+ /* I - Scanline buffer */
+ unsigned char *dst,
+ /* I - Bitmap buffer */
+ int srcbytes)
+ /* I - Number of bytes in src */
+{
+ int x; /* Looping var */
+ int y; /* Looping var */
+ unsigned char z; /* Looping var */
+ unsigned char srcbit; /* Current source bit */
+ unsigned char dstbit; /* Current destination bit */
+ unsigned char temp; /* Temporary variable */
+ unsigned char *srcptr; /* Pointer to data */
+ unsigned char *dstptr; /* Pointer to bitmap */
+
+
+ /**** NOTE: Currently planar output doesn't support flipped duplex!!! ****/
+
+ /*
+ * Loop through the page bitmap and write planar pixels... We have
+ * to separate each chunked color as needed...
+ */
+
+ for (z = 0; z < pdev->color_info.num_components; z ++)
+ for (y = 0; y < cups->height; y ++)
+ {
+ /*
+ * Grab the scanline data...
+ */
+
+ if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0)
+ {
+ dmprintf1(pdev->memory, "ERROR: Unable to get scanline %d!\n", y);
+ return_error(gs_error_unknownerror);
+ }
+
+ /*
+ * Pull the individual color planes out of the pixels...
+ */
+
+ if (srcptr[0] == 0 && memcmp(srcptr, srcptr + 1, srcbytes - 1) == 0)
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+ else
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (dstptr = dst, x = cups->width, srcbit = 64 >> z,
+ dstbit = 128;
+ x > 0;
+ x --)
+ {
+ if (*srcptr & srcbit)
+ *dstptr |= dstbit;
+
+ if (srcbit >= 16)
+ srcbit >>= 4;
+ else
+ {
+ srcbit = 64 >> z;
+ srcptr ++;
+ }
+
+ if (dstbit > 1)
+ dstbit >>= 1;
+ else
+ {
+ dstbit = 128;
+ dstptr ++;
+ }
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ for (dstptr = dst, x = cups->width, srcbit = 128 >> z,
+ dstbit = 128;
+ x > 0;
+ x --)
+ {
+ if (*srcptr & srcbit)
+ *dstptr |= dstbit;
+
+ if (srcbit >= 16)
+ srcbit >>= 4;
+ else
+ {
+ srcbit = 128 >> z;
+ srcptr ++;
+ }
+
+ if (dstbit > 1)
+ dstbit >>= 1;
+ else
+ {
+ dstbit = 128;
+ dstptr ++;
+ }
+ }
+ break;
+ case CUPS_CSPACE_KCMYcm :
+ for (dstptr = dst, x = cups->width, srcbit = 32 >> z,
+ dstbit = 128;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if (*srcptr & srcbit)
+ *dstptr |= dstbit;
+
+ if (dstbit > 1)
+ dstbit >>= 1;
+ else
+ {
+ dstbit = 128;
+ dstptr ++;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 2 :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (dstptr = dst, x = cups->width, srcbit = 48 >> (z * 2),
+ dstbit = 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if ((temp = *srcptr & srcbit) != 0)
+ {
+ if (srcbit == dstbit)
+ *dstptr |= temp;
+ else
+ {
+ switch (srcbit)
+ {
+ case 0x30 :
+ temp >>= 4;
+ break;
+ case 0x0c :
+ temp >>= 2;
+ break;
+ }
+
+ switch (dstbit)
+ {
+ case 0xc0 :
+ *dstptr |= temp << 6;
+ break;
+ case 0x30 :
+ *dstptr |= temp << 4;
+ break;
+ case 0x0c :
+ *dstptr |= temp << 2;
+ break;
+ case 0x03 :
+ *dstptr |= temp;
+ break;
+ }
+ }
+ }
+
+ if (dstbit > 0x03)
+ dstbit >>= 2;
+ else
+ {
+ dstbit = 0xc0;
+ dstptr ++;
+ }
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ for (dstptr = dst, x = cups->width, srcbit = 192 >> (z * 2),
+ dstbit = 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if ((temp = *srcptr & srcbit) != 0)
+ {
+ if (srcbit == dstbit)
+ *dstptr |= temp;
+ else
+ {
+ switch (srcbit)
+ {
+ case 0xc0 :
+ temp >>= 6;
+ break;
+ case 0x30 :
+ temp >>= 4;
+ break;
+ case 0x0c :
+ temp >>= 2;
+ break;
+ }
+
+ switch (dstbit)
+ {
+ case 0xc0 :
+ *dstptr |= temp << 6;
+ break;
+ case 0x30 :
+ *dstptr |= temp << 4;
+ break;
+ case 0x0c :
+ *dstptr |= temp << 2;
+ break;
+ case 0x03 :
+ *dstptr |= temp;
+ break;
+ }
+ }
+ }
+
+ if (dstbit > 0x03)
+ dstbit >>= 2;
+ else
+ {
+ dstbit = 0xc0;
+ dstptr ++;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 4 :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ if (z > 0)
+ srcptr ++;
+
+ if (z == 1)
+ srcbit = 0xf0;
+ else
+ srcbit = 0x0f;
+
+ for (dstptr = dst, x = cups->width, dstbit = 0xf0;
+ x > 0;
+ x --, srcptr += 2)
+ {
+ if ((temp = *srcptr & srcbit) != 0)
+ {
+ if (srcbit == dstbit)
+ *dstptr |= temp;
+ else
+ {
+ if (srcbit == 0xf0)
+ temp >>= 4;
+
+ if (dstbit == 0xf0)
+ *dstptr |= temp << 4;
+ else
+ *dstptr |= temp;
+ }
+ }
+
+ if (dstbit == 0xf0)
+ dstbit = 0x0f;
+ else
+ {
+ dstbit = 0xf0;
+ dstptr ++;
+ }
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ if (z > 1)
+ srcptr ++;
+
+ if (z & 1)
+ srcbit = 0x0f;
+ else
+ srcbit = 0xf0;
+
+ for (dstptr = dst, x = cups->width, dstbit = 0xf0;
+ x > 0;
+ x --, srcptr += 2)
+ {
+ if ((temp = *srcptr & srcbit) != 0)
+ {
+ if (srcbit == dstbit)
+ *dstptr |= temp;
+ else
+ {
+ if (srcbit == 0xf0)
+ temp >>= 4;
+
+ if (dstbit == 0xf0)
+ *dstptr |= temp << 4;
+ else
+ *dstptr |= temp;
+ }
+ }
+
+ if (dstbit == 0xf0)
+ dstbit = 0x0f;
+ else
+ {
+ dstbit = 0xf0;
+ dstptr ++;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 8 :
+ for (srcptr += z, dstptr = dst, x = cups->header.cupsBytesPerLine;
+ x > 0;
+ srcptr += pdev->color_info.num_components, x --)
+ *dstptr++ = *srcptr;
+ break;
+
+ case 16 :
+ for (srcptr += 2 * z, dstptr = dst, x = cups->header.cupsBytesPerLine;
+ x > 0;
+ srcptr += 2 * pdev->color_info.num_components, x --)
+ {
+ *dstptr++ = srcptr[0];
+ *dstptr++ = srcptr[1];
+ }
+ break;
+ }
+
+ /*
+ * Write the bitmap data to the raster stream...
+ */
+
+ cupsRasterWritePixels(cups->stream, dst, cups->header.cupsBytesPerLine);
+ }
+ return (0);
+}
+
+private int
+cups_spec_op(gx_device *dev_, int op, void *data, int datasize)
+{
+ return gx_default_dev_spec_op(dev_, op, data, datasize);
+}
+
+/*
+ */