/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 | } |