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: gscrdp.c,v 1.6 2002/10/08 00:49:49 dan 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 "gsdevice.h"
24 #include "gserrors.h"
25 #include "gsmatrix.h" /* for gscolor2.h */
26 #include "gsstruct.h"
27 #include "gxcspace.h"
28 #include "gscolor2.h" /* for gs_set/currentcolorrendering */
29 #include "gscrdp.h"
30 #include "gxarith.h"
31
32 /* ---------------- Writing ---------------- */
33
34 /* Internal procedures for writing parameter values. */
35 private void
store_vector3(float * p,const gs_vector3 * pvec)36 store_vector3(float *p, const gs_vector3 * pvec)
37 {
38 p[0] = pvec->u, p[1] = pvec->v, p[2] = pvec->w;
39 }
40 private int
write_floats(gs_param_list * plist,gs_param_name key,const float * values,int size,gs_memory_t * mem)41 write_floats(gs_param_list * plist, gs_param_name key,
42 const float *values, int size, gs_memory_t * mem)
43 {
44 float *p = (float *)
45 gs_alloc_byte_array(mem, size, sizeof(float), "write_floats");
46 gs_param_float_array fa;
47
48 if (p == 0)
49 return_error(gs_error_VMerror);
50 memcpy(p, values, size * sizeof(float));
51
52 fa.data = p;
53 fa.size = size;
54 fa.persistent = true;
55 return param_write_float_array(plist, key, &fa);
56 }
57 private int
write_vector3(gs_param_list * plist,gs_param_name key,const gs_vector3 * pvec,gs_memory_t * mem)58 write_vector3(gs_param_list * plist, gs_param_name key,
59 const gs_vector3 * pvec, gs_memory_t * mem)
60 {
61 float values[3];
62
63 store_vector3(values, pvec);
64 return write_floats(plist, key, values, 3, mem);
65 }
66 private int
write_matrix3(gs_param_list * plist,gs_param_name key,const gs_matrix3 * pmat,gs_memory_t * mem)67 write_matrix3(gs_param_list * plist, gs_param_name key,
68 const gs_matrix3 * pmat, gs_memory_t * mem)
69 {
70 float values[9];
71
72 if (!memcmp(pmat, &Matrix3_default, sizeof(*pmat)))
73 return 0;
74 store_vector3(values, &pmat->cu);
75 store_vector3(values + 3, &pmat->cv);
76 store_vector3(values + 6, &pmat->cw);
77 return write_floats(plist, key, values, 9, mem);
78 }
79 private int
write_range3(gs_param_list * plist,gs_param_name key,const gs_range3 * prange,gs_memory_t * mem)80 write_range3(gs_param_list * plist, gs_param_name key,
81 const gs_range3 * prange, gs_memory_t * mem)
82 {
83 float values[6];
84
85 if (!memcmp(prange, &Range3_default, sizeof(*prange)))
86 return 0;
87 values[0] = prange->ranges[0].rmin, values[1] = prange->ranges[0].rmax;
88 values[2] = prange->ranges[1].rmin, values[3] = prange->ranges[1].rmax;
89 values[4] = prange->ranges[2].rmin, values[5] = prange->ranges[2].rmax;
90 return write_floats(plist, key, values, 6, mem);
91 }
92 private int
write_proc3(gs_param_list * plist,gs_param_name key,const gs_cie_render * pcrd,const gs_cie_render_proc3 * procs,const gs_range3 * domain,gs_memory_t * mem)93 write_proc3(gs_param_list * plist, gs_param_name key,
94 const gs_cie_render * pcrd, const gs_cie_render_proc3 * procs,
95 const gs_range3 * domain, gs_memory_t * mem)
96 {
97 float *values;
98 uint size = gx_cie_cache_size;
99 gs_param_float_array fa;
100 int i;
101
102 if (!memcmp(procs, &Encode_default, sizeof(*procs)))
103 return 0;
104 values = (float *)gs_alloc_byte_array(mem, size * 3, sizeof(float),
105 "write_proc3");
106
107 if (values == 0)
108 return_error(gs_error_VMerror);
109 for (i = 0; i < 3; ++i) {
110 double base = domain->ranges[i].rmin;
111 double scale = (domain->ranges[i].rmax - base) / (size - 1);
112 int j;
113
114 for (j = 0; j < size; ++j)
115 values[i * size + j] =
116 (*procs->procs[i]) (j * scale + base, pcrd);
117 }
118 fa.data = values;
119 fa.size = size * 3;
120 fa.persistent = true;
121 return param_write_float_array(plist, key, &fa);
122 }
123
124 /* Write a CRD as a device parameter. */
125 int
param_write_cie_render1(gs_param_list * plist,gs_param_name key,gs_cie_render * pcrd,gs_memory_t * mem)126 param_write_cie_render1(gs_param_list * plist, gs_param_name key,
127 gs_cie_render * pcrd, gs_memory_t * mem)
128 {
129 gs_param_dict dict;
130 int code, dcode;
131
132 dict.size = 20;
133 if ((code = param_begin_write_dict(plist, key, &dict, false)) < 0)
134 return code;
135 code = param_put_cie_render1(dict.list, pcrd, mem);
136 dcode = param_end_write_dict(plist, key, &dict);
137 return (code < 0 ? code : dcode);
138 }
139
140 /* Write a CRD directly to a parameter list. */
141 int
param_put_cie_render1(gs_param_list * plist,gs_cie_render * pcrd,gs_memory_t * mem)142 param_put_cie_render1(gs_param_list * plist, gs_cie_render * pcrd,
143 gs_memory_t * mem)
144 {
145 int crd_type = GX_DEVICE_CRD1_TYPE;
146 int code = gs_cie_render_sample(pcrd); /* we need RenderTableT_is_id' */
147
148 if (code < 0)
149 return code;
150 if (pcrd->TransformPQR.proc_name) {
151 gs_param_string pn, pd;
152
153 param_string_from_string(pn, pcrd->TransformPQR.proc_name);
154 pn.size++; /* include terminating null */
155 pd.data = pcrd->TransformPQR.proc_data.data;
156 pd.size = pcrd->TransformPQR.proc_data.size;
157 pd.persistent = true; /****** WRONG ******/
158 if ((code = param_write_name(plist, "TransformPQRName", &pn)) < 0 ||
159 (code = param_write_string(plist, "TransformPQRData", &pd)) < 0
160 )
161 return code;
162 }
163 else if (pcrd->TransformPQR.proc != TransformPQR_default.proc) {
164 /* We have no way to represent the procedure, so return an error. */
165 return_error(gs_error_rangecheck);
166 }
167 if ((code = param_write_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
168 (code = write_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint, mem)) < 0
169 )
170 return code;
171 if (memcmp(&pcrd->points.BlackPoint, &BlackPoint_default,
172 sizeof(pcrd->points.BlackPoint))) {
173 if ((code = write_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint, mem)) < 0)
174 return code;
175 }
176 if ((code = write_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR, mem)) < 0 ||
177 (code = write_range3(plist, "RangePQR", &pcrd->RangePQR, mem)) < 0 ||
178 /* TransformPQR is handled separately */
179 (code = write_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN, mem)) < 0 ||
180 (code = write_proc3(plist, "EncodeLMNValues", pcrd,
181 &pcrd->EncodeLMN, &pcrd->DomainLMN, mem)) < 0 ||
182 (code = write_range3(plist, "RangeLMN", &pcrd->RangeLMN, mem)) < 0 ||
183 (code = write_matrix3(plist, "MatrixABC", &pcrd->MatrixABC, mem)) < 0 ||
184 (code = write_proc3(plist, "EncodeABCValues", pcrd,
185 &pcrd->EncodeABC, &pcrd->DomainABC, mem)) < 0 ||
186 (code = write_range3(plist, "RangeABC", &pcrd->RangeABC, mem)) < 0
187 )
188 return code;
189 if (pcrd->RenderTable.lookup.table) {
190 int n = pcrd->RenderTable.lookup.n;
191 int m = pcrd->RenderTable.lookup.m;
192 int na = pcrd->RenderTable.lookup.dims[0];
193 int *size = (int *)
194 gs_alloc_byte_array(mem, n + 1, sizeof(int), "RenderTableSize");
195
196 /*
197 * In principle, we should use gs_alloc_struct_array with a
198 * type descriptor for gs_param_string. However, it is widely
199 * assumed that parameter lists are transient, and don't require
200 * accurate GC information; so we can get away with allocating
201 * the string table as bytes.
202 */
203 gs_param_string *table =
204 (gs_param_string *)
205 gs_alloc_byte_array(mem, na, sizeof(gs_param_string),
206 "RenderTableTable");
207 gs_param_int_array ia;
208
209 if (size == 0 || table == 0)
210 code = gs_note_error(gs_error_VMerror);
211 else {
212 memcpy(size, pcrd->RenderTable.lookup.dims, sizeof(int) * n);
213
214 size[n] = m;
215 ia.data = size;
216 ia.size = n + 1;
217 ia.persistent = true;
218 code = param_write_int_array(plist, "RenderTableSize", &ia);
219 }
220 if (code >= 0) {
221 gs_param_string_array sa;
222 int a;
223
224 for (a = 0; a < na; ++a)
225 table[a].data = pcrd->RenderTable.lookup.table[a].data,
226 table[a].size = pcrd->RenderTable.lookup.table[a].size,
227 table[a].persistent = true;
228 sa.data = table;
229 sa.size = na;
230 sa.persistent = true;
231 code = param_write_string_array(plist, "RenderTableTable", &sa);
232 if (code >= 0 && !pcrd->caches.RenderTableT_is_identity) {
233 /****** WRITE RenderTableTValues LIKE write_proc3 ******/
234 uint size = gx_cie_cache_size;
235 float *values =
236 (float *)gs_alloc_byte_array(mem, size * m,
237 sizeof(float),
238 "write_proc3");
239 gs_param_float_array fa;
240 int i;
241
242 if (values == 0)
243 return_error(gs_error_VMerror);
244 for (i = 0; i < m; ++i) {
245 double scale = 255.0 / (size - 1);
246 int j;
247
248 for (j = 0; j < size; ++j)
249 values[i * size + j] =
250 frac2float((*pcrd->RenderTable.T.procs[i])
251 ((byte)(j * scale), pcrd));
252 }
253 fa.data = values;
254 fa.size = size * m;
255 fa.persistent = true;
256 code = param_write_float_array(plist, "RenderTableTValues",
257 &fa);
258 }
259 }
260 if (code < 0) {
261 gs_free_object(mem, table, "RenderTableTable");
262 gs_free_object(mem, size, "RenderTableSize");
263 return code;
264 }
265 }
266 return code;
267 }
268
269 /* ---------------- Reading ---------------- */
270
271 /* Internal procedures for reading parameter values. */
272 private void
load_vector3(gs_vector3 * pvec,const float * p)273 load_vector3(gs_vector3 * pvec, const float *p)
274 {
275 pvec->u = p[0], pvec->v = p[1], pvec->w = p[2];
276 }
277 private int
read_floats(gs_param_list * plist,gs_param_name key,float * values,int count)278 read_floats(gs_param_list * plist, gs_param_name key, float *values, int count)
279 {
280 gs_param_float_array fa;
281 int code = param_read_float_array(plist, key, &fa);
282
283 if (code)
284 return code;
285 if (fa.size != count)
286 return_error(gs_error_rangecheck);
287 memcpy(values, fa.data, sizeof(float) * count);
288
289 return 0;
290 }
291 private int
read_vector3(gs_param_list * plist,gs_param_name key,gs_vector3 * pvec,const gs_vector3 * dflt)292 read_vector3(gs_param_list * plist, gs_param_name key,
293 gs_vector3 * pvec, const gs_vector3 * dflt)
294 {
295 float values[3];
296 int code = read_floats(plist, key, values, 3);
297
298 switch (code) {
299 case 1: /* not defined */
300 if (dflt)
301 *pvec = *dflt;
302 break;
303 case 0:
304 load_vector3(pvec, values);
305 default: /* error */
306 break;
307 }
308 return code;
309 }
310 private int
read_matrix3(gs_param_list * plist,gs_param_name key,gs_matrix3 * pmat)311 read_matrix3(gs_param_list * plist, gs_param_name key, gs_matrix3 * pmat)
312 {
313 float values[9];
314 int code = read_floats(plist, key, values, 9);
315
316 switch (code) {
317 case 1: /* not defined */
318 *pmat = Matrix3_default;
319 break;
320 case 0:
321 load_vector3(&pmat->cu, values);
322 load_vector3(&pmat->cv, values + 3);
323 load_vector3(&pmat->cw, values + 6);
324 default: /* error */
325 break;
326 }
327 return code;
328 }
329 private int
read_range3(gs_param_list * plist,gs_param_name key,gs_range3 * prange)330 read_range3(gs_param_list * plist, gs_param_name key, gs_range3 * prange)
331 {
332 float values[6];
333 int code = read_floats(plist, key, values, 6);
334
335 switch (code) {
336 case 1: /* not defined */
337 *prange = Range3_default;
338 break;
339 case 0:
340 prange->ranges[0].rmin = values[0];
341 prange->ranges[0].rmax = values[1];
342 prange->ranges[1].rmin = values[2];
343 prange->ranges[1].rmax = values[3];
344 prange->ranges[2].rmin = values[4];
345 prange->ranges[2].rmax = values[5];
346 default: /* error */
347 break;
348 }
349 return code;
350 }
351 private int
read_proc3(gs_param_list * plist,gs_param_name key,float values[gx_cie_cache_size * 3])352 read_proc3(gs_param_list * plist, gs_param_name key,
353 float values[gx_cie_cache_size * 3])
354 {
355 return read_floats(plist, key, values, gx_cie_cache_size * 3);
356 }
357
358 /* Read a CRD from a device parameter. */
359 int
gs_cie_render1_param_initialize(gs_cie_render * pcrd,gs_param_list * plist,gs_param_name key,gx_device * dev)360 gs_cie_render1_param_initialize(gs_cie_render * pcrd, gs_param_list * plist,
361 gs_param_name key, gx_device * dev)
362 {
363 gs_param_dict dict;
364 int code = param_begin_read_dict(plist, key, &dict, false);
365 int dcode;
366
367 if (code < 0)
368 return code;
369 code = param_get_cie_render1(pcrd, dict.list, dev);
370 dcode = param_end_read_dict(plist, key, &dict);
371 if (code < 0)
372 return code;
373 if (dcode < 0)
374 return dcode;
375 gs_cie_render_init(pcrd);
376 gs_cie_render_sample(pcrd);
377 return gs_cie_render_complete(pcrd);
378 }
379
380 /* Define the structure for passing Encode values as "client data". */
381 typedef struct encode_data_s {
382 float lmn[gx_cie_cache_size * 3]; /* EncodeLMN */
383 float abc[gx_cie_cache_size * 3]; /* EncodeABC */
384 float t[gx_cie_cache_size * 4]; /* RenderTable.T */
385 } encode_data_t;
386
387 /* Define procedures that retrieve the Encode values read from the list. */
388 private float
encode_from_data(floatp v,const float values[gx_cie_cache_size],const gs_range * range)389 encode_from_data(floatp v, const float values[gx_cie_cache_size],
390 const gs_range * range)
391 {
392 return (v <= range->rmin ? values[0] :
393 v >= range->rmax ? values[gx_cie_cache_size - 1] :
394 values[(int)((v - range->rmin) / (range->rmax - range->rmin) *
395 (gx_cie_cache_size - 1) + 0.5)]);
396 }
397 /*
398 * The repetitive boilerplate in the next 10 procedures really sticks in
399 * my craw, but I've got a mandate not to use macros....
400 */
401 private float
encode_lmn_0_from_data(floatp v,const gs_cie_render * pcrd)402 encode_lmn_0_from_data(floatp v, const gs_cie_render * pcrd)
403 {
404 const encode_data_t *data = pcrd->client_data;
405
406 return encode_from_data(v, &data->lmn[0],
407 &pcrd->DomainLMN.ranges[0]);
408 }
409 private float
encode_lmn_1_from_data(floatp v,const gs_cie_render * pcrd)410 encode_lmn_1_from_data(floatp v, const gs_cie_render * pcrd)
411 {
412 const encode_data_t *data = pcrd->client_data;
413
414 return encode_from_data(v, &data->lmn[gx_cie_cache_size],
415 &pcrd->DomainLMN.ranges[1]);
416 }
417 private float
encode_lmn_2_from_data(floatp v,const gs_cie_render * pcrd)418 encode_lmn_2_from_data(floatp v, const gs_cie_render * pcrd)
419 {
420 const encode_data_t *data = pcrd->client_data;
421
422 return encode_from_data(v, &data->lmn[gx_cie_cache_size * 2],
423 &pcrd->DomainLMN.ranges[2]);
424 }
425 private float
encode_abc_0_from_data(floatp v,const gs_cie_render * pcrd)426 encode_abc_0_from_data(floatp v, const gs_cie_render * pcrd)
427 {
428 const encode_data_t *data = pcrd->client_data;
429
430 return encode_from_data(v, &data->abc[0],
431 &pcrd->DomainABC.ranges[0]);
432 }
433 private float
encode_abc_1_from_data(floatp v,const gs_cie_render * pcrd)434 encode_abc_1_from_data(floatp v, const gs_cie_render * pcrd)
435 {
436 const encode_data_t *data = pcrd->client_data;
437
438 return encode_from_data(v, &data->abc[gx_cie_cache_size],
439 &pcrd->DomainABC.ranges[1]);
440 }
441 private float
encode_abc_2_from_data(floatp v,const gs_cie_render * pcrd)442 encode_abc_2_from_data(floatp v, const gs_cie_render * pcrd)
443 {
444 const encode_data_t *data = pcrd->client_data;
445
446 return encode_from_data(v, &data->abc[gx_cie_cache_size * 2],
447 &pcrd->DomainABC.ranges[2]);
448 }
449 private frac
render_table_t_0_from_data(byte v,const gs_cie_render * pcrd)450 render_table_t_0_from_data(byte v, const gs_cie_render * pcrd)
451 {
452 const encode_data_t *data = pcrd->client_data;
453
454 return float2frac(encode_from_data(v / 255.0,
455 &data->t[0],
456 &Range3_default.ranges[0]));
457 }
458 private frac
render_table_t_1_from_data(byte v,const gs_cie_render * pcrd)459 render_table_t_1_from_data(byte v, const gs_cie_render * pcrd)
460 {
461 const encode_data_t *data = pcrd->client_data;
462
463 return float2frac(encode_from_data(v / 255.0,
464 &data->t[gx_cie_cache_size],
465 &Range3_default.ranges[0]));
466 }
467 private frac
render_table_t_2_from_data(byte v,const gs_cie_render * pcrd)468 render_table_t_2_from_data(byte v, const gs_cie_render * pcrd)
469 {
470 const encode_data_t *data = pcrd->client_data;
471
472 return float2frac(encode_from_data(v / 255.0,
473 &data->t[gx_cie_cache_size * 2],
474 &Range3_default.ranges[0]));
475 }
476 private frac
render_table_t_3_from_data(byte v,const gs_cie_render * pcrd)477 render_table_t_3_from_data(byte v, const gs_cie_render * pcrd)
478 {
479 const encode_data_t *data = pcrd->client_data;
480
481 return float2frac(encode_from_data(v / 255.0,
482 &data->t[gx_cie_cache_size * 3],
483 &Range3_default.ranges[0]));
484 }
485 private const gs_cie_render_proc3 EncodeLMN_from_data = {
486 {encode_lmn_0_from_data, encode_lmn_1_from_data, encode_lmn_2_from_data}
487 };
488 private const gs_cie_render_proc3 EncodeABC_from_data = {
489 {encode_abc_0_from_data, encode_abc_1_from_data, encode_abc_2_from_data}
490 };
491 private const gs_cie_render_table_procs RenderTableT_from_data = {
492 {render_table_t_0_from_data, render_table_t_1_from_data,
493 render_table_t_2_from_data, render_table_t_3_from_data
494 }
495 };
496
497 /* Read a CRD directly from a parameter list. */
498 int
param_get_cie_render1(gs_cie_render * pcrd,gs_param_list * plist,gx_device * dev)499 param_get_cie_render1(gs_cie_render * pcrd, gs_param_list * plist,
500 gx_device * dev)
501 {
502 encode_data_t data;
503 gs_param_int_array rt_size;
504 int crd_type;
505 int code, code_lmn, code_abc, code_rt, code_t;
506 gs_param_string pname, pdata;
507
508 /* Reset the status to invalidate cached information. */
509 pcrd->status = CIE_RENDER_STATUS_BUILT;
510 if ((code = param_read_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
511 crd_type != GX_DEVICE_CRD1_TYPE ||
512 (code = read_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint,
513 NULL)) < 0 ||
514 (code = read_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint,
515 &BlackPoint_default)) < 0 ||
516 (code = read_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
517 (code = read_range3(plist, "RangePQR", &pcrd->RangePQR)) < 0 ||
518 /* TransformPQR is handled specially below. */
519 (code = read_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
520 (code_lmn = code =
521 read_proc3(plist, "EncodeLMNValues", data.lmn)) < 0 ||
522 (code = read_range3(plist, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
523 (code = read_matrix3(plist, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
524 (code_abc = code =
525 read_proc3(plist, "EncodeABCValues", data.abc)) < 0 ||
526 (code = read_range3(plist, "RangeABC", &pcrd->RangeABC)) < 0
527 )
528 return code;
529 /* Handle the sampled functions. */
530 switch (code = param_read_string(plist, "TransformPQRName", &pname)) {
531 default: /* error */
532 return code;
533 case 1: /* missing */
534 pcrd->TransformPQR = TransformPQR_default;
535 break;
536 case 0: /* specified */
537 /* The procedure name must be null-terminated: */
538 /* see param_put_cie_render1 above. */
539 if (pname.size < 1 || pname.data[pname.size - 1] != 0)
540 return_error(gs_error_rangecheck);
541 pcrd->TransformPQR.proc = TransformPQR_lookup_proc_name;
542 pcrd->TransformPQR.proc_name = (const char *)pname.data;
543 switch (code = param_read_string(plist, "TransformPQRData", &pdata)) {
544 default: /* error */
545 return code;
546 case 1: /* missing */
547 pcrd->TransformPQR.proc_data.data = 0;
548 pcrd->TransformPQR.proc_data.size = 0;
549 break;
550 case 0:
551 pcrd->TransformPQR.proc_data.data = pdata.data;
552 pcrd->TransformPQR.proc_data.size = pdata.size;
553 }
554 pcrd->TransformPQR.driver_name = gs_devicename(dev);
555 break;
556 }
557 pcrd->client_data = &data;
558 if (code_lmn > 0)
559 pcrd->EncodeLMN = Encode_default;
560 else
561 pcrd->EncodeLMN = EncodeLMN_from_data;
562 if (code_abc > 0)
563 pcrd->EncodeABC = Encode_default;
564 else
565 pcrd->EncodeABC = EncodeABC_from_data;
566 code_rt = code = param_read_int_array(plist, "RenderTableSize", &rt_size);
567 if (code == 1) {
568 if (pcrd->RenderTable.lookup.table) {
569 gs_free_object(pcrd->rc.memory,
570 (void *)pcrd->RenderTable.lookup.table, /* break const */
571 "param_get_cie_render1(RenderTable)");
572 pcrd->RenderTable.lookup.table = 0;
573 }
574 pcrd->RenderTable.T = RenderTableT_default;
575 code_t = 1;
576 } else if (code < 0)
577 return code;
578 else if (rt_size.size != 4)
579 return_error(gs_error_rangecheck);
580 else {
581 gs_param_string_array rt_values;
582 gs_const_string *table;
583 int n, m, j;
584
585 for (j = 0; j < rt_size.size; ++j)
586 if (rt_size.data[j] < 1)
587 return_error(gs_error_rangecheck);
588 code = param_read_string_array(plist, "RenderTableTable", &rt_values);
589 if (code < 0)
590 return code;
591 if (code > 0 || rt_values.size != rt_size.data[0])
592 return_error(gs_error_rangecheck);
593 /* Note: currently n = 3 (rt_size.size = 4) always. */
594 for (j = 0; j < rt_values.size; ++j)
595 if (rt_values.data[j].size !=
596 rt_size.data[1] * rt_size.data[2] * rt_size.data[3])
597 return_error(gs_error_rangecheck);
598 pcrd->RenderTable.lookup.n = n = rt_size.size - 1;
599 pcrd->RenderTable.lookup.m = m = rt_size.data[n];
600 if (n > 4 || m > 4)
601 return_error(gs_error_rangecheck);
602 memcpy(pcrd->RenderTable.lookup.dims, rt_size.data, n * sizeof(int));
603 table =
604 gs_alloc_struct_array(pcrd->rc.memory,
605 pcrd->RenderTable.lookup.dims[0],
606 gs_const_string, &st_const_string_element,
607 "RenderTable table");
608 if (table == 0)
609 return_error(gs_error_VMerror);
610 for (j = 0; j < pcrd->RenderTable.lookup.dims[0]; ++j) {
611 table[j].data = rt_values.data[j].data;
612 table[j].size = rt_values.data[j].size;
613 }
614 pcrd->RenderTable.lookup.table = table;
615 pcrd->RenderTable.T = RenderTableT_from_data;
616 code_t = code = read_floats(plist, "RenderTableTValues", data.t,
617 gx_cie_cache_size * m);
618 if (code > 0)
619 pcrd->RenderTable.T = RenderTableT_default;
620 else if (code == 0)
621 pcrd->RenderTable.T = RenderTableT_from_data;
622 }
623 if ((code = gs_cie_render_init(pcrd)) >= 0 &&
624 (code = gs_cie_render_sample(pcrd)) >= 0
625 )
626 code = gs_cie_render_complete(pcrd);
627 /* Clean up before exiting. */
628 pcrd->client_data = 0;
629 if (code_lmn == 0)
630 pcrd->EncodeLMN = EncodeLMN_from_cache;
631 if (code_abc == 0)
632 pcrd->EncodeABC = EncodeABC_from_cache;
633 if (code_t == 0)
634 pcrd->RenderTable.T = RenderTableT_from_cache;
635 return code;
636 }
637