Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}