1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: zcrd.c 8250 2007-09-25 13:31:24Z giles $ */
15
/* CIE color rendering operators */
32
#include "store.h" /* for make_null */
34
/* Forward references */
35
static int zcrd1_proc_params(const gs_memory_t *mem, os_ptr op, ref_cie_render_procs * pcprocs);
36
static int zcrd1_params(os_ptr op, gs_cie_render * pcrd,
37
ref_cie_render_procs * pcprocs, gs_memory_t * mem);
38
static int cache_colorrendering1(i_ctx_t *i_ctx_p, gs_cie_render * pcrd,
39
const ref_cie_render_procs * pcprocs,
40
gs_ref_memory_t * imem);
42
/* - currentcolorrendering <dict> */
44
zcurrentcolorrendering(i_ctx_t *i_ctx_p)
49
*op = istate->colorrendering.dict;
53
/* <dict> .buildcolorrendering1 <crd> */
55
zbuildcolorrendering1(i_ctx_t *i_ctx_p)
58
gs_memory_t *mem = gs_state_memory(igs);
62
ref_cie_render_procs procs;
64
check_read_type(*op, t_dictionary);
66
code = gs_cie_render1_build(&pcrd, mem, ".buildcolorrendering1");
69
code = zcrd1_params(op, pcrd, &procs, mem);
71
(code = cache_colorrendering1(i_ctx_p, pcrd, &procs,
72
(gs_ref_memory_t *) mem)) < 0
74
rc_free_struct(pcrd, ".buildcolorrendering1");
78
/****** FIX refct ******/
79
/*rc_decrement(pcrd, ".buildcolorrendering1"); *//* build sets rc = 1 */
80
istate->colorrendering.dict = *op;
81
make_istruct_new(op, a_readonly, pcrd);
82
return (esp == ep ? 0 : o_push_estack);
85
/* <dict> .builddevicecolorrendering1 <crd> */
87
zbuilddevicecolorrendering1(i_ctx_t *i_ctx_p)
90
gs_memory_t *mem = gs_state_memory(igs);
92
gs_cie_render *pcrd = 0;
95
check_type(*op, t_dictionary);
96
code = dict_param_list_read(&list, op, NULL, false, iimemory);
99
code = gs_cie_render1_build(&pcrd, mem, ".builddevicecolorrendering1");
101
code = param_get_cie_render1(pcrd, (gs_param_list *) & list,
102
gs_currentdevice(igs));
104
/****** FIX refct ******/
105
/*rc_decrement(pcrd, ".builddevicecolorrendering1"); *//* build sets rc = 1 */
108
iparam_list_release(&list);
110
rc_free_struct(pcrd, ".builddevicecolorrendering1");
113
istate->colorrendering.dict = *op;
114
make_istruct_new(op, a_readonly, pcrd);
118
/* <dict> <crd> .setcolorrendering1 - */
120
zsetcolorrendering1(i_ctx_t *i_ctx_p)
124
ref_cie_render_procs procs;
127
check_type(op[-1], t_dictionary);
128
check_stype(*op, st_cie_render1);
129
code = zcrd1_proc_params(imemory, op - 1, &procs);
132
code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
135
if (gs_cie_cs_common(igs) != 0 &&
136
(code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
139
istate->colorrendering.dict = op[-1];
140
istate->colorrendering.procs = procs;
142
return (esp == ep ? 0 : o_push_estack);
145
/* <dict> <crd> .setdevicecolorrendering1 - */
147
zsetdevicecolorrendering1(i_ctx_t *i_ctx_p)
151
ref_cie_render_procs procs;
153
check_type(op[-1], t_dictionary);
154
check_stype(*op, st_cie_render1);
155
code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
158
refset_null((ref *)&procs, sizeof(procs) / sizeof(ref));
159
if (gs_cie_cs_common(igs) != 0 &&
160
(code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
163
istate->colorrendering.dict = op[-1];
164
refset_null((ref *)&istate->colorrendering.procs,
165
sizeof(istate->colorrendering.procs) / sizeof(ref));
170
/* Get ColorRenderingType 1 procedures from the PostScript dictionary. */
172
zcrd1_proc_params(const gs_memory_t *mem,
173
os_ptr op, ref_cie_render_procs * pcprocs)
178
code = dict_proc3_param(mem, op, "EncodeLMN", &pcprocs->EncodeLMN);
181
code = dict_proc3_param(mem, op, "EncodeABC", &pcprocs->EncodeABC);
184
code = dict_proc3_param(mem, op, "TransformPQR", &pcprocs->TransformPQR);
188
return gs_note_error(e_undefined);
189
if (dict_find_string(op, "RenderTable", &pRT) > 0) {
194
check_read_type(*pRT, t_array);
197
return_error(e_rangecheck);
198
prte = pRT->value.const_refs;
199
for (i = 5; i < size; i++)
200
check_proc_only(prte[i]);
201
make_const_array(&pcprocs->RenderTableT, a_readonly | r_space(pRT),
204
make_null(&pcprocs->RenderTableT);
208
/* Get ColorRenderingType 1 parameters from the PostScript dictionary. */
210
zcrd1_params(os_ptr op, gs_cie_render * pcrd,
211
ref_cie_render_procs * pcprocs, gs_memory_t * mem)
215
gx_color_lookup_table *const prtl = &pcrd->RenderTable.lookup;
218
if ((code = dict_int_param(op, "ColorRenderingType", 1, 1, 0, &ignore)) < 0 ||
219
(code = zcrd1_proc_params(mem, op, pcprocs)) < 0 ||
220
(code = dict_matrix3_param(mem, op, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
221
(code = dict_range3_param(mem, op, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
222
(code = dict_matrix3_param(mem, op, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
223
(code = dict_range3_param(mem, op, "RangeABC", &pcrd->RangeABC)) < 0 ||
224
(code = cie_points_param(mem, op, &pcrd->points)) < 0 ||
225
(code = dict_matrix3_param(mem, op, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
226
(code = dict_range3_param(mem,op, "RangePQR", &pcrd->RangePQR)) < 0
229
if (dict_find_string(op, "RenderTable", &pRT) > 0) {
230
const ref *prte = pRT->value.const_refs;
232
/* Finish unpacking and checking the RenderTable parameter. */
233
check_type_only(prte[4], t_integer);
234
if (!(prte[4].value.intval == 3 || prte[4].value.intval == 4))
235
return_error(e_rangecheck);
237
prtl->m = prte[4].value.intval;
238
if (r_size(pRT) != prtl->m + 5)
239
return_error(e_rangecheck);
240
code = cie_table_param(pRT, prtl, mem);
246
pcrd->EncodeLMN = Encode_default;
247
pcrd->EncodeABC = Encode_default;
248
pcrd->TransformPQR = TransformPQR_default;
249
pcrd->RenderTable.T = RenderTableT_default;
253
/* Cache the results of the color rendering procedures. */
254
static int cie_cache_render_finish(i_ctx_t *);
256
cache_colorrendering1(i_ctx_t *i_ctx_p, gs_cie_render * pcrd,
257
const ref_cie_render_procs * pcrprocs,
258
gs_ref_memory_t * imem)
261
int code = gs_cie_render_init(pcrd); /* sets Domain values */
265
(code = cie_cache_push_finish(i_ctx_p, cie_cache_render_finish, imem, pcrd)) < 0 ||
266
(code = cie_prepare_cache3(i_ctx_p, &pcrd->DomainLMN, pcrprocs->EncodeLMN.value.const_refs, pcrd->caches.EncodeLMN.caches, pcrd, imem, "Encode.LMN")) < 0 ||
267
(code = cie_prepare_cache3(i_ctx_p, &pcrd->DomainABC, pcrprocs->EncodeABC.value.const_refs, &pcrd->caches.EncodeABC[0], pcrd, imem, "Encode.ABC")) < 0
272
if (pcrd->RenderTable.lookup.table != 0) {
273
bool is_identity = true;
275
for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
276
if (r_size(pcrprocs->RenderTableT.value.const_refs + i) != 0) {
280
pcrd->caches.RenderTableT_is_identity = is_identity;
282
for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
284
cie_prepare_cache(i_ctx_p, Range4_default.ranges,
285
pcrprocs->RenderTableT.value.const_refs + i,
286
&pcrd->caches.RenderTableT[i].floats,
287
pcrd, imem, "RenderTable.T")) < 0
293
return o_push_estack;
296
/* Finish up after loading the rendering caches. */
298
cie_cache_render_finish(i_ctx_t *i_ctx_p)
301
gs_cie_render *pcrd = r_ptr(op, gs_cie_render);
304
if (pcrd->RenderTable.lookup.table != 0 &&
305
!pcrd->caches.RenderTableT_is_identity
307
/* Convert the RenderTableT cache from floats to fracs. */
310
for (j = 0; j < pcrd->RenderTable.lookup.m; j++)
311
gs_cie_cache_to_fracs(&pcrd->caches.RenderTableT[j].floats,
312
&pcrd->caches.RenderTableT[j].fracs);
314
pcrd->status = CIE_RENDER_STATUS_SAMPLED;
315
pcrd->EncodeLMN = EncodeLMN_from_cache;
316
pcrd->EncodeABC = EncodeABC_from_cache;
317
pcrd->RenderTable.T = RenderTableT_from_cache;
318
code = gs_cie_render_complete(pcrd);
325
/* ------ Internal procedures ------ */
327
/* Load the joint caches. */
329
cie_exec_tpqr(i_ctx_t *),
330
cie_post_exec_tpqr(i_ctx_t *),
331
cie_tpqr_finish(i_ctx_t *);
333
cie_cache_joint(i_ctx_t *i_ctx_p, const ref_cie_render_procs * pcrprocs,
334
const gs_cie_common *pcie, gs_state * pgs)
336
const gs_cie_render *pcrd = gs_currentcolorrendering(pgs);
337
gx_cie_joint_caches *pjc = gx_unshare_cie_caches(pgs);
338
gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
344
if (pcrd == 0) /* cache is not set up yet */
346
if (pjc == 0) /* must already be allocated */
347
return_error(e_VMerror);
348
if (r_has_type(&pcrprocs->TransformPQR, t_null)) {
350
* This CRD came from a driver, not from a PostScript dictionary.
351
* Resample TransformPQR in C code.
353
return gs_cie_cs_complete(pgs, true);
355
gs_cie_compute_points_sd(pjc, pcie, pcrd);
356
code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
360
/* When we're done, deallocate the procs and complete the caches. */
362
cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs);
364
space = r_space(&pqr_procs);
365
for (i = 0; i < 3; i++) {
366
ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i;
367
const float *ppt = (float *)&pjc->points_sd;
370
make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
372
make_array(p, a_readonly | space, 4 * 6, p + 4);
373
p[1] = pcrprocs->TransformPQR.value.refs[i];
374
make_oper(p + 2, 0, cie_exec_tpqr);
375
make_oper(p + 3, 0, cie_post_exec_tpqr);
376
for (j = 0, p += 4; j < 4 * 6; j++, p++, ppt++)
379
return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR,
380
pqr_procs.value.const_refs,
381
pjc->TransformPQR.caches,
382
pjc, imem, "Transform.PQR");
385
/* Private operator to shuffle arguments for the TransformPQR procedure: */
386
/* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
388
cie_exec_tpqr(i_ctx_t *i_ctx_p)
391
const ref *ppt = op[-1].value.const_refs;
392
uint space = r_space(op - 1);
397
*op = op[-4]; /* proc */
398
op[-1] = op[-6]; /* v */
399
for (i = 0; i < 4; i++)
400
make_const_array(op - 5 + i, a_readonly | space,
403
return zexec(i_ctx_p);
406
/* Remove extraneous values from the stack after executing */
407
/* the TransformPQR procedure. -mark- ... v -> v */
409
cie_post_exec_tpqr(i_ctx_t *i_ctx_p)
412
uint count = ref_stack_counttomark(&o_stack);
416
return_error(e_unmatchedmark);
418
ref_stack_pop(&o_stack, count - 1);
423
/* Free the procs array and complete the joint caches. */
425
cie_tpqr_finish(i_ctx_t *i_ctx_p)
428
gs_state *pgs = r_ptr(op, gs_state);
429
gs_cie_render *pcrd =
430
(gs_cie_render *)gs_currentcolorrendering(pgs); /* break const */
433
ifree_ref_array(op - 1, "cie_tpqr_finish");
434
pcrd->TransformPQR = TransformPQR_from_cache;
435
code = gs_cie_cs_complete(pgs, false);
440
/* Ws Bs Wd Bd Ps .transformPQR_scale_wb[012] Pd
442
The default TransformPQR procedure is implemented in C, rather than
443
PostScript, as a speed optimization.
445
This TransformPQR implements a relative colorimetric intent by scaling
446
the XYZ values relative to the white and black points.
449
ztpqr_scale_wb_common(i_ctx_t *i_ctx_p, int idx)
452
double a[4], Ps; /* a[0] = ws, a[1] = bs, a[2] = wd, a[3] = bd */
457
code = real_param(op, &Ps);
458
if (code < 0) return code;
460
for (i = 0; i < 4; i++) {
463
code = array_get(imemory, op - 4 + i, idx, &tmp);
465
code = real_param(&tmp, &a[i]);
466
if (code < 0) return code;
470
return_error(e_undefinedresult);
471
result = a[3] + (a[2] - a[3]) * (Ps - a[1]) / (a[0] - a[1]);
472
make_real(op - 4, result);
477
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb0 Pd */
479
ztpqr_scale_wb0(i_ctx_t *i_ctx_p)
481
return ztpqr_scale_wb_common(i_ctx_p, 3);
484
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
486
ztpqr_scale_wb1(i_ctx_t *i_ctx_p)
488
return ztpqr_scale_wb_common(i_ctx_p, 4);
491
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
493
ztpqr_scale_wb2(i_ctx_t *i_ctx_p)
495
return ztpqr_scale_wb_common(i_ctx_p, 5);
498
/* ------ Initialization procedure ------ */
500
const op_def zcrd_l2_op_defs[] =
502
op_def_begin_level2(),
503
{"0currentcolorrendering", zcurrentcolorrendering},
504
{"2.setcolorrendering1", zsetcolorrendering1},
505
{"2.setdevicecolorrendering1", zsetdevicecolorrendering1},
506
{"1.buildcolorrendering1", zbuildcolorrendering1},
507
{"1.builddevicecolorrendering1", zbuilddevicecolorrendering1},
508
/* Internal "operators" */
509
{"1%cie_render_finish", cie_cache_render_finish},
510
{"3%cie_exec_tpqr", cie_exec_tpqr},
511
{"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
512
{"1%cie_tpqr_finish", cie_tpqr_finish},
513
{"5.TransformPQR_scale_WB0", ztpqr_scale_wb0},
514
{"5.TransformPQR_scale_WB1", ztpqr_scale_wb1},
515
{"5.TransformPQR_scale_WB2", ztpqr_scale_wb2},