diff options
author | Ralph Giles <ralph.giles@artifex.com> | 2008-08-29 18:46:21 +0000 |
---|---|---|
committer | Ralph Giles <ralph.giles@artifex.com> | 2008-08-29 18:46:21 +0000 |
commit | 6ff2582d038f99b79178082b200bdfe73f734456 (patch) | |
tree | 6db04fc72813760fdc6912a15875ad83d57943df /gs/base/gdevperm.c | |
parent | 9d36ee856e41244d3cf0469fc0004d21e6911994 (diff) |
Split the source tree into two new directories.
PSSRC files are now in 'gs/psi'.
GLSRC files are now in 'gs/base'.
This is to facilitate build modularization and merging in the ghostpdl
tree.
NOTE: msvc32.mak is now in psi, not src.
git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@9048 a1074d23-0009-0410-80fe-cf8c14f379e6
Diffstat (limited to 'gs/base/gdevperm.c')
-rw-r--r-- | gs/base/gdevperm.c | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/gs/base/gdevperm.c b/gs/base/gdevperm.c new file mode 100644 index 000000000..61c7c6084 --- /dev/null +++ b/gs/base/gdevperm.c @@ -0,0 +1,473 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* Device which permutes color components, for testing DeviceN. */ +#include "gdevprn.h" +#include "gxdcconv.h" + +/** + * With no additional parameters, the device named "permute" looks to + * Ghostscript like a standard CMYK contone device, and outputs a PPM + * file, using a simple CMYK->RGB transform. This should be the + * baseline for regression testing. + * + * With the addition of -dPermute=1, the internal behavior changes + * somewhat, but in most cases the resulting rendered file should be + * the same. In this mode, the color model becomes "DeviceN" rather + * than "DeviceCMYK", the number of components goes to six, and the + * color model is considered to be the (yellow, cyan, cyan, magenta, + * 0, black) tuple. This is what's rendered into the memory + * buffer. Finally, on conversion to RGB for output, the colors are + * permuted back. + * + * As such, this code should check that all imaging code paths are + * 64-bit clean. Additionally, it should find incorrect code that + * assumes that the color model is one of DeviceGray, DeviceRGB, or + * DeviceCMYK. + **/ + +static dev_proc_print_page(perm_print_page); +static dev_proc_get_params(perm_get_params); +static dev_proc_put_params(perm_put_params); +static dev_proc_get_color_mapping_procs(perm_get_color_mapping_procs); +static dev_proc_get_color_comp_index(perm_get_color_comp_index); +static dev_proc_encode_color(perm_encode_color); +static dev_proc_decode_color(perm_decode_color); + +struct gx_device_perm_s { + gx_device_common; + gx_prn_device_common; + const char **std_colorant_names; + int num_std_colorant_names; /* Number of names in list */ + int mode; + int permute; +}; +typedef struct gx_device_perm_s gx_device_perm_t; + +static const gx_device_procs perm_procs = { + gdev_prn_open, + NULL, + NULL, + gdev_prn_output_page, + gdev_prn_close, + NULL, + NULL, + NULL, /* fill_rectangle */ + NULL, /* tile_rectangle */ + NULL, /* copy_mono */ + NULL, /* copy_color */ + NULL, /* draw_line */ + NULL, /* get_bits */ + perm_get_params, /* get_params */ + perm_put_params, /* put_params */ + NULL, /* map_cmyk_color - not used */ + NULL, /* get_xfont_procs */ + NULL, /* get_xfont_device */ + NULL, /* map_rgb_alpha_color */ + gx_page_device_get_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 */ + perm_get_color_mapping_procs, /* get_color_mapping_procs */ + perm_get_color_comp_index, + perm_encode_color, /* encode_color */ + perm_decode_color /* decode_color */ + +}; + +const gx_device_perm_t gs_perm_device = { + prn_device_body_extended(gx_device_perm_t, perm_procs, "permute", + DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72, 72, + 0, 0, 0, 0, + GX_DEVICE_COLOR_MAX_COMPONENTS, 4, + GX_CINFO_POLARITY_SUBTRACTIVE, + 32, 0, 255, 255, 256, 256, + GX_CINFO_SEP_LIN, + "DeviceN", + perm_print_page), + NULL, 0, 0, 0 +}; + + +static int +perm_print_page(gx_device_printer *pdev, FILE *pstream) +{ + int y; + gx_device_perm_t * const dev = (gx_device_perm_t *)pdev; + int ncomp = dev->num_std_colorant_names; + int raw_raster = pdev->width * ncomp; + byte *raw_line; + byte *cooked_line; + byte *row; + int code = 0; + int mode = dev->mode; + int permute = dev->permute; + + fprintf(pstream, "P6\n%d %d\n255\n", dev->width, dev->height); + raw_line = gs_alloc_bytes(pdev->memory, raw_raster, "perm_print_page"); + cooked_line = gs_alloc_bytes(pdev->memory, dev->width * 3, "perm_print_page"); + for (y = 0; y < dev->height; y++) { + int x; + code = gdev_prn_get_bits(pdev, y, raw_line, &row); + for (x = 0; x < dev->width; x++) { + int c, m, y, k; + int r, g, b; + + if (mode == 0) { + if (permute) { + c = row[x * ncomp + 1]; + m = row[x * ncomp + 3]; + y = row[x * ncomp + 0]; + k = row[x * ncomp + 5]; + } else { + c = row[x * ncomp]; + m = row[x * ncomp + 1]; + y = row[x * ncomp + 2]; + k = row[x * ncomp + 3]; + } + } else /* if (mode == 1) */ { + if (permute) { + c = row[x * ncomp + 1]; + m = row[x * ncomp + 3]; + y = row[x * ncomp + 0]; + k = 0; + } else { + c = row[x * ncomp]; + m = row[x * ncomp + 1]; + y = row[x * ncomp + 2]; + k = 0; + } + } + r = (255 - c) * (255 - k) / 255; + g = (255 - m) * (255 - k) / 255; + b = (255 - y) * (255 - k) / 255; + cooked_line[x * 3] = r; + cooked_line[x * 3 + 1] = g; + cooked_line[x * 3 + 2] = b; + } + fwrite(cooked_line, 1, dev->width * 3, pstream); + } + gs_free_object(pdev->memory, cooked_line, "perm_print_page"); + gs_free_object(pdev->memory, raw_line, "perm_print_page"); + return code; +} + +static void +perm_permute_cm(gx_device *pdev, frac out[]) +{ + gx_device_perm_t * const dev = (gx_device_perm_t *)pdev; + if (dev->permute) { + frac y; + out[5] = dev->mode == 0 ? out[3] : 0; + out[4] = frac_0; + y = out[2]; + out[3] = out[1]; + out[2] = out[0]; + out[1] = out[0]; + out[0] = y; + } +} + +static void +gray_cs_to_perm_cm_0(gx_device *dev, frac gray, frac out[]) +{ + out[0] = out[1] = out[2] = frac_0; + out[3] = frac_1 - gray; + perm_permute_cm(dev, out); +} + +static void +rgb_cs_to_perm_cm_0(gx_device *dev, const gs_imager_state *pis, + frac r, frac g, frac b, frac out[]) +{ + color_rgb_to_cmyk(r, g, b, pis, out); + perm_permute_cm(dev, out); +} + +static void +cmyk_cs_to_perm_cm_0(gx_device *dev, frac c, frac m, frac y, frac k, frac out[]) +{ + out[0] = c; + out[1] = m; + out[2] = y; + out[3] = k; + perm_permute_cm(dev, out); +}; + +static void +gray_cs_to_perm_cm_1(gx_device *dev, frac gray, frac out[]) +{ + out[0] = out[1] = out[2] = frac_1 - gray; + perm_permute_cm(dev, out); +} + +static void +rgb_cs_to_perm_cm_1(gx_device *dev, const gs_imager_state *pis, + frac r, frac g, frac b, frac out[]) +{ + out[0] = frac_1 - r; + out[1] = frac_1 - g; + out[2] = frac_1 - b; + perm_permute_cm(dev, out); +} + +static void +cmyk_cs_to_perm_cm_1(gx_device *dev, frac c, frac m, frac y, frac k, frac out[]) +{ + color_cmyk_to_rgb(c, m, y, k, NULL, out); + out[0] = frac_1 - out[0]; + out[1] = frac_1 - out[1]; + out[2] = frac_1 - out[2]; + perm_permute_cm(dev, out); +}; + +static const gx_cm_color_map_procs perm_cmapping_procs_0 = { + gray_cs_to_perm_cm_0, rgb_cs_to_perm_cm_0, cmyk_cs_to_perm_cm_0 +}; + +static const gx_cm_color_map_procs perm_cmapping_procs_1 = { + gray_cs_to_perm_cm_1, rgb_cs_to_perm_cm_1, cmyk_cs_to_perm_cm_1 +}; + +static const gx_cm_color_map_procs *perm_cmapping_procs[] = { + &perm_cmapping_procs_0, + &perm_cmapping_procs_1 +}; + +static const gx_cm_color_map_procs * +perm_get_color_mapping_procs(const gx_device *dev) +{ + const gx_device_perm_t * const pdev = (const gx_device_perm_t *)dev; + + if (pdev->mode < 0 || pdev->mode >= sizeof(perm_cmapping_procs) / sizeof(perm_cmapping_procs[0])) + return NULL; + return perm_cmapping_procs[pdev->mode]; +} + +#define compare_color_names(name, name_size, str, str_size) \ + (name_size == str_size && \ + (strncmp((const char *)name, (const char *)str, name_size) == 0)) + +static int +perm_get_color_comp_index(const gx_device *pdev, const char *pname, + int name_size, int component_type) +{ + const gx_device_perm_t * const dev = (const gx_device_perm_t *)pdev; + int n_separation_names = dev->num_std_colorant_names; + int i; + + for (i = 0; i < n_separation_names; i++) { + const char *sep_name = dev->std_colorant_names[i]; + if (compare_color_names(pname, name_size, sep_name, strlen(sep_name))) + return i; + } + return -1; +} + +/* Note: the encode and decode procs are entirely standard. The + permutation is all done in the color space to color model mapping. + In fact, we could probably just use the default here. +*/ + +/* + * Encode a list of colorant values into a gx_color_index_value. + */ +static gx_color_index +perm_encode_color(gx_device *dev, const gx_color_value colors[]) +{ + int bpc = 8; + int drop = sizeof(gx_color_value) * 8 - bpc; + gx_color_index color = 0; + int i = 0; + int ncomp = dev->color_info.num_components; + + for (; i<ncomp; i++) { + color <<= bpc; + color |= (colors[i] >> drop); + } + return (color == gx_no_color_index ? color ^ 1 : color); +} + +/* + * Decode a gx_color_index value back to a list of colorant values. + */ +static int +perm_decode_color(gx_device *dev, gx_color_index color, gx_color_value *out) +{ + int bpc = 8; + int drop = sizeof(gx_color_value) * 8 - bpc; + int mask = (1 << bpc) - 1; + int i = 0; + int ncomp = dev->color_info.num_components; + + for (; i<ncomp; i++) { + out[ncomp - i - 1] = (gx_color_value)((color & mask) << drop); + color >>= bpc; + } + return 0; +} + +#define set_param_array(a, d, s)\ + (a.data = d, a.size = s, a.persistent = false); + +static int +perm_get_params(gx_device *pdev, gs_param_list *plist) +{ + gx_device_perm_t * const dev = (gx_device_perm_t *)pdev; + int code; + + code = param_write_int(plist, "Permute", &dev->permute); + if (code >= 0) + code = param_write_int(plist, "Mode", &dev->mode); + /* + * We need to specify the SeparationColorNames if we are permuting the colors. + */ + if (code >= 0 && dev->permute == 1) { + int i; + /* Temp variables. The data is copied into the plist below. */ + gs_param_string_array scna; + gs_param_string scn[6]; + + set_param_array(scna, scn, dev->num_std_colorant_names); + /* Place colorant names into string array elements */ + for (i = 0; i < dev->num_std_colorant_names; i++) + param_string_from_string(scn[i], dev->std_colorant_names[i]); + /* + * Place the name array in the plist. This includes allocating + * memory for the name array element and the actual string array. + */ + code = param_write_name_array(plist, "SeparationColorNames", &scna); + } + if (code >= 0) + code = gdev_prn_get_params(pdev, plist); + return code; +} + +#undef set_param_array + +static const char * DeviceCMYKComponents[] = { + "Cyan", + "Magenta", + "Yellow", + "Black", + 0 /* List terminator */ +}; + +static const char * DeviceCMYComponents[] = { + "Cyan", + "Magenta", + "Yellow", + 0 /* List terminator */ +}; + +static const char * DeviceNComponents[] = { + "Yellow", + "Cyan", + "Cyan2", + "Magenta", + "Zero", + "Black", + 0 /* List terminator */ +}; + +static int +perm_set_color_model(gx_device_perm_t *dev, int mode, int permute) +{ + dev->mode = mode; + dev->permute = permute; + if (mode == 0 && permute == 0) { + dev->std_colorant_names = DeviceCMYKComponents; + dev->num_std_colorant_names = 4; + dev->color_info.cm_name = "DeviceCMYK"; + dev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + } else if (mode == 0 && permute == 1) { + dev->std_colorant_names = DeviceNComponents; + dev->num_std_colorant_names = 6; + dev->color_info.cm_name = "DeviceN"; + dev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + } else if (mode == 1 && permute == 0) { + dev->std_colorant_names = DeviceCMYComponents; + dev->num_std_colorant_names = 3; + dev->color_info.cm_name = "DeviceCMY"; + dev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + } else if (mode == 1 && permute == 1) { + dev->std_colorant_names = DeviceNComponents; + dev->num_std_colorant_names = 6; + dev->color_info.cm_name = "DeviceN"; + dev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + } else { + return -1; + } + dev->color_info.num_components = dev->num_std_colorant_names; + dev->color_info.depth = 8 * dev->num_std_colorant_names; + + return 0; +} + +static int +perm_put_params(gx_device *pdev, gs_param_list *plist) +{ + gx_device_perm_t * const dev = (gx_device_perm_t *)pdev; + gx_device_color_info save_info; + int code; + int new_permute = dev->permute; + int new_mode = dev->mode; + + code = param_read_int(plist, "Permute", &new_permute); + if (code < 0) + return code; + code = param_read_int(plist, "Mode", &new_mode); + if (code < 0) + return code; + if (new_mode < 0 || new_mode >= sizeof(perm_cmapping_procs) / sizeof(perm_cmapping_procs[0])) { + dlprintf("rangecheck!\n"); + return_error(gs_error_rangecheck); + } + dev->permute = new_permute; + dev->mode = new_mode; + save_info = pdev->color_info; + code = perm_set_color_model(dev, dev->mode, dev->permute); + if (code >= 0) + code = gdev_prn_put_params(pdev, plist); + if (code < 0) + pdev->color_info = save_info; + return code; +} + |