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