/* Copyright (C) 1993, 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: zcsindex.c,v 1.3.6.1.2.1 2003/01/17 00:49:05 giles Exp $ */ /* Indexed color space support */ #include "memory_.h" #include "ghost.h" #include "oper.h" #include "gsstruct.h" #include "gscolor.h" #include "gsmatrix.h" /* for gxcolor2.h */ #include "gxcspace.h" #include "gxfixed.h" /* ditto */ #include "gxcolor2.h" #include "estack.h" #include "ialloc.h" #include "icsmap.h" #include "igstate.h" #include "ivmspace.h" #include "store.h" /* Imported from gscolor2.c */ extern const gs_color_space_type gs_color_space_type_Indexed; /* Forward references. */ private int indexed_map1(P1(i_ctx_t *)); /* .setindexedspace - */ /* The current color space is the base space for the indexed space. */ private int zsetindexedspace(i_ctx_t *i_ctx_p) { os_ptr op = osp; ref *pproc = &istate->colorspace.procs.special.index_proc; const ref *pcsa; gs_color_space cs; ref_colorspace cspace_old; uint edepth = ref_stack_count(&e_stack); int num_entries; int code; check_read_type(*op, t_array); if (r_size(op) != 4) return_error(e_rangecheck); pcsa = op->value.const_refs + 1; check_type_only(pcsa[1], t_integer); if (pcsa[1].value.intval < 0 || pcsa[1].value.intval > 4095) return_error(e_rangecheck); num_entries = (int)pcsa[1].value.intval + 1; cs = *gs_currentcolorspace(igs); if (!cs.type->can_be_base_space) return_error(e_rangecheck); cspace_old = istate->colorspace; /* * We can't count on C compilers to recognize the aliasing * that would be involved in a direct assignment. * Formerly, we used the following code: cs_base = *(gs_direct_color_space *)&cs; cs.params.indexed.base_space = cs_base; * But the Watcom C 10.0 compiler is too smart: it turns this into * a direct assignment (and compiles incorrect code for it), * defeating our purpose. Instead, we have to do it by brute force * using memmove. */ if (r_has_type(&pcsa[2], t_string)) { int num_values = num_entries * cs_num_components(&cs); check_read(pcsa[2]); if (r_size(&pcsa[2]) != num_values) return_error(e_rangecheck); memmove(&cs.params.indexed.base_space, &cs, sizeof(cs.params.indexed.base_space)); gs_cspace_init(&cs, &gs_color_space_type_Indexed, NULL); cs.params.indexed.lookup.table.data = pcsa[2].value.const_bytes; cs.params.indexed.lookup.table.size = num_values; cs.params.indexed.use_proc = 0; make_null(pproc); code = 0; } else { gs_indexed_map *map; check_proc(pcsa[2]); /* * We have to call zcs_begin_map before moving the parameters, * since if the color space is a DeviceN or Separation space, * the memmove will overwrite its parameters. */ code = zcs_begin_map(i_ctx_p, &map, &pcsa[2], num_entries, (const gs_direct_color_space *)&cs, indexed_map1); if (code < 0) return code; memmove(&cs.params.indexed.base_space, &cs, sizeof(cs.params.indexed.base_space)); gs_cspace_init(&cs, &gs_color_space_type_Indexed, NULL); cs.params.indexed.use_proc = 1; *pproc = pcsa[2]; map->proc.lookup_index = lookup_indexed_map; cs.params.indexed.lookup.map = map; } cs.params.indexed.hival = num_entries - 1; code = gs_setcolorspace(igs, &cs); if (code < 0) { istate->colorspace = cspace_old; ref_stack_pop_to(&e_stack, edepth); return code; } pop(1); return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */ } /* Continuation procedure for saving mapped Indexed color values. */ private int indexed_map1(i_ctx_t *i_ctx_p) { os_ptr op = osp; es_ptr ep = esp; int i = (int)ep[csme_index].value.intval; if (i >= 0) { /* i.e., not first time */ int m = (int)ep[csme_num_components].value.intval; int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]); if (code < 0) return code; pop(m); op -= m; if (i == (int)ep[csme_hival].value.intval) { /* All done. */ esp -= num_csme; return o_pop_estack; } } push(1); ep[csme_index].value.intval = ++i; make_int(op, i); make_op_estack(ep + 1, indexed_map1); ep[2] = ep[csme_proc]; /* lookup proc */ esp = ep + 2; return o_push_estack; } /* ------ Initialization procedure ------ */ const op_def zcsindex_l2_op_defs[] = { op_def_begin_level2(), {"1.setindexedspace", zsetindexedspace}, /* Internal operators */ {"1%indexed_map1", indexed_map1}, op_def_end(0) }; /* ------ Internal routines ------ */ /* Allocate, and prepare to load, the index or tint map. */ int zcs_begin_map(i_ctx_t *i_ctx_p, gs_indexed_map ** pmap, const ref * pproc, int num_entries, const gs_direct_color_space * base_space, op_proc_t map1) { gs_memory_t *mem = gs_state_memory(igs); int space = imemory_space((gs_ref_memory_t *)mem); int num_components = cs_num_components((const gs_color_space *)base_space); int num_values = num_entries * num_components; gs_indexed_map *map; int code = alloc_indexed_map(&map, num_values, mem, "setcolorspace(mapped)"); es_ptr ep; if (code < 0) return code; /* Set the reference count to 0 rather than 1. */ rc_init_free(map, mem, 0, free_indexed_map); *pmap = map; /* Map the entire set of color indices. Since the */ /* o-stack may not be able to hold N*4096 values, we have */ /* to load them into the cache as they are generated. */ check_estack(num_csme + 1); /* 1 extra for map1 proc */ ep = esp += num_csme; make_int(ep + csme_num_components, num_components); make_struct(ep + csme_map, space, map); ep[csme_proc] = *pproc; make_int(ep + csme_hival, num_entries - 1); make_int(ep + csme_index, -1); push_op_estack(map1); return o_push_estack; }