1 /* Copyright (C) 1998, 1999 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: gscrd.c,v 1.6 2004/08/04 19:36:12 stefan Exp $ */
18 /* CIE color rendering dictionary creation */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "string_.h"
22 #include "gx.h"
23 #include "gscdefs.h" /* for gs_lib_device_list */
24 #include "gsdevice.h"
25 #include "gserrors.h"
26 #include "gsmatrix.h" /* for gscolor2.h */
27 #include "gsparam.h"
28 #include "gsstruct.h"
29 #include "gsutil.h"
30 #include "gxcspace.h"
31 #include "gscolor2.h" /* for gs_set/currentcolorrendering */
32 #include "gscrd.h"
33
34 /* Import gs_lib_device_list() */
35 extern_gs_lib_device_list();
36
37 /* Allocator structure type */
38 public_st_cie_render1();
39 private
40 ENUM_PTRS_WITH(cie_render1_enum_ptrs, gs_cie_render *pcrd) return 0;
41 case 0: return ENUM_OBJ(pcrd->client_data);
42 case 1: return ENUM_OBJ(pcrd->RenderTable.lookup.table);
43 case 2: return (pcrd->RenderTable.lookup.table ?
44 ENUM_CONST_STRING(&pcrd->TransformPQR.proc_data) :
45 0);
46 ENUM_PTRS_END
47 private RELOC_PTRS_WITH(cie_render1_reloc_ptrs, gs_cie_render *pcrd);
48 RELOC_OBJ_VAR(pcrd->client_data);
49 if (pcrd->RenderTable.lookup.table)
50 {
51 RELOC_OBJ_VAR(pcrd->RenderTable.lookup.table);
52 RELOC_CONST_STRING_VAR(pcrd->TransformPQR.proc_data);
53 }
54 RELOC_PTRS_END
55
56 /* Default CRD procedures. */
57
58 private int
tpqr_identity(int index,floatp in,const gs_cie_wbsd * pwbsd,gs_cie_render * pcrd,float * out)59 tpqr_identity(int index, floatp in, const gs_cie_wbsd * pwbsd,
60 gs_cie_render * pcrd, float *out)
61 {
62 *out = in;
63 return 0;
64 }
65
66 private int
tpqr_from_cache(int index,floatp in,const gs_cie_wbsd * pwbsd,gs_cie_render * pcrd,float * out)67 tpqr_from_cache(int index, floatp in, const gs_cie_wbsd * pwbsd,
68 gs_cie_render * pcrd, float *out)
69 {
70 /*
71 * Since the TransformPQR cache is in the joint caches, not in the
72 * CRD cache, we can't actually implement this procedure.
73 * Instead, the place that calls it checks for it specially.
74 */
75 *out = in;
76 return 0;
77 }
78
79 private float
render_identity(floatp in,const gs_cie_render * pcrd)80 render_identity(floatp in, const gs_cie_render * pcrd)
81 {
82 return in;
83 }
84 private frac
render_table_identity(byte in,const gs_cie_render * pcrd)85 render_table_identity(byte in, const gs_cie_render * pcrd)
86 {
87 return byte2frac(in);
88 }
89
90 /* Transformation procedures that just consult the cache. */
91
92 private float
EncodeABC_cached_A(floatp in,const gs_cie_render * pcrd)93 EncodeABC_cached_A(floatp in, const gs_cie_render * pcrd)
94 {
95 return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[0].floats);
96 }
97 private float
EncodeABC_cached_B(floatp in,const gs_cie_render * pcrd)98 EncodeABC_cached_B(floatp in, const gs_cie_render * pcrd)
99 {
100 return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[1].floats);
101 }
102 private float
EncodeABC_cached_C(floatp in,const gs_cie_render * pcrd)103 EncodeABC_cached_C(floatp in, const gs_cie_render * pcrd)
104 {
105 return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[2].floats);
106 }
107 private float
EncodeLMN_cached_L(floatp in,const gs_cie_render * pcrd)108 EncodeLMN_cached_L(floatp in, const gs_cie_render * pcrd)
109 {
110 return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[0].floats);
111 }
112 private float
EncodeLMN_cached_M(floatp in,const gs_cie_render * pcrd)113 EncodeLMN_cached_M(floatp in, const gs_cie_render * pcrd)
114 {
115 return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[1].floats);
116 }
117 private float
EncodeLMN_cached_N(floatp in,const gs_cie_render * pcrd)118 EncodeLMN_cached_N(floatp in, const gs_cie_render * pcrd)
119 {
120 return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[2].floats);
121 }
122
123 private frac
RTT_cached(byte in,const gs_cie_render * pcrd,int i)124 RTT_cached(byte in, const gs_cie_render * pcrd, int i)
125 {
126 return pcrd->caches.RenderTableT[i].fracs.values[
127 in * (gx_cie_cache_size - 1) / 255
128 ];
129 }
130 private frac
RTT_cached_0(byte in,const gs_cie_render * pcrd)131 RTT_cached_0(byte in, const gs_cie_render * pcrd)
132 {
133 return RTT_cached(in, pcrd, 0);
134 }
135 private frac
RTT_cached_1(byte in,const gs_cie_render * pcrd)136 RTT_cached_1(byte in, const gs_cie_render * pcrd)
137 {
138 return RTT_cached(in, pcrd, 1);
139 }
140 private frac
RTT_cached_2(byte in,const gs_cie_render * pcrd)141 RTT_cached_2(byte in, const gs_cie_render * pcrd)
142 {
143 return RTT_cached(in, pcrd, 2);
144 }
145 private frac
RTT_cached_3(byte in,const gs_cie_render * pcrd)146 RTT_cached_3(byte in, const gs_cie_render * pcrd)
147 {
148 return RTT_cached(in, pcrd, 3);
149 }
150
151 /* Define the TransformPQR trampoline procedure that looks up proc_name. */
152
153 private int
tpqr_do_lookup(gs_cie_render * pcrd,const gx_device * dev_proto)154 tpqr_do_lookup(gs_cie_render *pcrd, const gx_device *dev_proto)
155 {
156 gx_device *dev;
157 gs_memory_t *mem = pcrd->rc.memory;
158 gs_c_param_list list;
159 gs_param_string proc_addr;
160 int code;
161
162 /* Device prototypes are const, so we must create a copy. */
163 code = gs_copydevice(&dev, dev_proto, mem);
164 if (code < 0)
165 return code;
166 gs_c_param_list_write(&list, mem);
167 code = param_request((gs_param_list *)&list,
168 pcrd->TransformPQR.proc_name);
169 if (code >= 0) {
170 code = gs_getdeviceparams(dev, (gs_param_list *)&list);
171 if (code >= 0) {
172 gs_c_param_list_read(&list);
173 code = param_read_string((gs_param_list *)&list,
174 pcrd->TransformPQR.proc_name,
175 &proc_addr);
176 if (code == 0 && proc_addr.size == sizeof(gs_cie_transform_proc)) {
177 memcpy(&pcrd->TransformPQR.proc, proc_addr.data,
178 sizeof(gs_cie_transform_proc));
179 } else
180 code = gs_note_error(gs_error_rangecheck);
181 }
182 }
183 gs_c_param_list_release(&list);
184 gs_free_object(mem, dev, "tpqr_do_lookup(device)");
185 return code;
186 }
187 private int
tpqr_lookup(int index,floatp in,const gs_cie_wbsd * pwbsd,gs_cie_render * pcrd,float * out)188 tpqr_lookup(int index, floatp in, const gs_cie_wbsd * pwbsd,
189 gs_cie_render * pcrd, float *out)
190 {
191 const gx_device *const *dev_list;
192 int count = gs_lib_device_list(&dev_list, NULL);
193 int i;
194 int code;
195
196 for (i = 0; i < count; ++i)
197 if (!strcmp(gs_devicename(dev_list[i]),
198 pcrd->TransformPQR.driver_name))
199 break;
200 if (i < count)
201 code = tpqr_do_lookup(pcrd, dev_list[i]);
202 else
203 code = gs_note_error(gs_error_undefined);
204 if (code < 0)
205 return code;
206 return pcrd->TransformPQR.proc(index, in, pwbsd, pcrd, out);
207 }
208
209
210 /* Default vectors. */
211 const gs_cie_transform_proc3 TransformPQR_default = {
212 tpqr_identity,
213 0, /* proc_name */
214 {0, 0}, /* proc_data */
215 0 /* driver_name */
216 };
217 const gs_cie_transform_proc3 TransformPQR_from_cache = {
218 tpqr_from_cache,
219 0, /* proc_name */
220 {0, 0}, /* proc_data */
221 0 /* driver_name */
222 };
223 const gs_cie_transform_proc TransformPQR_lookup_proc_name = tpqr_lookup;
224 const gs_cie_render_proc3 Encode_default = {
225 {render_identity, render_identity, render_identity}
226 };
227 const gs_cie_render_proc3 EncodeLMN_from_cache = {
228 {EncodeLMN_cached_L, EncodeLMN_cached_M, EncodeLMN_cached_N}
229 };
230 const gs_cie_render_proc3 EncodeABC_from_cache = {
231 {EncodeABC_cached_A, EncodeABC_cached_B, EncodeABC_cached_C}
232 };
233 const gs_cie_render_table_procs RenderTableT_default = {
234 {render_table_identity, render_table_identity, render_table_identity,
235 render_table_identity
236 }
237 };
238 const gs_cie_render_table_procs RenderTableT_from_cache = {
239 {RTT_cached_0, RTT_cached_1, RTT_cached_2, RTT_cached_3}
240 };
241
242 /*
243 * Allocate and minimally initialize a CRD. Note that this procedure sets
244 * the reference count of the structure to 1, not 0. gs_setcolorrendering
245 * will increment the reference count again, so unless you want the
246 * structure to stay allocated permanently (or until a garbage collection),
247 * you should call rc_decrement(pcrd, "client name") *after* calling
248 * gs_setcolorrendering.
249 */
250 int
gs_cie_render1_build(gs_cie_render ** ppcrd,gs_memory_t * mem,client_name_t cname)251 gs_cie_render1_build(gs_cie_render ** ppcrd, gs_memory_t * mem,
252 client_name_t cname)
253 {
254 gs_cie_render *pcrd;
255
256 rc_alloc_struct_1(pcrd, gs_cie_render, &st_cie_render1, mem,
257 return_error(gs_error_VMerror), cname);
258 pcrd->id = gs_next_ids(mem, 1);
259 /* Initialize pointers for the GC. */
260 pcrd->client_data = 0;
261 pcrd->RenderTable.lookup.table = 0;
262 pcrd->status = CIE_RENDER_STATUS_BUILT;
263 *ppcrd = pcrd;
264 return 0;
265 }
266
267 /*
268 * Initialize a CRD given all of the relevant parameters.
269 * Any of the pointers except WhitePoint may be zero, meaning
270 * use the default values.
271 *
272 * The actual point, matrix, range, and procedure values are copied into the
273 * CRD, but only the pointer to the color lookup table is copied.
274 *
275 * If pfrom_crd is not NULL, then if the EncodeLMN, EncodeABC, or
276 * RenderTable.T procedures indicate that the values exist only in the
277 * cache, the corresponding values will be copied from pfrom_crd.
278 * Note that NULL values for the individual pointers still represent
279 * default values.
280 */
281 int
gs_cie_render1_init_from(const gs_memory_t * mem,gs_cie_render * pcrd,void * client_data,const gs_cie_render * pfrom_crd,const gs_vector3 * WhitePoint,const gs_vector3 * BlackPoint,const gs_matrix3 * MatrixPQR,const gs_range3 * RangePQR,const gs_cie_transform_proc3 * TransformPQR,const gs_matrix3 * MatrixLMN,const gs_cie_render_proc3 * EncodeLMN,const gs_range3 * RangeLMN,const gs_matrix3 * MatrixABC,const gs_cie_render_proc3 * EncodeABC,const gs_range3 * RangeABC,const gs_cie_render_table_t * RenderTable)282 gs_cie_render1_init_from(const gs_memory_t *mem,
283 gs_cie_render * pcrd,
284 void *client_data,
285 const gs_cie_render * pfrom_crd,
286 const gs_vector3 * WhitePoint,
287 const gs_vector3 * BlackPoint,
288 const gs_matrix3 * MatrixPQR,
289 const gs_range3 * RangePQR,
290 const gs_cie_transform_proc3 * TransformPQR,
291 const gs_matrix3 * MatrixLMN,
292 const gs_cie_render_proc3 * EncodeLMN,
293 const gs_range3 * RangeLMN,
294 const gs_matrix3 * MatrixABC,
295 const gs_cie_render_proc3 * EncodeABC,
296 const gs_range3 * RangeABC,
297 const gs_cie_render_table_t * RenderTable)
298 {
299 pcrd->id = gs_next_ids(mem, 1);
300 pcrd->client_data = client_data;
301 pcrd->points.WhitePoint = *WhitePoint;
302 pcrd->points.BlackPoint =
303 *(BlackPoint ? BlackPoint : &BlackPoint_default);
304 pcrd->MatrixPQR = *(MatrixPQR ? MatrixPQR : &Matrix3_default);
305 pcrd->RangePQR = *(RangePQR ? RangePQR : &Range3_default);
306 pcrd->TransformPQR =
307 *(TransformPQR ? TransformPQR : &TransformPQR_default);
308 pcrd->MatrixLMN = *(MatrixLMN ? MatrixLMN : &Matrix3_default);
309 pcrd->EncodeLMN = *(EncodeLMN ? EncodeLMN : &Encode_default);
310 if (pfrom_crd &&
311 !memcmp(&pcrd->EncodeLMN, &EncodeLMN_from_cache,
312 sizeof(EncodeLMN_from_cache))
313 )
314 memcpy(&pcrd->caches.EncodeLMN, &pfrom_crd->caches.EncodeLMN,
315 sizeof(pcrd->caches.EncodeLMN));
316 pcrd->RangeLMN = *(RangeLMN ? RangeLMN : &Range3_default);
317 pcrd->MatrixABC = *(MatrixABC ? MatrixABC : &Matrix3_default);
318 pcrd->EncodeABC = *(EncodeABC ? EncodeABC : &Encode_default);
319 if (pfrom_crd &&
320 !memcmp(&pcrd->EncodeABC, &EncodeABC_from_cache,
321 sizeof(EncodeABC_from_cache))
322 )
323 memcpy(pcrd->caches.EncodeABC, pfrom_crd->caches.EncodeABC,
324 sizeof(pcrd->caches.EncodeABC));
325 pcrd->RangeABC = *(RangeABC ? RangeABC : &Range3_default);
326 if (RenderTable) {
327 pcrd->RenderTable = *RenderTable;
328 if (pfrom_crd &&
329 !memcmp(&pcrd->RenderTable.T, &RenderTableT_from_cache,
330 sizeof(RenderTableT_from_cache))
331 ) {
332 memcpy(pcrd->caches.RenderTableT, pfrom_crd->caches.RenderTableT,
333 sizeof(pcrd->caches.RenderTableT));
334 pcrd->caches.RenderTableT_is_identity =
335 pfrom_crd->caches.RenderTableT_is_identity;
336 }
337 } else {
338 pcrd->RenderTable.lookup.table = 0;
339 pcrd->RenderTable.T = RenderTableT_default;
340 }
341 pcrd->status = CIE_RENDER_STATUS_BUILT;
342 return 0;
343 }
344 /*
345 * Initialize a CRD without the option of copying cached values.
346 */
347 int
gs_cie_render1_initialize(const gs_memory_t * mem,gs_cie_render * pcrd,void * client_data,const gs_vector3 * WhitePoint,const gs_vector3 * BlackPoint,const gs_matrix3 * MatrixPQR,const gs_range3 * RangePQR,const gs_cie_transform_proc3 * TransformPQR,const gs_matrix3 * MatrixLMN,const gs_cie_render_proc3 * EncodeLMN,const gs_range3 * RangeLMN,const gs_matrix3 * MatrixABC,const gs_cie_render_proc3 * EncodeABC,const gs_range3 * RangeABC,const gs_cie_render_table_t * RenderTable)348 gs_cie_render1_initialize(const gs_memory_t *mem,
349 gs_cie_render * pcrd, void *client_data,
350 const gs_vector3 * WhitePoint,
351 const gs_vector3 * BlackPoint,
352 const gs_matrix3 * MatrixPQR,
353 const gs_range3 * RangePQR,
354 const gs_cie_transform_proc3 * TransformPQR,
355 const gs_matrix3 * MatrixLMN,
356 const gs_cie_render_proc3 * EncodeLMN,
357 const gs_range3 * RangeLMN,
358 const gs_matrix3 * MatrixABC,
359 const gs_cie_render_proc3 * EncodeABC,
360 const gs_range3 * RangeABC,
361 const gs_cie_render_table_t * RenderTable)
362 {
363 return gs_cie_render1_init_from(mem, pcrd, client_data, NULL,
364 WhitePoint, BlackPoint,
365 MatrixPQR, RangePQR, TransformPQR,
366 MatrixLMN, EncodeLMN, RangeLMN,
367 MatrixABC, EncodeABC, RangeABC,
368 RenderTable);
369 }
370