/* * "$Id: gdevcups.c 9721 2009-05-04 10:59:18Z till $" * * 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_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. */ /* * Include necessary headers... */ #include "std.h" /* to stop stdlib.h redefining types */ #include "gdevprn.h" #include "gsparam.h" #include "gsexit.h" #include "arch.h" #include #include #include #include #include #undef private #define private /* * 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 colorspace is not defined until CUPS 1.2... */ # define CUPS_CSPACE_RGBW 17 #endif /* CUPS_RASTER_SYNCv1 */ /* * Newer versions of Ghostscript don't provide gs_exit() function anymore. * It has been renamed to gs_to_exit()... */ #ifdef dev_t_proc_encode_color # define gs_exit gs_to_exit #endif /* dev_t_proc_encode_color */ /* * 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 ; we can't include 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 int cups_print_pages(gx_device_printer *, FILE *, int); private int cups_put_params(gx_device *, gs_param_list *); private void 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); #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_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 */ } gx_device_cups; private gx_device_procs cups_procs = { cups_open, cups_get_matrix, cups_sync_output, gdev_prn_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, gx_error_get_color_comp_index, /* Dummy to avoid segfault */ 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 */ }; #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) gx_device_cups gs_cups_device = { prn_device_body_copies(gx_device_cups,/* type */ cups_procs, /* procedures */ "cups", /* 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 */ "", /* 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 */ #ifdef CUPS_RASTER_SYNCv1 , 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 */ "Letter" /* cupsPageSizeName */ #endif /* CUPS_RASTER_SYNCv1 */ }, 0 /* landscape */ }; /* * Globals... */ #ifdef GX_COLOR_INDEX_TYPE static gx_color_value cupsDecodeLUT[65536]; /* Output color to RGB value LUT */ #else static gx_color_value cupsDecodeLUT[256]; /* Output color to RGB value LUT */ #endif /* GX_COLOR_INDEX_TYPE */ static unsigned short cupsEncodeLUT[gx_max_color_value + 1]; /* RGB value to output color LUT */ static ppd_file_t *cupsPPD = 0; /* PPD file for this device */ static char *cupsProfile = NULL; /* Current simple color profile string */ static int cupsHaveProfile = 0; /* Has a color profile been defined? */ static int cupsMatrix[3][3][CUPS_MAX_VALUE + 1]; /* Color transform matrix LUT */ static int cupsDensity[CUPS_MAX_VALUE + 1]; /* Density LUT */ static unsigned char cupsRevLower1[16] = { /* Lower 1-bit reversal table */ 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f }, cupsRevUpper1[16] = { /* Upper 1-bit reversal table */ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 }, cupsRevLower2[16] = { /* Lower 2-bit reversal table */ 0x00, 0x04, 0x08, 0x0c, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x06, 0x0a, 0x0e, 0x03, 0x07, 0x0b, 0x0f }, cupsRevUpper2[16] = { /* Upper 2-bit reversal table */ 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0, 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0 }; /* * Local functions... */ static double cups_map_cielab(double, double); static void cups_print_chunked(gx_device_printer *, unsigned char *, unsigned char *, int); static void cups_print_banded(gx_device_printer *, unsigned char *, unsigned char *, int); static void 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 */ { dprintf1("DEBUG2: cups_close(%p)\n", pdev); 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 (cupsPPD != NULL) { ppdClose(cupsPPD); cupsPPD = NULL; } if (cupsProfile != NULL) { free(cupsProfile); cupsProfile = 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] = cupsDecodeLUT[ci & mask]; cv[0] = cupsDecodeLUT[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 = cupsEncodeLUT[cv[0]], i = 1; i < cups->color_info.num_components; i ++) ci = (ci << shift) | cupsEncodeLUT[cv[i]]; #ifdef DEBUG dprintf2("DEBUG2: cv[0]=%d -> %llx\n", cv[0], ci); #endif /* DEBUG */ /* * 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 */ } /* * Range check the return value... */ if (ci == gx_no_color_index) ci --; /* * Return the color index... */ return (ci); } /* * '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 */ { ppd_attr_t *backside = NULL; dprintf2("DEBUG2: cups_get_matrix(%p, %p)\n", pdev, pmat); /* * Set the raster width and height... */ cups->header.cupsWidth = cups->width; cups->header.cupsHeight = cups->height; /* * Set the transform matrix... */ dprintf1("DEBUG2: cups->header.Duplex = %d\n", cups->header.Duplex); dprintf1("DEBUG2: cups->page = %d\n", cups->page); if (cupsPPD) { backside = ppdFindAttr(cupsPPD, "cupsBackSide", NULL); dprintf1("DEBUG2: cupsPPD = %p\n", cupsPPD); if (backside) { dprintf1("DEBUG2: cupsBackSide = %s\n", backside->value); cupsPPD->flip_duplex = 0; } dprintf1("DEBUG2: cupsPPD->flip_duplex = %d\n", cupsPPD->flip_duplex); } if (cups->landscape) { /* * Do landscape orientation... */ if (cups->header.Duplex && cupsPPD && (cups->header.Tumble && (backside && !strcasecmp(backside->value, "Flipped"))) && !(cups->page & 1)) { 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 if (cups->header.Duplex && cupsPPD && (!cups->header.Tumble && (backside && !strcasecmp(backside->value, "Flipped"))) && !(cups->page & 1)) { 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] * ((float)cups->header.PageSize[0] - pdev->HWMargins[2]) / 72.0; } else if (cups->header.Duplex && cupsPPD && ((!cups->header.Tumble && (cupsPPD->flip_duplex || (backside && !strcasecmp(backside->value, "Rotated")))) || (cups->header.Tumble && (backside && !strcasecmp(backside->value, "ManualTumble")))) && !(cups->page & 1)) { 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] * ((float)cups->header.PageSize[0] - pdev->HWMargins[2]) / 72.0; } else { 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 if (cups->header.Duplex && cupsPPD && (cups->header.Tumble && (backside && !strcasecmp(backside->value, "Flipped"))) && !(cups->page & 1)) { 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; } else if (cups->header.Duplex && cupsPPD && (!cups->header.Tumble && (backside && !strcasecmp(backside->value, "Flipped"))) && !(cups->page & 1)) { 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] * pdev->HWMargins[1] / 72.0; } else if (cups->header.Duplex && cupsPPD && ((!cups->header.Tumble && (cupsPPD->flip_duplex || (backside && !strcasecmp(backside->value, "Rotated")))) || (cups->header.Tumble && (backside && !strcasecmp(backside->value, "ManualTumble")))) && !(cups->page & 1)) { 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] * pdev->HWMargins[1] / 72.0; } else { 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 */ dprintf2("DEBUG2: width = %d, height = %d\n", cups->width, cups->height); dprintf4("DEBUG2: PageSize = [ %d %d ], HWResolution = [ %d %d ]\n", cups->header.PageSize[0], cups->header.PageSize[1], cups->header.HWResolution[0], cups->header.HWResolution[1]); dprintf4("DEBUG2: HWMargins = [ %.3f %.3f %.3f %.3f ]\n", pdev->HWMargins[0], pdev->HWMargins[1], pdev->HWMargins[2], pdev->HWMargins[3]); dprintf6("DEBUG2: matrix = [ %.3f %.3f %.3f %.3f %.3f %.3f ]\n", pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty); } /* * '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 */ { #ifdef CUPS_RASTER_SYNCv1 int i; /* Looping var */ char name[255]; /* Attribute name */ #endif /* CUPS_RASTER_SYNCv1 */ int code; /* Return code */ gs_param_string s; /* Temporary string value */ bool b; /* Temporary boolean value */ dprintf2("DEBUG2: cups_get_params(%p, %p)\n", pdev, plist); /* * First process the "standard" page device parameters... */ dprintf("DEBUG2: before gdev_prn_get_params()\n"); if ((code = gdev_prn_get_params(pdev, plist)) < 0) return (code); dprintf("DEBUG2: after gdev_prn_get_params()\n"); /* * Then write the CUPS parameters... */ param_string_from_string(s, cups->header.MediaClass); if ((code = param_write_string(plist, "MediaClass", &s)) < 0) return (code); param_string_from_string(s, cups->header.MediaColor); if ((code = param_write_string(plist, "MediaColor", &s)) < 0) return (code); param_string_from_string(s, cups->header.MediaType); if ((code = param_write_string(plist, "MediaType", &s)) < 0) return (code); param_string_from_string(s, cups->header.OutputType); if ((code = param_write_string(plist, "OutputType", &s)) < 0) return (code); if ((code = param_write_int(plist, "AdvanceDistance", (int *)&(cups->header.AdvanceDistance))) < 0) return (code); if ((code = param_write_int(plist, "AdvanceMedia", (int *)&(cups->header.AdvanceMedia))) < 0) return (code); b = cups->header.Collate; if ((code = param_write_bool(plist, "Collate", &b)) < 0) return (code); if ((code = param_write_int(plist, "CutMedia", (int *)&(cups->header.CutMedia))) < 0) return (code); b = cups->header.Duplex; if ((code = param_write_bool(plist, "Duplex", &b)) < 0) return (code); b = cups->header.InsertSheet; if ((code = param_write_bool(plist, "InsertSheet", &b)) < 0) return (code); if ((code = param_write_int(plist, "Jog", (int *)&(cups->header.Jog))) < 0) return (code); if ((code = param_write_int(plist, "LeadingEdge", (int *)&(cups->header.LeadingEdge))) < 0) return (code); b = cups->header.ManualFeed; if ((code = param_write_bool(plist, "ManualFeed", &b)) < 0) return (code); if ((code = param_write_int(plist, "MediaPosition", (int *)&(cups->header.MediaPosition))) < 0) return (code); if ((code = param_write_int(plist, "MediaWeight", (int *)&(cups->header.MediaWeight))) < 0) return (code); b = cups->header.MirrorPrint; if ((code = param_write_bool(plist, "MirrorPrint", &b)) < 0) return (code); b = cups->header.NegativePrint; if ((code = param_write_bool(plist, "NegativePrint", &b)) < 0) return (code); b = cups->header.OutputFaceUp; if ((code = param_write_bool(plist, "OutputFaceUp", &b)) < 0) return (code); b = cups->header.Separations; if ((code = param_write_bool(plist, "Separations", &b)) < 0) return (code); b = cups->header.TraySwitch; if ((code = param_write_bool(plist, "TraySwitch", &b)) < 0) return (code); b = cups->header.Tumble; if ((code = param_write_bool(plist, "Tumble", &b)) < 0) return (code); #if 0 /* Don't include read-only parameters... */ if ((code = param_write_int(plist, "cupsWidth", (int *)&(cups->header.cupsWidth))) < 0) return (code); if ((code = param_write_int(plist, "cupsHeight", (int *)&(cups->header.cupsHeight))) < 0) return (code); if ((code = param_write_int(plist, "cupsBitsPerPixel", (int *)&(cups->header.cupsBitsPerPixel))) < 0) return (code); if ((code = param_write_int(plist, "cupsBytesPerLine", (int *)&(cups->header.cupsBytesPerLine))) < 0) return (code); #endif /* 0 */ if ((code = param_write_int(plist, "cupsMediaType", (int *)&(cups->header.cupsMediaType))) < 0) return (code); if ((code = param_write_int(plist, "cupsBitsPerColor", (int *)&(cups->header.cupsBitsPerColor))) < 0) return (code); if ((code = param_write_int(plist, "cupsColorOrder", (int *)&(cups->header.cupsColorOrder))) < 0) return (code); if ((code = param_write_int(plist, "cupsColorSpace", (int *)&(cups->header.cupsColorSpace))) < 0) return (code); if ((code = param_write_int(plist, "cupsCompression", (int *)&(cups->header.cupsCompression))) < 0) return (code); if ((code = param_write_int(plist, "cupsRowCount", (int *)&(cups->header.cupsRowCount))) < 0) return (code); if ((code = param_write_int(plist, "cupsRowFeed", (int *)&(cups->header.cupsRowFeed))) < 0) return (code); if ((code = param_write_int(plist, "cupsRowStep", (int *)&(cups->header.cupsRowStep))) < 0) return (code); #ifdef CUPS_RASTER_SYNCv1 #if 0 /* Don't include read-only parameters... */ if ((code = param_write_int(plist, "cupsNumColors", (int *)&(cups->header.cupsNumColors))) < 0) return (code); #endif /* 0 */ if ((code = param_write_float(plist, "cupsBorderlessScalingFactor", &(cups->header.cupsBorderlessScalingFactor))) < 0) return (code); for (i = 0; i < 16; i ++) { sprintf(name, "cupsInteger%d", i); if ((code = param_write_int(plist, strdup(name), (int *)(cups->header.cupsInteger + i))) < 0) return (code); } for (i = 0; i < 16; i ++) { sprintf(name, "cupsReal%d", i); if ((code = param_write_float(plist, strdup(name), cups->header.cupsReal + i)) < 0) return (code); } for (i = 0; i < 16; i ++) { sprintf(name, "cupsString%d", i); param_string_from_string(s, cups->header.cupsString[i]); if ((code = param_write_string(plist, strdup(name), &s)) < 0) return (code); } param_string_from_string(s, cups->header.cupsMarkerType); if ((code = param_write_string(plist, "cupsMarkerType", &s)) < 0) return (code); param_string_from_string(s, cups->header.cupsRenderingIntent); if ((code = param_write_string(plist, "cupsRenderingIntent", &s)) < 0) return (code); param_string_from_string(s, cups->header.cupsPageSizeName); if ((code = param_write_string(plist, "cupsPageSizeName", &s)) < 0) return (code); #endif /* CUPS_RASTER_SYNCv1 */ dprintf("DEBUG2: Leaving cups_get_params()\n"); return (0); } /* * '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 */ dprintf2("DEBUG2: cups_get_space_params(%p, %p)\n", pdev, space_params); if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL) { switch (sscanf(cache_env, "%f%254s", &cache_size, cache_units)) { case 0 : cache_size = 8 * 1024 * 1024; break; 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 cache_size = 8 * 1024 * 1024; dprintf1("DEBUG2: cache_size = %.0f\n", cache_size); space_params->MaxBitmap = (int)cache_size; space_params->BufferSpace = (int)cache_size / 10; } /* * '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, c1, c2; /* 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 DEBUG dprintf6("DEBUG2: cups_map_cmyk(%p, %d, %d, %d, %d, %p)\n", pdev, c, m, y, k, out); #endif /* DEBUG */ /* * Convert the CMYK color to the destination colorspace... */ switch (cups->header.cupsColorSpace) { case CUPS_CSPACE_W : c0 = frac_1 - (c * 31 + m * 61 + y * 8) / 100 - k; if (c0 < 0) out[0] = 0; else if (c0 > frac_1) out[0] = (frac)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[c0]; break; case CUPS_CSPACE_RGBA : out[3] = frac_1; case CUPS_CSPACE_RGB : c0 = frac_1 - c - k; c1 = frac_1 - m - k; c2 = frac_1 - y - k; if (c0 < 0) out[0] = 0; else if (c0 > frac_1) out[0] = (frac)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[c0]; if (c1 < 0) out[1] = 0; else if (c1 > frac_1) out[1] = (frac)cupsDensity[frac_1]; else out[1] = (frac)cupsDensity[c1]; if (c2 < 0) out[2] = 0; else if (c2 > frac_1) out[2] = (frac)cupsDensity[frac_1]; else out[2] = (frac)cupsDensity[c2]; 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)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[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)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[c0]; if (c1 < 0) out[1] = 0; else if (c1 > frac_1) out[1] = (frac)cupsDensity[frac_1]; else out[1] = (frac)cupsDensity[c1]; if (c2 < 0) out[2] = 0; else if (c2 > frac_1) out[2] = (frac)cupsDensity[frac_1]; else out[2] = (frac)cupsDensity[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)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[c0]; if (c1 < 0) out[1] = 0; else if (c1 > frac_1) out[1] = (frac)cupsDensity[frac_1]; else out[1] = (frac)cupsDensity[c1]; if (c2 < 0) out[2] = 0; else if (c2 > frac_1) out[2] = (frac)cupsDensity[frac_1]; else out[2] = (frac)cupsDensity[c2]; break; case CUPS_CSPACE_RGBW : c = frac_1 - c; m = frac_1 - m; y = frac_1 - y; k = frac_1 - k; case CUPS_CSPACE_CMYK : if (c < 0) out[0] = 0; else if (c > frac_1) out[0] = (frac)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[c]; if (m < 0) out[1] = 0; else if (m > frac_1) out[1] = (frac)cupsDensity[frac_1]; else out[1] = (frac)cupsDensity[m]; if (y < 0) out[2] = 0; else if (y > frac_1) out[2] = (frac)cupsDensity[frac_1]; else out[2] = (frac)cupsDensity[y]; if (k < 0) out[3] = 0; else if (k > frac_1) out[3] = (frac)cupsDensity[frac_1]; else out[3] = (frac)cupsDensity[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)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[y]; if (m < 0) out[1] = 0; else if (m > frac_1) out[1] = (frac)cupsDensity[frac_1]; else out[1] = (frac)cupsDensity[m]; if (c < 0) out[2] = 0; else if (c > frac_1) out[2] = (frac)cupsDensity[frac_1]; else out[2] = (frac)cupsDensity[c]; if (k < 0) out[3] = 0; else if (k > frac_1) out[3] = (frac)cupsDensity[frac_1]; else out[3] = (frac)cupsDensity[k]; break; case CUPS_CSPACE_KCMYcm : case CUPS_CSPACE_KCMY : if (k < 0) out[0] = 0; else if (k > frac_1) out[0] = (frac)cupsDensity[frac_1]; else out[0] = (frac)cupsDensity[k]; if (c < 0) out[1] = 0; else if (c > frac_1) out[1] = (frac)cupsDensity[frac_1]; else out[1] = (frac)cupsDensity[c]; if (m < 0) out[2] = 0; else if (m > frac_1) out[2] = (frac)cupsDensity[frac_1]; else out[2] = (frac)cupsDensity[m]; if (y < 0) out[3] = 0; else if (y > frac_1) out[3] = (frac)cupsDensity[frac_1]; else out[3] = (frac)cupsDensity[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] = cupsDecodeLUT[c0]; out[1] = cupsDecodeLUT[c1]; out[2] = cupsDecodeLUT[c2]; break; # endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ } #ifdef DEBUG switch (cups->color_info.num_components) { default : case 1 : dprintf1("DEBUG2: \\=== COLOR %d\n", out[0]); break; case 3 : dprintf3("DEBUG2: \\=== COLOR %d, %d, %d\n", out[0], out[1], out[2]); break; case 4 : dprintf4("DEBUG2: \\=== COLOR %d, %d, %d, %d\n", out[0], out[1], out[2], out[3]); break; } #endif /* DEBUG */ } /* * '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 DEBUG2 dprintf3("DEBUG2: cups_map_gray(%p, %d, %p)\n", pdev, g, out); #endif /* DEBUG2 */ /* * 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_imager_state *pis,/* 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 DEBUG dprintf6("DEBUG2: cups_map_rgb(%p, %p, %d, %d, %d, %p)\n", pdev, pis, r, g, b, out); #endif /* DEBUG */ /* * 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 (cupsHaveProfile) { /* * Color correct CMY... */ tc = cupsMatrix[0][0][c] + cupsMatrix[0][1][m] + cupsMatrix[0][2][y]; tm = cupsMatrix[1][0][c] + cupsMatrix[1][1][m] + cupsMatrix[1][2][y]; ty = cupsMatrix[2][0][c] + cupsMatrix[2][1][m] + cupsMatrix[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 DEBUG dprintf5("DEBUG2: cups_map_cmyk_color(%p, %d, %d, %d, %d)\n", pdev, c, m, y, k); #endif /* DEBUG */ /* * Setup the color info data as needed... */ if (pdev->color_info.num_components == 0) cups_set_color_info(pdev); /* * Density correct... */ if (cupsHaveProfile) { c = cupsDensity[c]; m = cupsDensity[m]; y = cupsDensity[y]; k = cupsDensity[k]; } ic = cupsEncodeLUT[c]; im = cupsEncodeLUT[m]; iy = cupsEncodeLUT[y]; ik = cupsEncodeLUT[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 DEBUG dprintf9("DEBUG2: CMYK (%d,%d,%d,%d) -> CMYK %08x (%d,%d,%d,%d)\n", c, m, y, k, (unsigned)i, ic, im, iy, ik); #endif /* DEBUG */ /* * 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 DEBUG dprintf3("DEBUG2: cups_map_color_rgb(%p, %d, %p)\n", pdev, (unsigned)color, prgb); #endif /* DEBUG */ /* * Setup the color info data as needed... */ if (pdev->color_info.num_components == 0) cups_set_color_info(pdev); #ifdef DEBUG dprintf1("DEBUG2: COLOR %08x = ", (unsigned)color); #endif /* DEBUG */ /* * 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] = cupsDecodeLUT[c3]; break; case CUPS_CSPACE_W : prgb[0] = prgb[1] = prgb[2] = cupsDecodeLUT[c3]; break; case CUPS_CSPACE_RGB : prgb[0] = cupsDecodeLUT[c1]; prgb[1] = cupsDecodeLUT[c2]; prgb[2] = cupsDecodeLUT[c3]; break; case CUPS_CSPACE_RGBA : prgb[0] = cupsDecodeLUT[c0]; prgb[1] = cupsDecodeLUT[c1]; prgb[2] = cupsDecodeLUT[c2]; break; case CUPS_CSPACE_CMY : prgb[0] = cupsDecodeLUT[c1]; prgb[1] = cupsDecodeLUT[c2]; prgb[2] = cupsDecodeLUT[c3]; break; case CUPS_CSPACE_YMC : prgb[0] = cupsDecodeLUT[c3]; prgb[1] = cupsDecodeLUT[c2]; prgb[2] = cupsDecodeLUT[c1]; break; case CUPS_CSPACE_KCMY : case CUPS_CSPACE_KCMYcm : k = cupsDecodeLUT[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 : /* * cupsDecodeLUT actually maps to RGBW, not CMYK... */ k = cupsDecodeLUT[c3]; c = cupsDecodeLUT[c0] + k; m = cupsDecodeLUT[c1] + k; y = cupsDecodeLUT[c2] + k; if (c > gx_max_color_value) prgb[0] = gx_max_color_value; else prgb[0] = c; if (m > gx_max_color_value) prgb[1] = gx_max_color_value; else prgb[1] = m; if (y > gx_max_color_value) prgb[2] = gx_max_color_value; else prgb[2] = y; break; case CUPS_CSPACE_CMYK : k = cupsDecodeLUT[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 = cupsDecodeLUT[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 */ } dprintf3("DEBUG2: RGB values: %d,%d,%d\n", prgb[0], prgb[1], prgb[2]); 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 DEBUG dprintf4("DEBUG2: cups_map_rgb_color(%p, %d, %d, %d)\n", pdev, r, g, b); #endif /* DEBUG */ /* * Setup the color info data as needed... */ if (pdev->color_info.num_components == 0) cups_set_color_info(pdev); /* * Do color correction as needed... */ if (cupsHaveProfile) { /* * 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 = cupsMatrix[0][0][ic] + cupsMatrix[0][1][im] + cupsMatrix[0][2][iy] + ik; tm = cupsMatrix[1][0][ic] + cupsMatrix[1][1][im] + cupsMatrix[1][2][iy] + ik; ty = cupsMatrix[2][0][ic] + cupsMatrix[2][1][im] + cupsMatrix[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 - cupsDensity[gx_max_color_value]; else r = gx_max_color_value - cupsDensity[tc]; if (tm < 0) g = gx_max_color_value; else if (tm > gx_max_color_value) g = gx_max_color_value - cupsDensity[gx_max_color_value]; else g = gx_max_color_value - cupsDensity[tm]; if (ty < 0) b = gx_max_color_value; else if (ty > gx_max_color_value) b = gx_max_color_value - cupsDensity[gx_max_color_value]; else b = gx_max_color_value - cupsDensity[ty]; } /* * Convert the RGB color to a color index... */ switch (cups->header.cupsColorSpace) { case CUPS_CSPACE_W : i = cupsEncodeLUT[(r * 31 + g * 61 + b * 8) / 100]; break; case CUPS_CSPACE_RGB : ic = cupsEncodeLUT[r]; im = cupsEncodeLUT[g]; iy = cupsEncodeLUT[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 = 0x0e; break; case 2 : i = 0xfc; break; case 4 : i = 0xfff0; break; case 8 : i = 0xffffff00; break; #ifdef GX_COLOR_INDEX_TYPE case 16 : i = 0xffffffffffff0000; break; #endif /* GX_COLOR_INDEX_TYPE */ } break; } case CUPS_CSPACE_RGBA : ic = cupsEncodeLUT[r]; im = cupsEncodeLUT[g]; iy = cupsEncodeLUT[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 = cupsEncodeLUT[gx_max_color_value - (r * 31 + g * 61 + b * 8) / 100]; break; case CUPS_CSPACE_CMY : ic = cupsEncodeLUT[gx_max_color_value - r]; im = cupsEncodeLUT[gx_max_color_value - g]; iy = cupsEncodeLUT[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 = cupsEncodeLUT[gx_max_color_value - r]; im = cupsEncodeLUT[gx_max_color_value - g]; iy = cupsEncodeLUT[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 = cupsEncodeLUT[ic - ik]; im = cupsEncodeLUT[im - ik]; iy = cupsEncodeLUT[iy - ik]; ik = cupsEncodeLUT[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 DEBUG dprintf8("DEBUG2: CMY (%d,%d,%d) -> CMYK %08x (%d,%d,%d,%d)\n", r, g, b, (unsigned)i, ic, im, iy, ik); #endif /* DEBUG */ 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 = cupsEncodeLUT[ic - ik]; im = cupsEncodeLUT[im - ik]; iy = cupsEncodeLUT[iy - ik]; ik = cupsEncodeLUT[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 = cupsEncodeLUT[ic - ik]; im = cupsEncodeLUT[im - ik]; iy = cupsEncodeLUT[iy - ik]; ik = cupsEncodeLUT[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 = cupsEncodeLUT[ic - ik]; im = cupsEncodeLUT[im - ik]; iy = cupsEncodeLUT[iy - ik]; ik = cupsEncodeLUT[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) << 16) | ik; break; #endif /* GX_COLOR_INDEX_TYPE */ } break; # endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ } #ifdef DEBUG dprintf4("DEBUG2: RGB %d,%d,%d = %08x\n", r, g, b, (unsigned)i); #endif /* DEBUG */ 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 */ dprintf1("DEBUG2: cups_open(%p)\n", pdev); cups->printer_procs.get_space_params = cups_get_space_params; if (cups->page == 0) { dprintf("INFO: Processing page 1...\n"); cups->page = 1; } cups_set_color_info(pdev); if ((code = gdev_prn_open(pdev)) != 0) return (code); if (cupsPPD == NULL) cupsPPD = ppdOpenFile(getenv("PPD")); 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 */ FILE *fp, /* I - Output file */ int num_copies) /* I - Number of copies */ { int copy; /* Copy number */ int srcbytes; /* Byte width of scanline */ unsigned char *src, /* Scanline data */ *dst; /* Bitmap data */ (void)fp; /* reference unused file pointer to prevent compiler warning */ dprintf3("DEBUG2: cups_print_pages(%p, %p, %d)\n", pdev, fp, num_copies); /* * 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); dprintf4("DEBUG2: cupsBitsPerPixel = %d, cupsWidth = %d, cupsBytesPerLine = %d, srcbytes = %d\n", cups->header.cupsBitsPerPixel, cups->header.cupsWidth, cups->header.cupsBytesPerLine, srcbytes); src = (unsigned char *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), srcbytes, 1, "cups_print_pages"); if (src == NULL) /* can't allocate input buffer */ return_error(gs_error_VMerror); /* * Need an output buffer, too... */ dst = (unsigned char *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), cups->header.cupsBytesPerLine, 2, "cups_print_pages"); if (dst == NULL) /* can't allocate working area */ return_error(gs_error_VMerror); /* * See if the stream has been initialized yet... */ if (cups->stream == NULL) { if ((cups->stream = cupsRasterOpen(fileno(cups->file), CUPS_RASTER_WRITE)) == NULL) { perror("ERROR: Unable to open raster stream - "); gs_exit(gs_lib_ctx_get_non_gc_memory_t(), 0); } } /* * Output a page of graphics... */ if (num_copies < 1) num_copies = 1; if (cupsPPD != NULL && !cupsPPD->manual_copies) { cups->header.NumCopies = num_copies; num_copies = 1; } dprintf3("DEBUG2: cupsWidth = %d, cupsHeight = %d, cupsBytesPerLine = %d\n", cups->header.cupsWidth, cups->header.cupsHeight, cups->header.cupsBytesPerLine); for (copy = num_copies; copy > 0; copy --) { cupsRasterWriteHeader(cups->stream, &(cups->header)); if (pdev->color_info.num_components == 1) cups_print_chunked(pdev, src, dst, srcbytes); else switch (cups->header.cupsColorOrder) { case CUPS_ORDER_CHUNKED : cups_print_chunked(pdev, src, dst, srcbytes); break; case CUPS_ORDER_BANDED : cups_print_banded(pdev, src, dst, srcbytes); break; case CUPS_ORDER_PLANAR : cups_print_planar(pdev, src, dst, srcbytes); break; } } /* * Free temporary storage and return... */ gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)src, srcbytes, 1, "cups_print_pages"); gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)dst, cups->header.cupsBytesPerLine, 1, "cups_print_pages"); cups->page ++; dprintf1("INFO: Processing page %d...\n", cups->page); return (0); } /* * '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 */ #ifdef CUPS_RASTER_SYNCv1 char name[255]; /* Name of attribute */ float sf; /* cupsBorderlessScalingFactor */ #endif /* CUPS_RASTER_SYNCv1 */ float margins[4]; /* Physical margins of print */ 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; /* Space parameter data */ int width, /* New width of page */ height; /* New height of page */ ppd_attr_t *backside = NULL, *backsiderequiresflippedmargins = NULL; float swap; int xflip = 0, yflip = 0; dprintf2("DEBUG2: cups_put_params(%p, %p)\n", pdev, plist); /* * Process other options for CUPS... */ #define stringoption(name, sname) \ if ((code = param_read_string(plist, sname, &stringval)) < 0) \ { \ dprintf2("ERROR: Error setting %s to \"%s\"...\n", sname, \ (char *)stringval.data); \ param_signal_error(plist, sname, code); \ return (code); \ } \ else if (code == 0) \ { \ dprintf2("DEBUG: Setting %s to \"%s\"...\n", sname, \ (char *)stringval.data); \ 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) \ { \ dprintf2("ERROR: Error setting %s to %d...\n", sname, (int)intval); \ param_signal_error(plist, sname, code); \ return (code); \ } \ else if (code == 0) \ { \ dprintf2("DEBUG: Setting %s to %d...\n", sname, (int)intval); \ cups->header.name = (type)intval; \ } #define floatoption(name, sname) \ if ((code = param_read_float(plist, sname, &floatval)) < 0) \ { \ dprintf2("ERROR: Error setting %s to %.4f...\n", sname, (float)floatval); \ param_signal_error(plist, sname, code); \ return (code); \ } \ else if (code == 0) \ { \ dprintf2("DEBUG: Setting %s to %.4f...\n", sname, (float)floatval); \ 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) \ { \ dprintf2("ERROR: Error setting %s to %d...\n", sname, (int)boolval); \ param_signal_error(plist, sname, code); \ return (code); \ } \ if (code == 0) \ cups->header.name = CUPS_FALSE; \ } \ else if (code == 0) \ { \ dprintf2("DEBUG: Setting %s to %d...\n", sname, (int)boolval); \ 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) \ { \ dprintf1("ERROR: Error setting %s...\n", sname); \ param_signal_error(plist, sname, code); \ return (code); \ } \ if (code == 0) \ { \ dprintf1("DEBUG: Setting %s to zero\n", sname); \ for (i = 0; i < count; i ++) \ cups->header.name[i] = 0; \ } \ } \ else if (code == 0) \ { \ dprintf1("DEBUG: Setting %s to", sname); \ for (i = 0; i < count; i ++) \ dprintf1(" %d", (unsigned)(arrayval.data[i])); \ cups->header.name[i] = (unsigned)arrayval.data[i]; \ dprintf("...\n"); \ } 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; 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) intoption(LeadingEdge, "LeadingEdge", cups_edge_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; i < 16; i ++) { sprintf(name, "cupsInteger%d", i); intoption(cupsInteger[i],strdup(name), unsigned) } for (i = 0; i < 16; i ++) { sprintf(name, "cupsReal%d", i); floatoption(cupsReal[i], strdup(name)) } for (i = 0; i < 16; i ++) { sprintf(name, "cupsString%d", i); stringoption(cupsString[i], strdup(name)) } 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); return (code); } else if (code == 0) { if (cupsProfile != NULL) free(cupsProfile); cupsProfile = strdup((char *)stringval.data); } cups_set_color_info(pdev); /* * Then process standard page device options... */ if ((code = gdev_prn_put_params(pdev, plist)) < 0) return (code); /* * Update margins/sizes as needed... */ if (size_set) { /* * Compute the page margins... */ dprintf2("DEBUG: Updating PageSize to [%.0f %.0f]...\n", cups->MediaSize[0], cups->MediaSize[1]); memset(margins, 0, sizeof(margins)); cups->landscape = 0; if (cupsPPD != NULL) { dprintf1("DEBUG2: cups->header.Duplex = %d\n", cups->header.Duplex); dprintf1("DEBUG2: cups->page = %d\n", cups->page); dprintf1("DEBUG2: cupsPPD = %p\n", cupsPPD); backside = ppdFindAttr(cupsPPD, "cupsBackSide", NULL); if (backside) { dprintf1("DEBUG2: cupsBackSide = %s\n", backside->value); cupsPPD->flip_duplex = 0; } dprintf1("DEBUG2: cupsPPD->flip_duplex = %d\n", cupsPPD->flip_duplex); backsiderequiresflippedmargins = ppdFindAttr(cupsPPD, "APDuplexRequiresFlippedMargin", NULL); if (backsiderequiresflippedmargins) dprintf1("DEBUG2: APDuplexRequiresFlippedMargin = %s\n", backsiderequiresflippedmargins->value); if (cups->header.Duplex && (cups->header.Tumble && (backside && !strcasecmp(backside->value, "Flipped"))) && !(cups->page & 1)) { xflip = 1; if (backsiderequiresflippedmargins && !strcasecmp(backsiderequiresflippedmargins->value, "False")) yflip = 0; else 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")) yflip = 1; else yflip = 0; } else if (cups->header.Duplex && ((!cups->header.Tumble && (cupsPPD->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")) yflip = 0; else yflip = 1; } else { xflip = 0; yflip = 0; } /* * Find the matching page size... */ for (i = cupsPPD->num_sizes, size = cupsPPD->sizes; i > 0; i --, size ++) if (fabs(cups->MediaSize[1] - size->length) < 5.0 && fabs(cups->MediaSize[0] - size->width) < 5.0 && #ifdef CUPS_RASTER_SYNCv1 ((strlen(cups->header.cupsPageSizeName) == 0) || (strcasecmp(cups->header.cupsPageSizeName, size->name) == 0)) && #endif (!margins_set || (fabs(cups->HWMargins[0] - size->left) < 1.0 && fabs(cups->HWMargins[1] - size->bottom) < 1.0))) break; if (i > 0) { /* * Standard size... */ dprintf1("DEBUG: size = %s\n", size->name); gx_device_set_media_size(pdev, size->width, size->length); margins[0] = size->left / 72.0; margins[1] = size->bottom / 72.0; margins[2] = (size->width - size->right) / 72.0; margins[3] = (size->length - 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; } } else { /* * No matching portrait size; look for a matching size in * landscape orientation... */ for (i = cupsPPD->num_sizes, size = cupsPPD->sizes; i > 0; i --, size ++) if (fabs(cups->MediaSize[0] - size->length) < 5.0 && fabs(cups->MediaSize[1] - size->width) < 5.0 && #ifdef CUPS_RASTER_SYNCv1 ((strlen(cups->header.cupsPageSizeName) == 0) || (strcasecmp(cups->header.cupsPageSizeName, size->name) == 0)) && #endif (!margins_set || (fabs(cups->HWMargins[0] - size->left) < 1.0 && fabs(cups->HWMargins[1] - size->bottom) < 1.0))) break; if (i > 0) { /* * Standard size in landscape orientation... */ dprintf1("DEBUG: landscape size = %s\n", size->name); gx_device_set_media_size(pdev, size->length, size->width); cups->landscape = 1; margins[0] = (size->length - size->top) / 72.0; margins[1] = size->left / 72.0; margins[2] = size->bottom / 72.0; margins[3] = (size->width - 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; } } else { /* * Custom size... */ dprintf("DEBUG: size = Custom\n"); for (i = 0; i < 4; i ++) margins[i] = cupsPPD->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; } } } dprintf4("DEBUG: margins[] = [ %f %f %f %f ]\n", margins[0], margins[1], margins[2], margins[3]); } /* * Set the margins to update the bitmap size... */ gx_device_set_margins(pdev, margins, false); } /* * Set CUPS raster header values... */ cups->header.HWResolution[0] = pdev->HWResolution[0]; cups->header.HWResolution[1] = pdev->HWResolution[1]; #ifdef CUPS_RASTER_SYNCv1 cups->header.cupsPageSize[0] = pdev->MediaSize[0]; cups->header.cupsPageSize[1] = pdev->MediaSize[1]; cups->header.cupsImagingBBox[0] = pdev->HWMargins[0]; cups->header.cupsImagingBBox[1] = pdev->HWMargins[1]; cups->header.cupsImagingBBox[2] = pdev->MediaSize[0] - pdev->HWMargins[2]; cups->header.cupsImagingBBox[3] = pdev->MediaSize[1] - pdev->HWMargins[3]; if ((sf = cups->header.cupsBorderlessScalingFactor) < 1.0) sf = 1.0; cups->header.Margins[0] = pdev->HWMargins[0] * sf; cups->header.Margins[1] = pdev->HWMargins[1] * sf; cups->header.PageSize[0] = pdev->MediaSize[0] * sf; cups->header.PageSize[1] = pdev->MediaSize[1] * sf; cups->header.ImagingBoundingBox[0] = pdev->HWMargins[0] * sf; cups->header.ImagingBoundingBox[1] = pdev->HWMargins[1] * sf; cups->header.ImagingBoundingBox[2] = (pdev->MediaSize[0] - pdev->HWMargins[2]) * sf; cups->header.ImagingBoundingBox[3] = (pdev->MediaSize[1] - pdev->HWMargins[3]) * sf; #else cups->header.Margins[0] = pdev->HWMargins[0]; cups->header.Margins[1] = pdev->HWMargins[1]; cups->header.PageSize[0] = pdev->MediaSize[0]; cups->header.PageSize[1] = pdev->MediaSize[1]; cups->header.ImagingBoundingBox[0] = pdev->HWMargins[0]; cups->header.ImagingBoundingBox[1] = pdev->HWMargins[3]; cups->header.ImagingBoundingBox[2] = pdev->MediaSize[0] - pdev->HWMargins[2]; cups->header.ImagingBoundingBox[3] = pdev->MediaSize[1] - pdev->HWMargins[1]; #endif /* CUPS_RASTER_SYNCv1 */ /* * 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; } #ifdef CUPS_RASTER_SYNCv1 if (cups->header.cupsBorderlessScalingFactor > 1.0) { width *= cups->header.cupsBorderlessScalingFactor; height *= cups->header.cupsBorderlessScalingFactor; } #endif /* CUPS_RASTER_SYNCv1 */ /* * Don't reallocate memory unless the device has been opened... */ if (pdev->is_open) { /* * Device is open, so reallocate... */ dprintf4("DEBUG2: Reallocating memory, [%.0f %.0f] = %dx%d pixels...\n", pdev->MediaSize[0], pdev->MediaSize[1], width, height); sp = ((gx_device_printer *)pdev)->space_params; if ((code = gdev_prn_reallocate_memory(pdev, &sp, width, height)) < 0) return (code); } else { /* * Device isn't yet open, so just save the new width and height... */ dprintf4("DEBUG: Setting initial media size, [%.0f %.0f] = %dx%d pixels...\n", pdev->MediaSize[0], pdev->MediaSize[1], width, height); pdev->width = width; pdev->height = height; } } dprintf1("DEBUG2: ppd = %p\n", cupsPPD); dprintf2("DEBUG2: PageSize = [ %.3f %.3f ]\n", pdev->MediaSize[0], pdev->MediaSize[1]); dprintf4("DEBUG2: margins = [ %.3f %.3f %.3f %.3f ]\n", margins[0], margins[1], margins[2], margins[3]); dprintf2("DEBUG2: HWResolution = [ %.3f %.3f ]\n", pdev->HWResolution[0], pdev->HWResolution[1]); dprintf2("DEBUG2: width = %d, height = %d\n", pdev->width, pdev->height); dprintf4("DEBUG2: HWMargins = [ %.3f %.3f %.3f %.3f ]\n", pdev->HWMargins[0], pdev->HWMargins[1], pdev->HWMargins[2], pdev->HWMargins[3]); return (0); } /* * 'cups_set_color_info()' - Set the color information structure based on * the required output. */ private void 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 */ dprintf1("DEBUG2: cups_set_color_info(%p)\n", pdev); #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_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; break; case CUPS_CSPACE_CMY : case CUPS_CSPACE_YMC : case CUPS_CSPACE_RGB : #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 : 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_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_RGBW : 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_W : case CUPS_CSPACE_WHITE : case CUPS_CSPACE_RGB : case CUPS_CSPACE_RGBA : case CUPS_CSPACE_RGBW : # 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 */ cupsEncodeLUT[i] = j; #ifdef DEBUG if (i == 0 || cupsEncodeLUT[i] != cupsEncodeLUT[i - 1]) dprintf2("DEBUG2: cupsEncodeLUT[%d] = %d\n", i, (int)cupsEncodeLUT[i]); #endif /* DEBUG */ } dprintf1("DEBUG2: cupsEncodeLUT[0] = %d\n", (int)cupsEncodeLUT[0]); dprintf2("DEBUG2: cupsEncodeLUT[%d] = %d\n", gx_max_color_value, (int)cupsEncodeLUT[gx_max_color_value]); for (i = 0; i < cups->color_info.dither_grays; i ++) cupsDecodeLUT[i] = gx_max_color_value * i / max_lut; dprintf2("DEBUG: num_components = %d, depth = %d\n", cups->color_info.num_components, cups->color_info.depth); dprintf2("DEBUG: cupsColorSpace = %d, cupsColorOrder = %d\n", cups->header.cupsColorSpace, cups->header.cupsColorOrder); dprintf2("DEBUG: cupsBitsPerPixel = %d, cupsBitsPerColor = %d\n", cups->header.cupsBitsPerPixel, cups->header.cupsBitsPerColor); dprintf2("DEBUG: max_gray = %d, dither_grays = %d\n", cups->color_info.max_gray, cups->color_info.dither_grays); dprintf2("DEBUG: max_color = %d, dither_colors = %d\n", cups->color_info.max_color, cups->color_info.dither_colors); /* * Set the color profile as needed... */ cupsHaveProfile = 0; #ifdef dev_t_proc_encode_color if (cupsProfile) #else if (cupsProfile && cups->header.cupsBitsPerColor == 8) #endif /* dev_t_proc_encode_color */ { dprintf1("DEBUG: Using user-defined profile \"%s\"...\n", cupsProfile); if (sscanf(cupsProfile, "%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) dprintf("ERROR: User-defined profile does not contain 11 integers!\n"); else { cupsHaveProfile = 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 (cupsPPD) #else else if (cupsPPD && 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 = cupsPPD->profiles; i < cupsPPD->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 < cupsPPD->num_profiles) { dprintf("DEBUG: Using color profile in PPD file!\n"); cupsHaveProfile = 1; d = profile->density; g = profile->gamma; memcpy(m, profile->matrix, sizeof(m)); } } if (cupsHaveProfile) { for (i = 0; i < 3; i ++) for (j = 0; j < 3; j ++) for (k = 0; k <= CUPS_MAX_VALUE; k ++) { cupsMatrix[i][j][k] = (int)((float)k * m[i][j] + 0.5); if ((k & 4095) == 0) dprintf4("DEBUG2: cupsMatrix[%d][%d][%d] = %d\n", i, j, k, cupsMatrix[i][j][k]); } for (k = 0; k <= CUPS_MAX_VALUE; k ++) { cupsDensity[k] = (int)((float)CUPS_MAX_VALUE * d * pow((float)k / (float)CUPS_MAX_VALUE, g) + 0.5); if ((k & 4095) == 0) dprintf2("DEBUG2: cupsDensity[%d] = %d\n", k, cupsDensity[k]); } } else { for (k = 0; k <= CUPS_MAX_VALUE; k ++) cupsDensity[k] = k; } } /* * 'cups_sync_output()' - Keep the user informed of our status... */ private int /* O - Error status */ cups_sync_output(gx_device *pdev) /* I - Device info */ { dprintf1("INFO: Processing page %d...\n", cups->page); return (0); } /* * 'cups_print_chunked()' - Print a page of chunked pixels. */ static void 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 flip; /* Flip scanline? */ ppd_attr_t *backside = NULL; if (cupsPPD) { backside = ppdFindAttr(cupsPPD, "cupsBackSide", NULL); if (backside) cupsPPD->flip_duplex = 0; } if (cups->header.Duplex && cupsPPD && ((!cups->header.Tumble && (cupsPPD->flip_duplex || (backside && !strcasecmp(backside->value, "Rotated")))) || (cups->header.Tumble && (backside && (!strcasecmp(backside->value, "Flipped") || !strcasecmp(backside->value, "ManualTumble"))))) && !(cups->page & 1)) flip = 1; else flip = 0; dprintf2("DEBUG: cups_print_chunked - flip = %d, height = %d\n", flip, cups->height); /* * Loop through the page bitmap and write chunked pixels, reversing as * needed... */ for (y = 0; y < cups->height; y ++) { /* * Grab the scanline data... */ if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0) { dprintf1("ERROR: Unable to get scanline %d!\n", y); gs_exit(gs_lib_ctx_get_non_gc_memory_t(), 1); } if (flip) { /* * 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 = cupsRevUpper1[*srcptr & 15] | cupsRevLower1[*srcptr >> 4]; } break; case 2 : /* 2-bit W/K image */ for (srcptr += srcbytes - 1; count > 0; count --, srcptr --, dstptr ++) { *dstptr = cupsRevUpper2[*srcptr & 15] | cupsRevLower2[*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); } } } /* * 'cups_print_banded()' - Print a page of banded pixels. */ static void 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 flip; /* Flip scanline? */ ppd_attr_t *backside = NULL; if (cupsPPD) { backside = ppdFindAttr(cupsPPD, "cupsBackSide", NULL); if (backside) cupsPPD->flip_duplex = 0; } if (cups->header.Duplex && cupsPPD && ((!cups->header.Tumble && (cupsPPD->flip_duplex || (backside && !strcasecmp(backside->value, "Rotated")))) || (cups->header.Tumble && (backside && (!strcasecmp(backside->value, "Flipped") || !strcasecmp(backside->value, "ManualTumble"))))) && !(cups->page & 1)) flip = 1; else flip = 0; dprintf2("DEBUG: cups_print_banded - flip = %d, height = %d\n", flip, cups->height); /* * 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 = 0; y < cups->height; y ++) { /* * Grab the scanline data... */ if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0) { dprintf1("ERROR: Unable to get scanline %d!\n", y); gs_exit(gs_lib_ctx_get_non_gc_memory_t(), 1); } /* * 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 (flip) 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 = flip ? 1 << (x & 7) : 128; x > 0; x --, srcptr ++) { if (*srcptr & 0x40) *cptr |= bit; if (*srcptr & 0x20) *mptr |= bit; if (*srcptr & 0x10) *yptr |= bit; if (flip) { 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 (flip) { 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 = flip ? 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 (flip) { 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 (flip) { 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 = flip ? 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 (flip) { 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 = flip ? 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 (flip) { 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 (flip) 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 (flip) 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 (flip) 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 = flip ? 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 (flip) { 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 (flip) 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 (flip) 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 (flip) 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 = flip && (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 (flip) { 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 (!flip) { 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 = flip && (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 (flip) { 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 (!flip) { cptr ++; mptr ++; yptr ++; kptr ++; } break; } break; } break; case 8 : switch (cups->header.cupsColorSpace) { default : if (flip) 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 (flip) 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 (flip) 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 (flip) 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); } } /* * 'cups_print_planar()' - Print a page of planar pixels. */ static void 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 */ int 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) { dprintf1("ERROR: Unable to get scanline %d!\n", y); gs_exit(gs_lib_ctx_get_non_gc_memory_t(), 1); } /* * 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); } } /* * End of "$Id: gdevcups.c 9721 2009-05-04 10:59:18Z till $". */