xref: /plan9/sys/src/cmd/gs/src/zcsindex.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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