summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gsncdummy.c')
-rw-r--r--base/gsncdummy.c1071
1 files changed, 1071 insertions, 0 deletions
diff --git a/base/gsncdummy.c b/base/gsncdummy.c
new file mode 100644
index 00000000..58654b94
--- /dev/null
+++ b/base/gsncdummy.c
@@ -0,0 +1,1071 @@
+/* Copyright (C) 2001-2019 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 the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Sample implementation for client custom processing of color spaces. */
+
+/*
+ * If this flag is 1 then we also do custom processing for the DeviceGray,
+ * DeviceRGB, and DeviceCMYK color spaces. For these color spaces, we
+ * convert all text to shades of red, all images to shades of green and
+ * all lines and fills to shades of blue. if the flag is 0 then our example
+ * only handles PANTONE colors (see comment below).
+ */
+
+/* Added these two defines so that I could compare to ghost script rendering color */
+
+#define OBJECT_TYPE_EXAMPLE 1 /* 0 --> disabled, 1 --> enabled */
+#define PANTONE_ONLY 0
+/*
+ * This module has been created to demonstrate how to support the use of
+ * PANTONE colors to the Ghostscript graphics library. PANTONE colors
+ * are specified in both PostScript and PDF files via the use of DeviceN
+ * or Separation color spaces.
+ *
+ * PANTONE is a registered trademark and PANTONE colors are a
+ * licensed product of Pantone Inc. See http://www.pantone.com
+ * for more information.
+ *
+ * See the comments at the start of src/gsnamecl.c for description of the
+ * client color processing routines.
+ *
+ * Since this is only a 'demo' implementation, the example implementation does
+ * not have some features which might be expected in a 'real' implementation.
+ *
+ * 1. The Pantone color data table does not have actual entries for all
+ * of the different Pantone colors. This data is not included since
+ * the values are dependent upon specific details of the output device,
+ * inks, etc.
+ * 2. Colors in PostScript and PDF are specified with by values between
+ * 0 and 1. The output colorant values are scaled linearly.
+ * 3. DeviceN color spaces can specify multiple colors. However this
+ * implementation assumes that if a PANTONE color is specified in a
+ * DeviceN color space, then only PANTONE colors or CMYK are present.
+ * This was done to keep the code simple. If other colors are present,
+ * then this implementation falls back to using the alternate color space
+ * specified with the DeviceN color space. (This is the normal PS
+ * and PDF operation.)
+ *
+ * See also src/zsncdummy.c for an example custom color callback.
+ */
+
+#include "stdpre.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gscdefs.h"
+#include "gscspace.h"
+#include "gxcspace.h"
+#include "gscie.h"
+#include "gsicc.h"
+#include "gxdevice.h"
+#include "gzstate.h"
+#include "gsutil.h"
+#include "gxcie.h"
+#include "gsncdummy.h"
+
+#if ENABLE_CUSTOM_COLOR_CALLBACK /* Defined in src/gsnamecl.h */
+
+/*
+ * Since this is only a 'demo' list, the list does have not entries for all
+ * of the different PANTONE colors. Creation of a real list is left as an
+ * exercise for the user.
+ */
+const pantone_list_t pantone_list[] = {
+ { "PantoneCyan", 1, 0, 0, 0 },
+ { "PantoneMagenta", 0, 1, 0, 0 },
+ { "PantoneYellow", 0, 0, 1, 0 },
+ { "PantoneBlack", 0, 0, 0, 1 },
+ { "Orange", 0, 1, .5, 0 }
+};
+
+/*
+ * We will handle color spaces that include both PANTONE colors, CMYK, and
+ * 'None'. 'None' is a special case in DeviceN color spaces. It has no
+ * effects upon the output color but it can be present in DeviceN color
+ * spaces in a PDF file. To simplify the code, we need pantone index values
+ * for these five 'colors'.
+ */
+#define PANTONE_NONE count_of(pantone_list)
+#define PANTONE_CYAN (PANTONE_NONE + 1)
+#define PANTONE_MAGENTA (PANTONE_NONE + 2)
+#define PANTONE_YELLOW (PANTONE_NONE + 3)
+#define PANTONE_BLACK (PANTONE_NONE + 4)
+
+/* Compare two names */
+#define compare_names(name1, name_size1, name2, name_size2) \
+ (name_size1 == name_size2 && \
+ (memcmp((const char *)name1, (const char *)name2, name_size1) == 0))
+
+/*
+ * Define a structure for holding our client specific data. In our demo,
+ * we are only supporting Separation and DeviceN color spaces. To make
+ * life simpler, we are using the same data structure for both types
+ * of color spaces.
+ */
+typedef struct demo_color_space_data_s {
+ /*
+ * All client color space data blocks must begin with a routine for
+ * handling the reference counts for the data block.
+ */
+ cs_proc_adjust_client_cspace_count((*client_adjust_cspace_count));
+
+ /* Use a reference count for knowing when to release the data block. */
+ int ref_count;
+
+ /* the memory allocator used */
+ gs_memory_t *memory;
+
+ /* A flag which indicates the client wants to process the color space. */
+ bool client_is_going_to_handle_color_space;
+
+ /*
+ * We store an index into our Pantone color translation table for each
+ * colorant in the color space.
+ */
+ int color_index[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ gs_gstate *CIEtoXYZ_pgs; /* Used to map CIE spaces to XYZ */
+ /* refer to gx_cie_to_xyz_alloc */
+} demo_color_space_data_t;
+
+gs_private_st_ptrs1(st_demo_color_space_data, demo_color_space_data_t,
+ "demo_color_space_data_t", demo_color_space_enum_ptrs,
+ demo_color_space_reloc_ptrs, CIEtoXYZ_pgs);
+
+/*
+ * Dummy install routine for color spaces which are not handled by the client.
+ */
+static bool
+client_install_no_op(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ return false; /* Do nothing */
+}
+
+/*
+ * Adjust the reference count on our client data,
+ * freeing it if necessary.
+ */
+static void
+client_adjust_cspace_count(const gs_color_space * pcs, int delta)
+{
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data);
+
+ pdata->ref_count += delta;
+ if (pdata->ref_count <= 0) {
+ /* Free up the CIE to XYZ gs_gstate if it was allocated */
+ if (pdata->CIEtoXYZ_pgs) {
+ gx_cie_to_xyz_free(pdata->CIEtoXYZ_pgs);
+ }
+ gs_free_object(pdata->memory, pdata, "client_adjust_cspace_count(pdata)");
+ }
+}
+
+/*
+ * Allocate a data block for holding our data for the client specific
+ * data for a color space. In our demo, we are only supporting the
+ * Separation and DeviceN color spaces. We use a single data structure
+ * to make the code simpler. We also provide sample hooks for a client
+ * that wants to convert ALL CIEBased color spaces to XYZ (or Lab).
+ */
+static demo_color_space_data_t *
+allocate_client_data_block(int initial_ref_count, gs_memory_t *mem)
+{
+ /*
+ * We allocate this with normal GC structure declarations since
+ * we need this to be able to allocate the gs_gstate for XYZ
+ * conversion.
+ * Since this is in stable memory, we use a simple reference count.
+ * See client_adjust_cspace_count.
+ */
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)gs_alloc_struct(mem, demo_color_space_data_t,
+ &st_demo_color_space_data, "allocate_client_data_block(pdata)");
+
+ if (pdata != NULL) {
+ memset(pdata, 0, sizeof(demo_color_space_data_t));
+ /*
+ * All client color space data blocks must have a pointer to a
+ * reference count adjust routine as their first field.
+ */
+ pdata->client_adjust_cspace_count = client_adjust_cspace_count;
+ pdata->ref_count = 1;
+ pdata->memory = mem;
+ }
+
+ return pdata;
+}
+
+static bool
+client_install_generic(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ demo_color_space_data_t * pclient_data;
+
+ /* Exit if we have already installed this color space. */
+ if (pcs->pclient_color_space_data != NULL)
+ return true;
+
+ pclient_data = allocate_client_data_block(1, pcs->rc.memory->stable_memory);
+ pcs->pclient_color_space_data = (client_color_space_data_t *) pclient_data;
+ if (pclient_data)
+ {
+ pclient_data->client_is_going_to_handle_color_space = 1;
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Check if we want to use the PANTONE color processing logic for the given
+ * Separation color space.
+ */
+static bool
+client_pantone_install_Separation(client_custom_color_params_t * pparam,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ const gs_separation_name name = pcs->params.separation.sep_name;
+ int pan_index;
+ byte * pname;
+ uint name_size;
+ gx_device * dev = pgs->device;
+ int num_pantone_colors = count_of(pantone_list);
+ bool use_custom_color_callback = false;
+
+ /* Exit if we have already installed this color space. */
+ if (pcs->pclient_color_space_data != NULL)
+ return true;
+
+ /*
+ * Get the character string and length for the component name.
+ */
+ pcs->params.separation.get_colorname_string(dev->memory, name,
+ &pname, &name_size);
+ /*
+ * Compare the colorant name to those in our PANTONE color list.
+ */
+ for (pan_index = 0; pan_index < num_pantone_colors ; pan_index++) {
+ const char * pan_name = pantone_list[pan_index].name;
+
+ if (compare_names(pname, name_size, pan_name, strlen(pan_name))) {
+ use_custom_color_callback = true;
+ break;
+ }
+ }
+
+ if (use_custom_color_callback) {
+ demo_color_space_data_t * pclient_data =
+ allocate_client_data_block(1, pcs->rc.memory->stable_memory);
+
+ if (pclient_data == NULL)
+ return false;
+ pclient_data->color_index[0] = pan_index;
+ pcs->pclient_color_space_data =
+ (client_color_space_data_t *) pclient_data;
+ }
+ return use_custom_color_callback;
+}
+
+/*
+ * Check if we want to use the PANTONE color processing logic for the given
+ * DeviceN color space.
+ */
+static bool
+client_pantone_install_DeviceN(client_custom_color_params_t * pparam,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ const gs_separation_name *names = pcs->params.device_n.names;
+ int num_comp = pcs->params.device_n.num_components;
+ int i;
+ int pan_index;
+ byte * pname;
+ uint name_size;
+ gx_device * dev = pgs->device;
+ int num_pantone_colors = count_of(pantone_list);
+ bool pantone_found = false;
+ bool other_separation_found = false;
+ bool use_pantone;
+ const char none_str[] = "None";
+ const uint none_size = strlen(none_str);
+ const char cyan_str[] = "Cyan";
+ const uint cyan_size = strlen(cyan_str);
+ const char magenta_str[] = "Magenta";
+ const uint magenta_size = strlen(magenta_str);
+ const char yellow_str[] = "Yellow";
+ const uint yellow_size = strlen(yellow_str);
+ const char black_str[] = "Black";
+ const uint black_size = strlen(black_str);
+ int pantone_color_index[GS_CLIENT_COLOR_MAX_COMPONENTS];
+
+ /* Exit if we have already installed this color space. */
+ if (pcs->pclient_color_space_data != NULL)
+ return true;
+
+ /*
+ * Now check the names of the color components.
+ */
+ for(i = 0; i < num_comp; i++ ) {
+ bool match = false;
+
+ /*
+ * Get the character string and length for the component name.
+ */
+ pcs->params.device_n.get_colorname_string(dev->memory, names[i],
+ &pname, &name_size);
+ /*
+ * Postscript does not include /None as a color component but it is
+ * allowed in PDF so we accept it. We simply skip components named
+ * 'None'.
+ */
+ if (compare_names(none_str, none_size, pname, name_size)) {
+ pantone_color_index[i] = PANTONE_NONE;
+ continue;
+ }
+ /*
+ * Check if our color space includes the CMYK process colors.
+ */
+ if (compare_names(cyan_str, cyan_size, pname, name_size)) {
+ pantone_color_index[i] = PANTONE_CYAN;
+ continue;
+ }
+ if (compare_names(magenta_str, magenta_size, pname, name_size)) {
+ pantone_color_index[i] = PANTONE_MAGENTA;
+ continue;
+ }
+ if (compare_names(yellow_str, yellow_size, pname, name_size)) {
+ pantone_color_index[i] = PANTONE_YELLOW;
+ continue;
+ }
+ if (compare_names(black_str, black_size, pname, name_size)) {
+ pantone_color_index[i] = PANTONE_BLACK;
+ continue;
+ }
+ /*
+ * Compare the colorant name to those in our Pantone color list.
+ */
+ for (pan_index = 0; pan_index < num_pantone_colors ; pan_index++) {
+ const char * pan_name = pantone_list[pan_index].name;
+
+ if (compare_names(pname, name_size, pan_name, strlen(pan_name))) {
+ pantone_color_index[i] = pan_index;
+ match = pantone_found = true;
+ break;
+ }
+ }
+ if (!match) { /* Exit if we find a non Pantone color */
+ other_separation_found = true;
+ break;
+ }
+ }
+ /*
+ * Handle this color space as a 'pantone color space' if we have only
+ * PANTONE colors and CMYK. Any other separations will force us to
+ * use the normal Ghostscript processing for a DeviceN color space.
+ */
+ use_pantone = pantone_found && !other_separation_found;
+ if (use_pantone) {
+ demo_color_space_data_t * pclient_data =
+ allocate_client_data_block(1, pcs->rc.memory->stable_memory);
+
+ if (pclient_data == NULL)
+ return false;
+ for(i = 0; i < num_comp; i++ )
+ pclient_data->color_index[i] = pantone_color_index[i];
+ pcs->pclient_color_space_data =
+ (client_color_space_data_t *) pclient_data;
+ }
+ return use_pantone;
+}
+
+/*
+ * Convert a set of color values in a 'PANTONE color space' into a device
+ * color values.
+ *
+ * This routine creates an equivalent CMYK color and then uses
+ * gx_remap_concrete_cmyk to convert this into device colorants. Note: It
+ * is possible to go directy to the output device colorants. However the
+ * pantone_install_xxx routines should verify that the expected device
+ * colorants match the actual device colorants. (For instance, Ghostscript
+ * can install temporary compositing devices for functions like handling
+ * PDF 1.4 transparency. The compositing devices may have a process color
+ * models which differ from the final output device.)
+ */
+static int
+client_pantone_remap_color(client_custom_color_params_t * pparam,
+ const frac * pconc, const demo_color_space_data_t * pparams,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select, int num_comp)
+{
+ int i, pantone_index, cvalue;
+ int cyan = 0;
+ int magenta = 0;
+ int yellow = 0;
+ int black = 0;
+ frac cc, cm, cy, ck;
+ const pantone_list_t * plist;
+
+ /*
+ * If the client color space data pointer is NULL then we are not processing
+ * this color space. The rangecheck error will indicate that GS should do
+ * its normal color space processing.
+ */
+ if (pparams == NULL)
+ return_error(gs_error_rangecheck);
+
+ /*
+ * Create a CMYK representation of the various colors in our color space.
+ * Note: If we have multiple components, then we do a simple sum of the
+ * CMYK equivalent for each color. If desired, a more complex handling is
+ * left to the user.
+ */
+ for (i = 0; i < num_comp; i++) {
+ cvalue = pconc[i];
+ pantone_index = pparams->color_index[i];
+ switch (pantone_index) {
+ case PANTONE_NONE:
+ break;
+ case PANTONE_CYAN:
+ cyan += cvalue;
+ break;
+ case PANTONE_MAGENTA:
+ magenta += cvalue;
+ break;
+ case PANTONE_YELLOW:
+ yellow += cvalue;
+ break;
+ case PANTONE_BLACK:
+ black += cvalue;
+ break;
+ default:
+ plist = &(pantone_list[pantone_index]);
+ cyan += (int) floor(cvalue * plist->c);
+ magenta += (int) floor(cvalue * plist->m);
+ yellow += (int) floor(cvalue * plist->y);
+ black += (int) floor(cvalue * plist->k);
+ break;
+ }
+ }
+ /* Clamp our color values */
+ cc = (cyan > frac_1) ? frac_1 : (cyan < frac_0) ? frac_0 : cyan;
+ cm = (magenta > frac_1) ? frac_1 : (magenta < frac_0) ? frac_0 : magenta;
+ cy = (yellow > frac_1) ? frac_1 : (yellow < frac_0) ? frac_0 : yellow;
+ ck = (black > frac_1) ? frac_1 : (black < frac_0) ? frac_0 : black;
+ gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pgs, dev, select);
+ return 0;
+}
+
+/*
+ * Convert a Separation color (with PANTONE colorants) into device color.
+ */
+static int
+client_pantone_remap_Separation(client_custom_color_params_t * pparam,
+ const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
+ const gs_gstate * pgs, gx_device * dev, gs_color_select_t select)
+{
+ return client_pantone_remap_color(pparam, pconc,
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data),
+ pdc, pgs, dev, select, 1);
+}
+
+/*
+ * Convert a DeviceN color (with PANTONE colorants) into device color.
+ */
+static int
+client_pantone_remap_DeviceN(client_custom_color_params_t * pparam,
+ const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
+ const gs_gstate * pgs, gx_device * dev, gs_color_select_t select)
+{
+ return client_pantone_remap_color(pparam, pconc,
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data),
+ pdc, pgs, dev, select, gs_color_space_num_components(pcs));
+}
+
+#if !PANTONE_ONLY
+
+/*
+ * Install a DeviceGray color space.
+ */
+static bool
+client_install_DeviceGray(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ /* Nothing to do in our demo */
+ return true;
+}
+
+/*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given colors and the object type.
+ */
+static int
+convert_intensity_into_device_color(const frac intensity,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select)
+{
+ frac cc, cm, cy, ck;
+
+ switch (dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS) {
+ case GS_TEXT_TAG: /* Make text red. */
+ cc = ck = 0;
+ cm = cy = frac_1 - intensity;
+ break;
+ case GS_IMAGE_TAG: /* Make images green. */
+ cm = ck = 0;
+ cc = cy = frac_1 - intensity;
+ break;
+ case GS_PATH_TAG: /* Make lines and fills blue. */
+ default:
+ cy = ck = 0;
+ cc = cm = frac_1 - intensity;
+ break;
+ }
+
+ /* Send CMYK colors to the device */
+ gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pgs, dev, select);
+ return 0;
+}
+
+/*
+ * Convert a DeviceGray color into device color.
+ */
+static int
+client_remap_DeviceGray(client_custom_color_params_t * pparams,
+ const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
+ const gs_gstate * pgs, gx_device * dev, gs_color_select_t select)
+{
+
+ #if OBJECT_TYPE_EXAMPLE
+
+ /* For demo and debug purposes, make our colors a function of the
+ * intensity of the given colors and the object type. */
+
+ frac intensity = pconc[0];
+ convert_intensity_into_device_color(intensity, pdc, pgs, dev, select);
+
+ #else
+
+ /* If desired, replace with your own color transformation */
+
+ gx_remap_concrete_gray(pconc[0], pdc, pgs, dev, select);
+
+ #endif
+
+ return 0;
+}
+
+/*
+ * Install a DeviceRGB color space.
+ */
+static bool
+client_install_DeviceRGB(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ /* Nothing to do in our demo */
+ dlprintf1("client_install_DeviceRGB ri = %d\n", pgs->renderingintent);
+ return true;
+}
+
+/*
+ * Convert a DeviceRGB color into device color.
+ */
+static int
+client_remap_DeviceRGB(client_custom_color_params_t * pparams,
+ const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
+ const gs_gstate * pgs, gx_device * dev, gs_color_select_t select)
+{
+
+ #if OBJECT_TYPE_EXAMPLE
+
+ /* For demo and debug purposes, make our colors a function of the
+ * intensity of the given colors and the object type. */
+
+ frac intensity = (frac)(pconc[0] * 0.30 + pconc[1] * 0.59 + pconc[2] * 0.11);
+ convert_intensity_into_device_color(intensity, pdc, pgs, dev, select);
+
+ #else
+
+ /* If desired, replace with your own color transformation */
+
+ gx_remap_concrete_rgb(pconc[0], pconc[1], pconc[2], pdc, pgs, dev, select);
+
+ #endif
+
+ return 0;
+}
+
+/*
+ * Install a DeviceCMYK color space.
+ */
+static bool
+client_install_DeviceCMYK(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ /* Nothing to do in our demo */
+ return true;
+}
+
+/*
+ * Convert a DeviceGray color into device color.
+ */
+static int
+client_remap_DeviceCMYK(client_custom_color_params_t * pparams,
+ const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
+ const gs_gstate * pgs, gx_device * dev, gs_color_select_t select)
+{
+
+ #if OBJECT_TYPE_EXAMPLE
+
+ /*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given colors and the object type. */
+
+ frac intensity = frac_1 - (frac)(pconc[0] * 0.30 + pconc[1] * 0.59
+ + pconc[2] * 0.11 + pconc[3]);
+
+ if (intensity < frac_0)
+ intensity = frac_0;
+ convert_intensity_into_device_color(intensity, pdc, pgs, dev, select);
+
+ #else
+
+ /* If desired, replace with your own color transformation */
+ gx_remap_concrete_cmyk(pconc[0], pconc[1], pconc[2], pconc[3],pdc, pgs, dev, select);
+
+ #endif
+
+ return 0;
+}
+
+/*
+ * Convert a floating point color value into a fixed (frac) color value
+ * given a specified floating point range.
+ */
+#define convert2frac(color, range) \
+ (color <= range.rmin) ? frac_0 \
+ : (color >= range.rmax) ? frac_1 \
+ : (frac) (frac_1 * \
+ (color - range.rmin) / (range.rmax - range.rmin))
+
+static bool
+client_install_CIEtoA(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ /* get ready for converting to XYZ */
+ demo_color_space_data_t * pdata;
+
+ /* Exit if we have already installed this color space. */
+ if (pcs->pclient_color_space_data != NULL)
+ return true;
+
+ pdata = allocate_client_data_block(1, pcs->rc.memory->stable_memory);
+ pcs->pclient_color_space_data = (client_color_space_data_t *) pdata;
+ if (pdata)
+ {
+ int code;
+ gs_cie_a *pcie = pcs->params.a;
+ gs_sample_loop_params_t lp;
+ int i;
+
+ pdata->client_is_going_to_handle_color_space = 1;
+
+ /* Fill the caches we need in the CIE color space */
+ gs_cie_cache_init(&pcie->caches.DecodeA.floats.params, &lp,
+ &pcie->RangeA, "DecodeA");
+ for (i = 0; i <= lp.N; ++i) {
+ float in = SAMPLE_LOOP_VALUE(i, lp);
+
+ pcie->caches.DecodeA.floats.values[i] = (*pcie->DecodeA)(in, pcie);
+ }
+ gx_cie_load_common_cache(&pcie->common, pgs);
+ gs_cie_a_complete(pcie);
+ if ((code=gs_cie_cs_complete(pgs, true)) >= 0) {
+ /* Now allocate the conversion gs_gstate in stable_memory */
+ /* so that the garbage collector won't free it */
+ code = gx_cie_to_xyz_alloc(&pdata->CIEtoXYZ_pgs, pcs,
+ pcs->rc.memory->stable_memory);
+ }
+ if (code < 0) {
+ client_adjust_cspace_count(pcs, -1); /* free it up */
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+client_install_CIEtoXYZ(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ /* get ready for converting to XYZ */
+ demo_color_space_data_t * pdata;
+
+ /* Exit if we have already installed this color space. */
+ if (pcs->pclient_color_space_data != NULL)
+ return true;
+
+ pdata = allocate_client_data_block(1, pcs->rc.memory->stable_memory);
+ pcs->pclient_color_space_data = (client_color_space_data_t *) pdata;
+ if (pdata)
+ {
+ int code;
+ const gs_cie_abc *pcie;
+
+ pdata->client_is_going_to_handle_color_space = 1;
+ switch (pcs->type->index) {
+ case gs_color_space_index_CIEDEF: {
+ gs_cie_def *pcie_def = pcs->params.def;
+
+ pcie = (gs_cie_abc *)pcie_def;
+ CIE_LOAD_CACHE_BODY(pcie_def->caches_def.DecodeDEF, pcie_def->RangeDEF.ranges,
+ &pcie_def->DecodeDEF, DecodeDEF_default, pcie_def,
+ "DecodeDEF");
+ break;
+ }
+ case gs_color_space_index_CIEDEFG: {
+ gs_cie_defg *pcie_defg = pcs->params.defg;
+
+ pcie = (gs_cie_abc *)pcie_defg;
+ CIE_LOAD_CACHE_BODY(pcie_defg->caches_defg.DecodeDEFG, pcie_defg->RangeDEFG.ranges,
+ &pcie_defg->DecodeDEFG, DecodeDEFG_default, pcie_defg,
+ "DecodeDEFG");
+ break;
+ }
+ case gs_color_space_index_CIEABC: {
+ pcie = pcs->params.abc;
+ break;
+ }
+ default:
+ /* can't happen since we only come here for certain color spaces */
+ return false;
+ }
+ /* Fill the caches we need in the CIE color space */
+ if ((code=gx_install_cie_abc((gs_cie_abc *)pcie, pgs)) >= 0) {
+ /* Now allocate the conversion gs_gstate in stable_memory */
+ /* so that the garbage collector won't free it */
+ code = gx_cie_to_xyz_alloc(&pdata->CIEtoXYZ_pgs, pcs,
+ pcs->rc.memory->stable_memory);
+ }
+ if (code < 0) {
+ client_adjust_cspace_count(pcs, -1); /* free it up */
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+client_install_ICCtoXYZ(client_custom_color_params_t * pparams,
+ gs_color_space * pcs, gs_gstate * pgs)
+{
+ int code;
+ const gs_icc_params * picc_params = (const gs_icc_params *)&pcs->params.icc;
+ gs_cie_icc * picc_info = picc_params->picc_info;
+ demo_color_space_data_t * pdata;
+
+ if (pcs->pclient_color_space_data != NULL)
+ return true;
+
+ pdata = allocate_client_data_block(1, pcs->rc.memory->stable_memory);
+ pcs->pclient_color_space_data = (client_color_space_data_t *) pdata;
+
+ /* Need to initialize the client data. The gs_gstate is what is needed in pdata->CIEtoXZY_ps */
+
+ /* update the stub information used by the joint caches */
+ gx_cie_load_common_cache(&picc_info->common, pgs);
+ gx_cie_common_complete(&picc_info->common);
+
+ if ((code=gs_cie_cs_complete(pgs, true)) < 0) {
+ client_adjust_cspace_count(pcs, -1); /* free it up */
+ return false;
+ }
+
+ /* Now allocate the conversion gs_gstate in stable_memory */
+ /* so that the garbage collector won't free it */
+ code = gx_cie_to_xyz_alloc(&pdata->CIEtoXYZ_pgs, pcs,
+ pcs->rc.memory->stable_memory);
+
+ if (code < 0) {
+ client_adjust_cspace_count(pcs, -1); /* free it up */
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Convert a CIEBasedA color into device color.
+ */
+static int
+client_remap_CIEBasedA(client_custom_color_params_t * pparams,
+ const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select)
+{
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data);
+ frac gray = convert2frac(pc->paint.values[0], pcs->params.a->RangeA);
+
+ /*** Demonstrate method to convert to XYZ ***/
+ if (pdata->CIEtoXYZ_pgs) {
+ frac xyz[3];
+
+ cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pgs);
+ /* We don't really do anything with these values, but this */
+ /* is where a real client could convert to a device color */
+ if_debug4('|', "[c]client_remap CIEA [%g] -> XYZ [%g, %g, %g]\n",
+ pc->paint.values[0],
+ frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2]));
+
+ }
+ /*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given color value and the object type.
+ */
+ return client_remap_DeviceGray(pparams, &gray, pcs, pdc, pgs, dev, select);
+}
+
+/*
+ * Convert a CIEBasedABC color into device color.
+ */
+static int
+client_remap_CIEBasedABC(client_custom_color_params_t * pparams,
+ const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select)
+{
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data);
+ frac rgb[3];
+ int i;
+
+ /*** Demonstrate method to convert to XYZ ***/
+ if (pdata->CIEtoXYZ_pgs) {
+ frac xyz[3];
+
+ cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pgs);
+ /* We don't really do anything with these values, but this */
+ /* is where a real client could convert to a device color */
+ if_debug6('|', "[c]client_remap CIEABC [%g, %g, %g] -> XYZ [%g, %g, %g]\n",
+ pc->paint.values[0], pc->paint.values[1], pc->paint.values[2],
+ frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2]));
+ }
+ /*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given color value and the object type. The color
+ * values could represent almost anything. However we are assuming
+ * that they are RGB values.
+ */
+ for (i = 0; i < 3; i++)
+ rgb[i] = convert2frac(pc->paint.values[i],
+ pcs->params.abc->RangeABC.ranges[i]);
+ return client_remap_DeviceRGB(pparams, rgb, pcs, pdc, pgs, dev, select);
+}
+
+/*
+ * Convert a CIEBasedDEF color into device color.
+ */
+static int
+client_remap_CIEBasedDEF(client_custom_color_params_t * pparams,
+ const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select)
+{
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data);
+ frac rgb[3];
+ int i;
+
+ /*** Demonstrate method to convert to XYZ ***/
+ if (pdata->CIEtoXYZ_pgs) {
+ frac xyz[3];
+
+ cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pgs);
+ /* We don't really do anything with these values, but this */
+ /* is where a real client could convert to a device color */
+ if_debug6('|', "[c]client_remap CIEDEF [%g, %g, %g] -> XYZ [%g, %g, %g]\n",
+ pc->paint.values[0], pc->paint.values[1], pc->paint.values[2],
+ frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2]));
+ }
+ /*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given color value and the object type. The color
+ * values could represent almost anything. However we are assuming
+ * that they are RGB values.
+ */
+ for (i = 0; i < 3; i++)
+ rgb[i] = convert2frac(pc->paint.values[i],
+ pcs->params.def->RangeDEF.ranges[i]);
+ return client_remap_DeviceRGB(pparams, rgb, pcs, pdc, pgs, dev, select);
+}
+
+/*
+ * Convert a CIEBasedDEFG color into device color.
+ */
+static int
+client_remap_CIEBasedDEFG(client_custom_color_params_t * pparams,
+ const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select)
+{
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data);
+ frac cmyk[4];
+ int i;
+
+ /*** Demonstrate method to convert to XYZ ***/
+ if (pdata->CIEtoXYZ_pgs) {
+ frac xyz[3];
+
+ cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pgs);
+ /* We don't really do anything with these values, but this */
+ /* is where a real client could convert to a device color */
+ if_debug7('|', "[c]client_remap CIEDEFG [%g, %g, %g] -> XYZ [%g, %g, %g]\n",
+ pc->paint.values[0], pc->paint.values[1], pc->paint.values[2],
+ pc->paint.values[3],
+ frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2]));
+ }
+ /*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given color value and the object type. The color
+ * values could represent almost anything. However we are assuming
+ * that they are CMYK values.
+ */
+ for (i = 0; i < 4; i++)
+ cmyk[i] = convert2frac(pc->paint.values[i],
+ pcs->params.defg->RangeDEFG.ranges[i]);
+ return client_remap_DeviceRGB(pparams, cmyk, pcs, pdc, pgs, dev, select);
+}
+
+/*
+ * Convert a ICCBased color into device color.
+ */
+static int
+client_remap_ICCBased(client_custom_color_params_t * pparams,
+ const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
+ gs_color_select_t select)
+{
+ demo_color_space_data_t * pdata =
+ (demo_color_space_data_t *)(pcs->pclient_color_space_data);
+ frac frac_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ int i, num_values = pcs->params.icc.picc_info->num_components;
+
+ /*** Demonstrate method to convert to XYZ ***/
+ if (pdata->CIEtoXYZ_pgs) {
+
+ frac xyz[3];
+
+ cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pgs);
+ /* We don't really do anything with these values, but this */
+ /* is where a real client could convert to a device color */
+ if_debug6('|', "[c]client_remap ICCBased [%g, %g, %g] -> XYZ [%g, %g, %g]\n",
+ pc->paint.values[0], pc->paint.values[1], pc->paint.values[2],
+ frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2]));
+ }
+
+ /*
+ * For demo and debug purposes, make our colors a function of the
+ * intensity of the given color value and the object type. The color
+ * values could represent almost anything. However based upon the
+ * number of color values, we are assuming that they are either
+ * gray, RGB, or CMYK values.
+ */
+ for (i = 0; i < num_values; i++)
+ frac_color[i] = convert2frac(pc->paint.values[i],
+ pcs->params.icc.picc_info->Range.ranges[i]);
+ switch (num_values) {
+ case 0:
+ case 2:
+ return_error(gs_error_rangecheck);
+ case 1:
+ return client_remap_DeviceGray(pparams, frac_color, pcs,
+ pdc, pgs, dev, select);
+ case 3:
+ return client_remap_DeviceRGB(pparams, frac_color, pcs,
+ pdc, pgs, dev, select);
+ case 4:
+ default:
+ return client_remap_DeviceCMYK(pparams, frac_color, pcs,
+ pdc, pgs, dev, select);
+ }
+}
+
+#undef convert2frac
+
+#endif /* NOT PANTONE_ONLY */
+
+#if PANTONE_ONLY
+
+ /*
+ * For PANTONE colors, we only need to handle Separation and DeviceN
+ * color spaces. These are the only color spaces that can have PANTONE
+ * colors.
+ */
+ client_custom_color_procs_t demo_procs = {
+ client_install_no_op, /* DeviceGray */
+ NULL,
+ client_install_no_op, /* DeviceRGB */
+ NULL,
+ client_install_no_op, /* DeviceCMYK */
+ NULL,
+ client_pantone_install_Separation, /* Separation */
+ client_pantone_remap_Separation,
+ client_pantone_install_DeviceN, /* DeviceN */
+ client_pantone_remap_DeviceN,
+ client_install_no_op, /* CIEBasedA */
+ NULL,
+ client_install_no_op, /* CIEBasedABC */
+ NULL,
+ client_install_no_op, /* CIEBasedDEF */
+ NULL,
+ client_install_no_op, /* CIEBasedDEFG */
+ NULL,
+ client_install_no_op, /* ICCBased */
+ NULL
+ };
+
+#else /* Not PANTONE_ONLY special */
+
+/*
+ * Client call back procedures for our demo which illustrates color
+ * processing based upon object type.
+ */
+client_custom_color_procs_t demo_procs = {
+ client_install_DeviceGray, /* DeviceGray */
+ client_remap_DeviceGray,
+ client_install_DeviceRGB, /* DeviceRGB */
+ client_remap_DeviceRGB,
+ client_install_DeviceCMYK, /* DeviceCMYK */
+ client_remap_DeviceCMYK,
+ client_pantone_install_Separation, /* Separation */
+ client_pantone_remap_Separation,
+ client_pantone_install_DeviceN, /* DeviceN */
+ client_pantone_remap_DeviceN,
+ client_install_CIEtoA, /* CIEBasedA */
+ client_remap_CIEBasedA,
+ client_install_CIEtoXYZ, /* CIEBasedABC */
+ client_remap_CIEBasedABC,
+ client_install_CIEtoXYZ, /* CIEBasedDEF */
+ client_remap_CIEBasedDEF,
+ client_install_CIEtoXYZ, /* CIEBasedDEFG */
+ client_remap_CIEBasedDEFG,
+ client_install_ICCtoXYZ, /* ICCBased */
+ client_remap_ICCBased
+};
+
+#endif /* PANTONE_ONLY_EXAMPLE */
+
+#endif /* ENABLE_CUSTOM_COLOR_CALLBACK */