Coverage Report

Created: 2025-06-24 07:01

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