1 /* Copyright (C) 1993, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: zcsindex.c,v 1.8 2005/07/13 21:21:47 dan Exp $ */
18 /* Indexed color space support */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gsstruct.h"
23 #include "gscolor.h"
24 #include "gsmatrix.h" /* for gxcolor2.h */
25 #include "gxcspace.h"
26 #include "gxfixed.h" /* ditto */
27 #include "gxcolor2.h"
28 #include "estack.h"
29 #include "ialloc.h"
30 #include "icsmap.h"
31 #include "igstate.h"
32 #include "ivmspace.h"
33 #include "store.h"
34
35 /* Imported from gscolor2.c */
36 extern const gs_color_space_type gs_color_space_type_Indexed;
37
38 /* Forward references. */
39 private int indexed_map1(i_ctx_t *);
40
41 /* <array> .setindexedspace - */
42 /* The current color space is the base space for the indexed space. */
43 private int
zsetindexedspace(i_ctx_t * i_ctx_p)44 zsetindexedspace(i_ctx_t *i_ctx_p)
45 {
46 os_ptr op = osp;
47 ref *pproc = &istate->colorspace.procs.special.index_proc;
48 const ref *pcsa;
49 gs_color_space cs;
50 ref_colorspace cspace_old;
51 uint edepth = ref_stack_count(&e_stack);
52 int num_entries;
53 int code;
54
55 check_read_type(*op, t_array);
56 if (r_size(op) != 4)
57 return_error(e_rangecheck);
58 pcsa = op->value.const_refs + 1;
59 check_type_only(pcsa[1], t_integer);
60 if (pcsa[1].value.intval < 0 || pcsa[1].value.intval > 4095)
61 return_error(e_rangecheck);
62 num_entries = (int)pcsa[1].value.intval + 1;
63 cs = *gs_currentcolorspace(igs);
64 if (!cs.type->can_be_base_space)
65 return_error(e_rangecheck);
66 cspace_old = istate->colorspace;
67 /*
68 * We can't count on C compilers to recognize the aliasing
69 * that would be involved in a direct assignment.
70 * Formerly, we used the following code:
71 cs_base = *(gs_direct_color_space *)&cs;
72 cs.params.indexed.base_space = cs_base;
73 * But the Watcom C 10.0 compiler is too smart: it turns this into
74 * a direct assignment (and compiles incorrect code for it),
75 * defeating our purpose. Instead, we have to do it by brute force
76 * using memmove.
77 */
78 if (r_has_type(&pcsa[2], t_string)) {
79 int num_values = num_entries * cs_num_components(&cs);
80
81 check_read(pcsa[2]);
82 /*
83 * The PDF and PS specifications state that the lookup table must have
84 * the exact number of of data bytes needed. However we have found
85 * PDF files from Amyuni with extra data bytes. Acrobat 6.0 accepts
86 * these files without complaint, so we ignore the extra data.
87 */
88 if (r_size(&pcsa[2]) < num_values)
89 return_error(e_rangecheck);
90 memmove(&cs.params.indexed.base_space, &cs,
91 sizeof(cs.params.indexed.base_space));
92 gs_cspace_init(&cs, &gs_color_space_type_Indexed, imemory, false);
93 cs.params.indexed.lookup.table.data = pcsa[2].value.const_bytes;
94 cs.params.indexed.lookup.table.size = num_values;
95 cs.params.indexed.use_proc = 0;
96 make_null(pproc);
97 code = 0;
98 } else {
99 gs_indexed_map *map;
100
101 check_proc(pcsa[2]);
102 /*
103 * We have to call zcs_begin_map before moving the parameters,
104 * since if the color space is a DeviceN or Separation space,
105 * the memmove will overwrite its parameters.
106 */
107 code = zcs_begin_map(i_ctx_p, &map, &pcsa[2], num_entries,
108 (const gs_direct_color_space *)&cs,
109 indexed_map1);
110 if (code < 0)
111 return code;
112 memmove(&cs.params.indexed.base_space, &cs,
113 sizeof(cs.params.indexed.base_space));
114 gs_cspace_init(&cs, &gs_color_space_type_Indexed, imemory, false);
115 cs.params.indexed.use_proc = 1;
116 *pproc = pcsa[2];
117 map->proc.lookup_index = lookup_indexed_map;
118 cs.params.indexed.lookup.map = map;
119 }
120 cs.params.indexed.hival = num_entries - 1;
121 code = gs_setcolorspace(igs, &cs);
122 if (code < 0) {
123 istate->colorspace = cspace_old;
124 ref_stack_pop_to(&e_stack, edepth);
125 return code;
126 }
127 pop(1);
128 return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
129 }
130
131 /* Continuation procedure for saving mapped Indexed color values. */
132 private int
indexed_map1(i_ctx_t * i_ctx_p)133 indexed_map1(i_ctx_t *i_ctx_p)
134 {
135 os_ptr op = osp;
136 es_ptr ep = esp;
137 int i = (int)ep[csme_index].value.intval;
138
139 if (i >= 0) { /* i.e., not first time */
140 int m = (int)ep[csme_num_components].value.intval;
141 int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
142
143 if (code < 0)
144 return code;
145 pop(m);
146 op -= m;
147 if (i == (int)ep[csme_hival].value.intval) { /* All done. */
148 esp -= num_csme;
149 return o_pop_estack;
150 }
151 }
152 push(1);
153 ep[csme_index].value.intval = ++i;
154 make_int(op, i);
155 make_op_estack(ep + 1, indexed_map1);
156 ep[2] = ep[csme_proc]; /* lookup proc */
157 esp = ep + 2;
158 return o_push_estack;
159 }
160
161 /* ------ Initialization procedure ------ */
162
163 const op_def zcsindex_l2_op_defs[] =
164 {
165 op_def_begin_level2(),
166 {"1.setindexedspace", zsetindexedspace},
167 /* Internal operators */
168 {"1%indexed_map1", indexed_map1},
169 op_def_end(0)
170 };
171
172 /* ------ Internal routines ------ */
173
174 /* Allocate, and prepare to load, the index or tint map. */
175 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)176 zcs_begin_map(i_ctx_t *i_ctx_p, gs_indexed_map ** pmap, const ref * pproc,
177 int num_entries, const gs_direct_color_space * base_space,
178 op_proc_t map1)
179 {
180 gs_memory_t *mem = gs_state_memory(igs);
181 int space = imemory_space((gs_ref_memory_t *)mem);
182 int num_components =
183 cs_num_components((const gs_color_space *)base_space);
184 int num_values = num_entries * num_components;
185 gs_indexed_map *map;
186 int code = alloc_indexed_map(&map, num_values, mem,
187 "setcolorspace(mapped)");
188 es_ptr ep;
189
190 if (code < 0)
191 return code;
192 /* Set the reference count to 0 rather than 1. */
193 rc_init_free(map, mem, 0, free_indexed_map);
194 *pmap = map;
195 /* Map the entire set of color indices. Since the */
196 /* o-stack may not be able to hold N*4096 values, we have */
197 /* to load them into the cache as they are generated. */
198 check_estack(num_csme + 1); /* 1 extra for map1 proc */
199 ep = esp += num_csme;
200 make_int(ep + csme_num_components, num_components);
201 make_struct(ep + csme_map, space, map);
202 ep[csme_proc] = *pproc;
203 make_int(ep + csme_hival, num_entries - 1);
204 make_int(ep + csme_index, -1);
205 push_op_estack(map1);
206 return o_push_estack;
207 }
208