/* Copyright (C) 1997, 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gscdevn.c,v 1.6.2.1.2.1 2003/01/17 00:49:02 giles Exp $ */ /* DeviceN color space and operation definition */ #include "memory_.h" #include "gx.h" #include "gserrors.h" #include "gscdevn.h" #include "gsfunc.h" #include "gsrefct.h" #include "gsmatrix.h" /* for gscolor2.h */ #include "gsstruct.h" #include "gxcspace.h" #include "gxcdevn.h" /* ---------------- Color space ---------------- */ /* GC descriptors */ gs_private_st_composite(st_color_space_DeviceN, gs_paint_color_space, "gs_color_space_DeviceN", cs_DeviceN_enum_ptrs, cs_DeviceN_reloc_ptrs); private_st_device_n_map(); /* Define the DeviceN color space type. */ private cs_proc_num_components(gx_num_components_DeviceN); private cs_proc_base_space(gx_alt_space_DeviceN); private cs_proc_equal(gx_equal_DeviceN); private cs_proc_init_color(gx_init_DeviceN); private cs_proc_restrict_color(gx_restrict_DeviceN); private cs_proc_concrete_space(gx_concrete_space_DeviceN); private cs_proc_concretize_color(gx_concretize_DeviceN); private cs_proc_remap_concrete_color(gx_remap_concrete_DeviceN); private cs_proc_install_cspace(gx_install_DeviceN); private cs_proc_adjust_cspace_count(gx_adjust_cspace_DeviceN); const gs_color_space_type gs_color_space_type_DeviceN = { gs_color_space_index_DeviceN, true, false, &st_color_space_DeviceN, gx_num_components_DeviceN, gx_alt_space_DeviceN, gx_equal_DeviceN, gx_init_DeviceN, gx_restrict_DeviceN, gx_concrete_space_DeviceN, gx_concretize_DeviceN, gx_remap_concrete_DeviceN, gx_default_remap_color, gx_install_DeviceN, gx_adjust_cspace_DeviceN, gx_no_adjust_color_count }; /* GC procedures */ private ENUM_PTRS_WITH(cs_DeviceN_enum_ptrs, gs_color_space *pcs) { return ENUM_USING(*pcs->params.device_n.alt_space.type->stype, &pcs->params.device_n.alt_space, sizeof(pcs->params.device_n.alt_space), index - 2); } ENUM_PTR(0, gs_color_space, params.device_n.names); ENUM_PTR(1, gs_color_space, params.device_n.map); ENUM_PTRS_END private RELOC_PTRS_WITH(cs_DeviceN_reloc_ptrs, gs_color_space *pcs) { RELOC_PTR(gs_color_space, params.device_n.names); RELOC_PTR(gs_color_space, params.device_n.map); RELOC_USING(*pcs->params.device_n.alt_space.type->stype, &pcs->params.device_n.alt_space, sizeof(gs_base_color_space)); } RELOC_PTRS_END /* ------ Public procedures ------ */ /* * Build a DeviceN color space. */ int gs_cspace_build_DeviceN( gs_color_space **ppcspace, gs_separation_name *psnames, uint num_components, const gs_color_space *palt_cspace, gs_memory_t *pmem ) { gs_color_space *pcspace = 0; /* bogus initialization */ gs_device_n_params *pcsdevn = 0; /* bogus initialization */ int code; if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space) return_error(gs_error_rangecheck); code = gs_cspace_alloc(&pcspace, &gs_color_space_type_DeviceN, pmem); if (code < 0) return code; pcsdevn = &pcspace->params.device_n; code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN"); if (code < 0) { gs_free_object(pmem, pcspace, "gs_cspace_build_DeviceN"); return code; } pcsdevn->names = psnames; pcsdevn->num_components = num_components; gs_cspace_init_from((gs_color_space *)&pcsdevn->alt_space, palt_cspace); *ppcspace = pcspace; return 0; } /* Allocate and initialize a DeviceN map. */ int alloc_device_n_map(gs_device_n_map ** ppmap, gs_memory_t * mem, client_name_t cname) { gs_device_n_map *pimap; rc_alloc_struct_1(pimap, gs_device_n_map, &st_device_n_map, mem, return_error(gs_error_VMerror), cname); pimap->tint_transform = 0; pimap->tint_transform_data = 0; pimap->cache_valid = false; *ppmap = pimap; return 0; } /* * Set the DeviceN tint transformation procedure. */ int gs_cspace_set_devn_proc(gs_color_space * pcspace, int (*proc)(P5(const gs_device_n_params *, const float *, float *, const gs_imager_state *, void * )), void *proc_data ) { gs_device_n_map *pimap; if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN) return_error(gs_error_rangecheck); pimap = pcspace->params.device_n.map; pimap->tint_transform = proc; pimap->tint_transform_data = proc_data; pimap->cache_valid = false; return 0; } /* Map a DeviceN color using a Function. */ private int map_devn_using_function(const gs_device_n_params *pcsdevn, const float *in, float *out, const gs_imager_state *pis, void *data) { gs_function_t *const pfn = data; return gs_function_evaluate(pfn, in, out); } /* * Set the DeviceN tint transformation procedure to a Function. */ int gs_cspace_set_devn_function(gs_color_space *pcspace, gs_function_t *pfn) { gs_device_n_map *pimap; if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN || pfn->params.m != pcspace->params.device_n.num_components || pfn->params.n != gs_color_space_num_components((gs_color_space *) &pcspace->params.device_n.alt_space) ) return_error(gs_error_rangecheck); pimap = pcspace->params.device_n.map; pimap->tint_transform = map_devn_using_function; pimap->tint_transform_data = pfn; pimap->cache_valid = false; return 0; } /* * If the DeviceN tint transformation procedure is a Function, * return the function object, otherwise return 0. */ gs_function_t * gs_cspace_get_devn_function(const gs_color_space *pcspace) { if (gs_color_space_get_index(pcspace) == gs_color_space_index_DeviceN && pcspace->params.device_n.map->tint_transform == map_devn_using_function) return pcspace->params.device_n.map->tint_transform_data; return 0; } /* ------ Color space implementation ------ */ /* Return the number of components of a DeviceN space. */ private int gx_num_components_DeviceN(const gs_color_space * pcs) { return pcs->params.device_n.num_components; } /* Return the alternate space of a DeviceN space. */ private const gs_color_space * gx_alt_space_DeviceN(const gs_color_space * pcs) { return (const gs_color_space *)&(pcs->params.device_n.alt_space); } /* Test whether one DeviceN color space equals another. */ private bool gx_equal_DeviceN(const gs_color_space *pcs1, const gs_color_space *pcs2) { return (gs_color_space_equal(gx_alt_space_DeviceN(pcs1), gx_alt_space_DeviceN(pcs2)) && pcs1->params.device_n.num_components == pcs2->params.device_n.num_components && !memcmp(pcs1->params.device_n.names, pcs2->params.device_n.names, pcs1->params.device_n.num_components * sizeof(pcs1->params.device_n.names[0])) && pcs1->params.device_n.map->tint_transform == pcs2->params.device_n.map->tint_transform && pcs1->params.device_n.map->tint_transform_data == pcs2->params.device_n.map->tint_transform_data); } /* Initialize a DeviceN color. */ private void gx_init_DeviceN(gs_client_color * pcc, const gs_color_space * pcs) { int i; for (i = 0; i < pcs->params.device_n.num_components; ++i) pcc->paint.values[i] = 1.0; } /* Force a DeviceN color into legal range. */ private void gx_restrict_DeviceN(gs_client_color * pcc, const gs_color_space * pcs) { int i; for (i = 0; i < pcs->params.device_n.num_components; ++i) { floatp value = pcc->paint.values[i]; pcc->paint.values[i] = (value <= 0 ? 0 : value >= 1 ? 1 : value); } } /* Remap a DeviceN color. */ private const gs_color_space * gx_concrete_space_DeviceN(const gs_color_space * pcs, const gs_imager_state * pis) { /* We don't support concrete DeviceN spaces yet. */ const gs_color_space *pacs = (const gs_color_space *)&pcs->params.device_n.alt_space; return cs_concrete_space(pacs, pis); } private int gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs, frac * pconc, const gs_imager_state * pis) { int code, tcode; gs_client_color cc; const gs_color_space *pacs = (const gs_color_space *)&pcs->params.device_n.alt_space; gs_device_n_map *map = pcs->params.device_n.map; /* Check the 1-element cache first. */ if (map->cache_valid) { int i; for (i = pcs->params.device_n.num_components; --i >= 0;) { if (map->tint[i] != pc->paint.values[i]) break; } if (i < 0) { int num_out = gs_color_space_num_components(pacs); for (i = 0; i < num_out; ++i) pconc[i] = map->conc[i]; return 0; } } /* * We always map into the alternate color space. We must preserve * tcode for implementing a semi-hack in the interpreter. */ tcode = (*pcs->params.device_n.map->tint_transform) (&pcs->params.device_n, pc->paint.values, &cc.paint.values[0], pis, pcs->params.device_n.map->tint_transform_data); if (tcode < 0) return tcode; code = (*pacs->type->concretize_color) (&cc, pacs, pconc, pis); return (code < 0 || tcode == 0 ? code : tcode); } private int gx_remap_concrete_DeviceN(const frac * pconc, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { /* We don't support concrete DeviceN colors yet. */ return_error(gs_error_rangecheck); } /* Install a DeviceN color space. */ private int gx_install_DeviceN(const gs_color_space * pcs, gs_state * pgs) { const gs_separation_name *names = pcs->params.device_n.names; uint i, j; const char none_str[] = "None"; const int none_size = strlen(none_str); /* * Postscript does not accept /None as a color component but it is * allowed in PDF so we accept it. Except for /None, no components * are allowed to have duplicated names. */ for (i = 1; i < pcs->params.device_n.num_components; ++i) { byte *pname; uint name_size; pcs->params.device_n.get_colorname_string(names[i], &pname, &name_size); if (name_size != none_size || (strncmp(none_str, (const char *) pname, name_size)!=0)) { for (j = 0; j < i; ++j) { if (names[i] == names[j]) return_error(gs_error_rangecheck); } } } return (*pcs->params.device_n.alt_space.type->install_cspace) ((const gs_color_space *) & pcs->params.device_n.alt_space, pgs); } /* Adjust the reference count of a DeviceN color space. */ private void gx_adjust_cspace_DeviceN(const gs_color_space * pcs, int delta) { rc_adjust_const(pcs->params.device_n.map, delta, "gx_adjust_DeviceN"); (*pcs->params.device_n.alt_space.type->adjust_cspace_count) ((const gs_color_space *)&pcs->params.device_n.alt_space, delta); }