1 /* Copyright (C) 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
3 This software is provided AS-IS with no warranty, either express or
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.
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.
17 /* $Id: zcrd.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18 /* CIE color rendering operators */
35 #include "store.h" /* for make_null */
37 /* Forward references */
38 private int zcrd1_proc_params(const gs_memory_t *mem, os_ptr op, ref_cie_render_procs * pcprocs);
39 private int zcrd1_params(os_ptr op, gs_cie_render * pcrd,
40 ref_cie_render_procs * pcprocs, gs_memory_t * mem);
41 private int cache_colorrendering1(i_ctx_t *i_ctx_p, gs_cie_render * pcrd,
42 const ref_cie_render_procs * pcprocs,
43 gs_ref_memory_t * imem);
45 /* - currentcolorrendering <dict> */
47 zcurrentcolorrendering(i_ctx_t *i_ctx_p)
52 *op = istate->colorrendering.dict;
56 /* <dict> .buildcolorrendering1 <crd> */
58 zbuildcolorrendering1(i_ctx_t *i_ctx_p)
61 gs_memory_t *mem = gs_state_memory(igs);
65 ref_cie_render_procs procs;
67 check_read_type(*op, t_dictionary);
69 code = gs_cie_render1_build(&pcrd, mem, ".buildcolorrendering1");
72 code = zcrd1_params(op, pcrd, &procs, mem);
74 (code = cache_colorrendering1(i_ctx_p, pcrd, &procs,
75 (gs_ref_memory_t *) mem)) < 0
77 rc_free_struct(pcrd, ".buildcolorrendering1");
81 /****** FIX refct ******/
82 /*rc_decrement(pcrd, ".buildcolorrendering1"); *//* build sets rc = 1 */
83 istate->colorrendering.dict = *op;
84 make_istruct_new(op, a_readonly, pcrd);
85 return (esp == ep ? 0 : o_push_estack);
88 /* <dict> .builddevicecolorrendering1 <crd> */
90 zbuilddevicecolorrendering1(i_ctx_t *i_ctx_p)
93 gs_memory_t *mem = gs_state_memory(igs);
95 gs_cie_render *pcrd = 0;
98 check_type(*op, t_dictionary);
99 code = dict_param_list_read(&list, op, NULL, false, iimemory);
102 code = gs_cie_render1_build(&pcrd, mem, ".builddevicecolorrendering1");
104 code = param_get_cie_render1(pcrd, (gs_param_list *) & list,
105 gs_currentdevice(igs));
107 /****** FIX refct ******/
108 /*rc_decrement(pcrd, ".builddevicecolorrendering1"); *//* build sets rc = 1 */
111 iparam_list_release(&list);
113 rc_free_struct(pcrd, ".builddevicecolorrendering1");
116 istate->colorrendering.dict = *op;
117 make_istruct_new(op, a_readonly, pcrd);
121 /* <dict> <crd> .setcolorrendering1 - */
123 zsetcolorrendering1(i_ctx_t *i_ctx_p)
127 ref_cie_render_procs procs;
130 check_type(op[-1], t_dictionary);
131 check_stype(*op, st_cie_render1);
132 code = zcrd1_proc_params(imemory, op - 1, &procs);
135 code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
138 if (gs_cie_cs_common(igs) != 0 &&
139 (code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
142 istate->colorrendering.dict = op[-1];
143 istate->colorrendering.procs = procs;
145 return (esp == ep ? 0 : o_push_estack);
148 /* <dict> <crd> .setdevicecolorrendering1 - */
150 zsetdevicecolorrendering1(i_ctx_t *i_ctx_p)
154 ref_cie_render_procs procs;
156 check_type(op[-1], t_dictionary);
157 check_stype(*op, st_cie_render1);
158 code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
161 refset_null((ref *)&procs, sizeof(procs) / sizeof(ref));
162 if (gs_cie_cs_common(igs) != 0 &&
163 (code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
166 istate->colorrendering.dict = op[-1];
167 refset_null((ref *)&istate->colorrendering.procs,
168 sizeof(istate->colorrendering.procs) / sizeof(ref));
173 /* Get ColorRenderingType 1 procedures from the PostScript dictionary. */
175 zcrd1_proc_params(const gs_memory_t *mem,
176 os_ptr op, ref_cie_render_procs * pcprocs)
181 if ((code = dict_proc3_param(mem, op, "EncodeLMN", &pcprocs->EncodeLMN)) < 0 ||
182 (code = dict_proc3_param(mem, op, "EncodeABC", &pcprocs->EncodeABC)) < 0 ||
183 (code = dict_proc3_param(mem, op, "TransformPQR", &pcprocs->TransformPQR)) < 0
185 return (code < 0 ? code : gs_note_error(e_rangecheck));
186 if (dict_find_string(op, "RenderTable", &pRT) > 0) {
191 check_read_type(*pRT, t_array);
194 return_error(e_rangecheck);
195 prte = pRT->value.const_refs;
196 for (i = 5; i < size; i++)
197 check_proc_only(prte[i]);
198 make_const_array(&pcprocs->RenderTableT, a_readonly | r_space(pRT),
201 make_null(&pcprocs->RenderTableT);
205 /* Get ColorRenderingType 1 parameters from the PostScript dictionary. */
207 zcrd1_params(os_ptr op, gs_cie_render * pcrd,
208 ref_cie_render_procs * pcprocs, gs_memory_t * mem)
212 gx_color_lookup_table *const prtl = &pcrd->RenderTable.lookup;
215 if ((code = dict_int_param(op, "ColorRenderingType", 1, 1, 0, &ignore)) < 0 ||
216 (code = zcrd1_proc_params(mem, op, pcprocs)) < 0 ||
217 (code = dict_matrix3_param(mem, op, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
218 (code = dict_range3_param(mem, op, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
219 (code = dict_matrix3_param(mem, op, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
220 (code = dict_range3_param(mem, op, "RangeABC", &pcrd->RangeABC)) < 0 ||
221 (code = cie_points_param(mem, op, &pcrd->points)) < 0 ||
222 (code = dict_matrix3_param(mem, op, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
223 (code = dict_range3_param(mem,op, "RangePQR", &pcrd->RangePQR)) < 0
226 if (dict_find_string(op, "RenderTable", &pRT) > 0) {
227 const ref *prte = pRT->value.const_refs;
229 /* Finish unpacking and checking the RenderTable parameter. */
230 check_type_only(prte[4], t_integer);
231 if (!(prte[4].value.intval == 3 || prte[4].value.intval == 4))
232 return_error(e_rangecheck);
234 prtl->m = prte[4].value.intval;
235 if (r_size(pRT) != prtl->m + 5)
236 return_error(e_rangecheck);
237 code = cie_table_param(pRT, prtl, mem);
243 pcrd->EncodeLMN = Encode_default;
244 pcrd->EncodeABC = Encode_default;
245 pcrd->TransformPQR = TransformPQR_default;
246 pcrd->RenderTable.T = RenderTableT_default;
250 /* Cache the results of the color rendering procedures. */
251 private int cie_cache_render_finish(i_ctx_t *);
253 cache_colorrendering1(i_ctx_t *i_ctx_p, gs_cie_render * pcrd,
254 const ref_cie_render_procs * pcrprocs,
255 gs_ref_memory_t * imem)
258 int code = gs_cie_render_init(pcrd); /* sets Domain values */
262 (code = cie_cache_push_finish(i_ctx_p, cie_cache_render_finish, imem, pcrd)) < 0 ||
263 (code = cie_prepare_cache3(i_ctx_p, &pcrd->DomainLMN, pcrprocs->EncodeLMN.value.const_refs, pcrd->caches.EncodeLMN.caches, pcrd, imem, "Encode.LMN")) < 0 ||
264 (code = cie_prepare_cache3(i_ctx_p, &pcrd->DomainABC, pcrprocs->EncodeABC.value.const_refs, &pcrd->caches.EncodeABC[0], pcrd, imem, "Encode.ABC")) < 0
269 if (pcrd->RenderTable.lookup.table != 0) {
270 bool is_identity = true;
272 for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
273 if (r_size(pcrprocs->RenderTableT.value.const_refs + i) != 0) {
277 pcrd->caches.RenderTableT_is_identity = is_identity;
279 for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
281 cie_prepare_cache(i_ctx_p, Range4_default.ranges,
282 pcrprocs->RenderTableT.value.const_refs + i,
283 &pcrd->caches.RenderTableT[i].floats,
284 pcrd, imem, "RenderTable.T")) < 0
290 return o_push_estack;
293 /* Finish up after loading the rendering caches. */
295 cie_cache_render_finish(i_ctx_t *i_ctx_p)
298 gs_cie_render *pcrd = r_ptr(op, gs_cie_render);
301 if (pcrd->RenderTable.lookup.table != 0 &&
302 !pcrd->caches.RenderTableT_is_identity
304 /* Convert the RenderTableT cache from floats to fracs. */
307 for (j = 0; j < pcrd->RenderTable.lookup.m; j++)
308 gs_cie_cache_to_fracs(&pcrd->caches.RenderTableT[j].floats,
309 &pcrd->caches.RenderTableT[j].fracs);
311 pcrd->status = CIE_RENDER_STATUS_SAMPLED;
312 pcrd->EncodeLMN = EncodeLMN_from_cache;
313 pcrd->EncodeABC = EncodeABC_from_cache;
314 pcrd->RenderTable.T = RenderTableT_from_cache;
315 code = gs_cie_render_complete(pcrd);
322 /* ------ Internal procedures ------ */
324 /* Load the joint caches. */
326 cie_exec_tpqr(i_ctx_t *),
327 cie_post_exec_tpqr(i_ctx_t *),
328 cie_tpqr_finish(i_ctx_t *);
330 cie_cache_joint(i_ctx_t *i_ctx_p, const ref_cie_render_procs * pcrprocs,
331 const gs_cie_common *pcie, gs_state * pgs)
333 const gs_cie_render *pcrd = gs_currentcolorrendering(pgs);
334 gx_cie_joint_caches *pjc = gx_currentciecaches(pgs);
335 gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
341 if (pcrd == 0) /* cache is not set up yet */
343 if (pjc == 0) /* must already be allocated */
344 return_error(e_VMerror);
345 if (r_has_type(&pcrprocs->TransformPQR, t_null)) {
347 * This CRD came from a driver, not from a PostScript dictionary.
348 * Resample TransformPQR in C code.
350 return gs_cie_cs_complete(pgs, true);
352 gs_cie_compute_points_sd(pjc, pcie, pcrd);
353 code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
357 /* When we're done, deallocate the procs and complete the caches. */
359 cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs);
361 space = r_space(&pqr_procs);
362 for (i = 0; i < 3; i++) {
363 ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i;
365 make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
367 make_array(p, a_readonly | space, 4 * 6, p + 4);
368 p[1] = pcrprocs->TransformPQR.value.refs[i];
369 make_oper(p + 2, 0, cie_exec_tpqr);
370 make_oper(p + 3, 0, cie_post_exec_tpqr);
373 /* cant use array due to structure alignment */
374 make_real(p, pjc->points_sd.ws.xyz.u); p++;
375 make_real(p, pjc->points_sd.ws.xyz.v); p++;
376 make_real(p, pjc->points_sd.ws.xyz.w); p++;
377 make_real(p, pjc->points_sd.ws.pqr.u); p++;
378 make_real(p, pjc->points_sd.ws.pqr.v); p++;
379 make_real(p, pjc->points_sd.ws.pqr.w); p++;
381 make_real(p, pjc->points_sd.bs.xyz.u); p++;
382 make_real(p, pjc->points_sd.bs.xyz.v); p++;
383 make_real(p, pjc->points_sd.bs.xyz.w); p++;
384 make_real(p, pjc->points_sd.bs.pqr.u); p++;
385 make_real(p, pjc->points_sd.bs.pqr.v); p++;
386 make_real(p, pjc->points_sd.bs.pqr.w); p++;
388 make_real(p, pjc->points_sd.wd.xyz.u); p++;
389 make_real(p, pjc->points_sd.wd.xyz.v); p++;
390 make_real(p, pjc->points_sd.wd.xyz.w); p++;
391 make_real(p, pjc->points_sd.wd.pqr.u); p++;
392 make_real(p, pjc->points_sd.wd.pqr.v); p++;
393 make_real(p, pjc->points_sd.wd.pqr.w); p++;
395 make_real(p, pjc->points_sd.bd.xyz.u); p++;
396 make_real(p, pjc->points_sd.bd.xyz.v); p++;
397 make_real(p, pjc->points_sd.bd.xyz.w); p++;
398 make_real(p, pjc->points_sd.bd.pqr.u); p++;
399 make_real(p, pjc->points_sd.bd.pqr.v); p++;
400 make_real(p, pjc->points_sd.bd.pqr.w); p++;
402 return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR,
403 pqr_procs.value.const_refs,
404 pjc->TransformPQR.caches,
405 pjc, imem, "Transform.PQR");
408 /* Private operator to shuffle arguments for the TransformPQR procedure: */
409 /* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
411 cie_exec_tpqr(i_ctx_t *i_ctx_p)
414 const ref *ppt = op[-1].value.const_refs;
415 uint space = r_space(op - 1);
420 *op = op[-4]; /* proc */
421 op[-1] = op[-6]; /* v */
422 for (i = 0; i < 4; i++)
423 make_const_array(op - 5 + i, a_readonly | space,
426 return zexec(i_ctx_p);
429 /* Remove extraneous values from the stack after executing */
430 /* the TransformPQR procedure. -mark- ... v -> v */
432 cie_post_exec_tpqr(i_ctx_t *i_ctx_p)
435 uint count = ref_stack_counttomark(&o_stack);
439 return_error(e_unmatchedmark);
441 ref_stack_pop(&o_stack, count - 1);
446 /* Free the procs array and complete the joint caches. */
448 cie_tpqr_finish(i_ctx_t *i_ctx_p)
451 gs_state *pgs = r_ptr(op, gs_state);
452 gs_cie_render *pcrd =
453 (gs_cie_render *)gs_currentcolorrendering(pgs); /* break const */
456 ifree_ref_array(op - 1, "cie_tpqr_finish");
457 pcrd->TransformPQR = TransformPQR_from_cache;
458 code = gs_cie_cs_complete(pgs, false);
463 /* Ws Bs Wd Bd Ps .transformPQR_scale_wb[012] Pd
465 The default TransformPQR procedure is implemented in C, rather than
466 PostScript, as a speed optimization.
468 This TransformPQR implements a relative colorimetric intent by scaling
469 the XYZ values relative to the white and black points.
472 ztpqr_scale_wb_common(i_ctx_t *i_ctx_p, int idx)
475 double a[4], Ps; /* a[0] = ws, a[1] = bs, a[2] = wd, a[3] = bd */
480 code = real_param(op, &Ps);
481 if (code < 0) return code;
483 for (i = 0; i < 4; i++) {
486 code = array_get(imemory, op - 4 + i, idx, &tmp);
488 code = real_param(&tmp, &a[i]);
489 if (code < 0) return code;
493 return_error(e_undefinedresult);
494 result = a[3] + (a[2] - a[3]) * (Ps - a[1]) / (a[0] - a[1]);
495 make_real(op - 4, result);
500 /* Ws Bs Wd Bd Ps .TransformPQR_scale_wb0 Pd */
502 ztpqr_scale_wb0(i_ctx_t *i_ctx_p)
504 return ztpqr_scale_wb_common(i_ctx_p, 3);
507 /* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
509 ztpqr_scale_wb1(i_ctx_t *i_ctx_p)
511 return ztpqr_scale_wb_common(i_ctx_p, 4);
514 /* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
516 ztpqr_scale_wb2(i_ctx_t *i_ctx_p)
518 return ztpqr_scale_wb_common(i_ctx_p, 5);
521 /* ------ Initialization procedure ------ */
523 const op_def zcrd_l2_op_defs[] =
525 op_def_begin_level2(),
526 {"0currentcolorrendering", zcurrentcolorrendering},
527 {"2.setcolorrendering1", zsetcolorrendering1},
528 {"2.setdevicecolorrendering1", zsetdevicecolorrendering1},
529 {"1.buildcolorrendering1", zbuildcolorrendering1},
530 {"1.builddevicecolorrendering1", zbuilddevicecolorrendering1},
531 /* Internal "operators" */
532 {"1%cie_render_finish", cie_cache_render_finish},
533 {"3%cie_exec_tpqr", cie_exec_tpqr},
534 {"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
535 {"1%cie_tpqr_finish", cie_tpqr_finish},
536 {"5.TransformPQR_scale_WB0", ztpqr_scale_wb0},
537 {"5.TransformPQR_scale_WB1", ztpqr_scale_wb1},
538 {"5.TransformPQR_scale_WB2", ztpqr_scale_wb2},