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