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) 1995, 1996, 1997, 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: zcrd.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18
/* CIE color rendering operators */
19
#include "math_.h"
20
#include "ghost.h"
21
#include "oper.h"
22
#include "gsstruct.h"
23
#include "gscspace.h"
24
#include "gscolor2.h"
25
#include "gscrd.h"
26
#include "gscrdp.h"
27
#include "estack.h"
28
#include "ialloc.h"
29
#include "idict.h"
30
#include "idparam.h"
31
#include "igstate.h"
32
#include "icie.h"
33
#include "iparam.h"
34
#include "ivmspace.h"
35
#include "store.h"		/* for make_null */
36
 
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);
44
 
45
/* - currentcolorrendering <dict> */
46
private int
47
zcurrentcolorrendering(i_ctx_t *i_ctx_p)
48
{
49
    os_ptr op = osp;
50
 
51
    push(1);
52
    *op = istate->colorrendering.dict;
53
    return 0;
54
}
55
 
56
/* <dict> .buildcolorrendering1 <crd> */
57
private int
58
zbuildcolorrendering1(i_ctx_t *i_ctx_p)
59
{
60
    os_ptr op = osp;
61
    gs_memory_t *mem = gs_state_memory(igs);
62
    int code;
63
    es_ptr ep = esp;
64
    gs_cie_render *pcrd;
65
    ref_cie_render_procs procs;
66
 
67
    check_read_type(*op, t_dictionary);
68
    check_dict_read(*op);
69
    code = gs_cie_render1_build(&pcrd, mem, ".buildcolorrendering1");
70
    if (code < 0)
71
	return code;
72
    code = zcrd1_params(op, pcrd, &procs, mem);
73
    if (code < 0 ||
74
    (code = cache_colorrendering1(i_ctx_p, pcrd, &procs,
75
				  (gs_ref_memory_t *) mem)) < 0
76
	) {
77
	rc_free_struct(pcrd, ".buildcolorrendering1");
78
	esp = ep;
79
	return code;
80
    }
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);
86
}
87
 
88
/* <dict> .builddevicecolorrendering1 <crd> */
89
private int
90
zbuilddevicecolorrendering1(i_ctx_t *i_ctx_p)
91
{
92
    os_ptr op = osp;
93
    gs_memory_t *mem = gs_state_memory(igs);
94
    dict_param_list list;
95
    gs_cie_render *pcrd = 0;
96
    int code;
97
 
98
    check_type(*op, t_dictionary);
99
    code = dict_param_list_read(&list, op, NULL, false, iimemory);
100
    if (code < 0)
101
	return code;
102
    code = gs_cie_render1_build(&pcrd, mem, ".builddevicecolorrendering1");
103
    if (code >= 0) {
104
	code = param_get_cie_render1(pcrd, (gs_param_list *) & list,
105
				     gs_currentdevice(igs));
106
	if (code >= 0) {
107
	    /****** FIX refct ******/
108
	    /*rc_decrement(pcrd, ".builddevicecolorrendering1"); *//* build sets rc = 1 */
109
	}
110
    }
111
    iparam_list_release(&list);
112
    if (code < 0) {
113
	rc_free_struct(pcrd, ".builddevicecolorrendering1");
114
	return code;
115
    }
116
    istate->colorrendering.dict = *op;
117
    make_istruct_new(op, a_readonly, pcrd);
118
    return 0;
119
}
120
 
121
/* <dict> <crd> .setcolorrendering1 - */
122
private int
123
zsetcolorrendering1(i_ctx_t *i_ctx_p)
124
{
125
    os_ptr op = osp;
126
    es_ptr ep = esp;
127
    ref_cie_render_procs procs;
128
    int code;
129
 
130
    check_type(op[-1], t_dictionary);
131
    check_stype(*op, st_cie_render1);
132
    code = zcrd1_proc_params(imemory, op - 1, &procs);
133
    if (code < 0)
134
	return code;
135
    code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
136
    if (code < 0)
137
	return code;
138
    if (gs_cie_cs_common(igs) != 0 &&
139
	(code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
140
	)
141
	return code;
142
    istate->colorrendering.dict = op[-1];
143
    istate->colorrendering.procs = procs;
144
    pop(2);
145
    return (esp == ep ? 0 : o_push_estack);
146
}
147
 
148
/* <dict> <crd> .setdevicecolorrendering1 - */
149
private int
150
zsetdevicecolorrendering1(i_ctx_t *i_ctx_p)
151
{
152
    os_ptr op = osp;
153
    int code;
154
    ref_cie_render_procs procs;
155
 
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));
159
    if (code < 0)
160
	return code;
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
164
	)
165
	return code;
166
    istate->colorrendering.dict = op[-1];
167
    refset_null((ref *)&istate->colorrendering.procs,
168
		sizeof(istate->colorrendering.procs) / sizeof(ref));
169
    pop(2);
170
    return 0;
171
}
172
 
173
/* Get ColorRenderingType 1 procedures from the PostScript dictionary. */
174
private int
175
zcrd1_proc_params(const gs_memory_t *mem, 
176
		  os_ptr op, ref_cie_render_procs * pcprocs)
177
{
178
    int code;
179
    ref *pRT;
180
 
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
184
	)
185
	return (code < 0 ? code : gs_note_error(e_rangecheck));
186
    if (dict_find_string(op, "RenderTable", &pRT) > 0) {
187
	const ref *prte;
188
	int size;
189
	int i;
190
 
191
	check_read_type(*pRT, t_array);
192
	size = r_size(pRT);
193
	if (size < 5)
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),
199
			 size - 5, prte + 5);
200
    } else
201
	make_null(&pcprocs->RenderTableT);
202
    return 0;
203
}
204
 
205
/* Get ColorRenderingType 1 parameters from the PostScript dictionary. */
206
private int
207
zcrd1_params(os_ptr op, gs_cie_render * pcrd,
208
	     ref_cie_render_procs * pcprocs, gs_memory_t * mem)
209
{
210
    int code;
211
    int ignore;
212
    gx_color_lookup_table *const prtl = &pcrd->RenderTable.lookup;
213
    ref *pRT;
214
 
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
224
	)
225
	return code;
226
    if (dict_find_string(op, "RenderTable", &pRT) > 0) {
227
	const ref *prte = pRT->value.const_refs;
228
 
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);
233
	prtl->n = 3;
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);
238
	if (code < 0)
239
	    return code;
240
    } else {
241
	prtl->table = 0;
242
    }
243
    pcrd->EncodeLMN = Encode_default;
244
    pcrd->EncodeABC = Encode_default;
245
    pcrd->TransformPQR = TransformPQR_default;
246
    pcrd->RenderTable.T = RenderTableT_default;
247
    return 0;
248
}
249
 
250
/* Cache the results of the color rendering procedures. */
251
private int cie_cache_render_finish(i_ctx_t *);
252
private int
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)
256
{
257
    es_ptr ep = esp;
258
    int code = gs_cie_render_init(pcrd);	/* sets Domain values */
259
    int i;
260
 
261
    if (code < 0 ||
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
265
	) {
266
	esp = ep;
267
	return code;
268
    }
269
    if (pcrd->RenderTable.lookup.table != 0) {
270
	bool is_identity = true;
271
 
272
	for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
273
	    if (r_size(pcrprocs->RenderTableT.value.const_refs + i) != 0) {
274
		is_identity = false;
275
		break;
276
	    }
277
	pcrd->caches.RenderTableT_is_identity = is_identity;
278
	if (!is_identity)
279
	    for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
280
		if ((code =
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
285
		    ) {
286
		    esp = ep;
287
		    return code;
288
		}
289
    }
290
    return o_push_estack;
291
}
292
 
293
/* Finish up after loading the rendering caches. */
294
private int
295
cie_cache_render_finish(i_ctx_t *i_ctx_p)
296
{
297
    os_ptr op = osp;
298
    gs_cie_render *pcrd = r_ptr(op, gs_cie_render);
299
    int code;
300
 
301
    if (pcrd->RenderTable.lookup.table != 0 &&
302
	!pcrd->caches.RenderTableT_is_identity
303
	) {
304
	/* Convert the RenderTableT cache from floats to fracs. */
305
	int j;
306
 
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);
310
    }
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);
316
    if (code < 0)
317
	return code;
318
    pop(1);
319
    return 0;
320
}
321
 
322
/* ------ Internal procedures ------ */
323
 
324
/* Load the joint caches. */
325
private int
326
    cie_exec_tpqr(i_ctx_t *),
327
    cie_post_exec_tpqr(i_ctx_t *),
328
    cie_tpqr_finish(i_ctx_t *);
329
int
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)
332
{
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);
336
    ref pqr_procs;
337
    uint space;
338
    int code;
339
    int i;
340
 
341
    if (pcrd == 0)		/* cache is not set up yet */
342
	return 0;
343
    if (pjc == 0)		/* must already be allocated */
344
	return_error(e_VMerror);
345
    if (r_has_type(&pcrprocs->TransformPQR, t_null)) {
346
	/*
347
	 * This CRD came from a driver, not from a PostScript dictionary.
348
	 * Resample TransformPQR in C code.
349
	 */
350
	return gs_cie_cs_complete(pgs, true);
351
    }
352
    gs_cie_compute_points_sd(pjc, pcie, pcrd);
353
    code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
354
			    "cie_cache_common");
355
    if (code < 0)
356
	return code;
357
    /* When we're done, deallocate the procs and complete the caches. */
358
    check_estack(3);
359
    cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs);
360
    *++esp = pqr_procs;
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;
364
	const float *ppt = (float *)&pjc->points_sd;
365
	int j;
366
 
367
	make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
368
		   4, p);
369
	make_array(p, a_readonly | space, 4 * 6, p + 4);
370
	p[1] = pcrprocs->TransformPQR.value.refs[i];
371
	make_oper(p + 2, 0, cie_exec_tpqr);
372
	make_oper(p + 3, 0, cie_post_exec_tpqr);
373
	for (j = 0, p += 4; j < 4 * 6; j++, p++, ppt++)
374
	    make_real(p, *ppt);
375
    }
376
    return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR,
377
			      pqr_procs.value.const_refs,
378
			      pjc->TransformPQR.caches,
379
			      pjc, imem, "Transform.PQR");
380
}
381
 
382
/* Private operator to shuffle arguments for the TransformPQR procedure: */
383
/* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
384
private int
385
cie_exec_tpqr(i_ctx_t *i_ctx_p)
386
{
387
    os_ptr op = osp;
388
    const ref *ppt = op[-1].value.const_refs;
389
    uint space = r_space(op - 1);
390
    int i;
391
 
392
    check_op(3);
393
    push(4);
394
    *op = op[-4];		/* proc */
395
    op[-1] = op[-6];		/* v */
396
    for (i = 0; i < 4; i++)
397
	make_const_array(op - 5 + i, a_readonly | space,
398
			 6, ppt + i * 6);
399
    make_mark(op - 6);
400
    return zexec(i_ctx_p);
401
}
402
 
403
/* Remove extraneous values from the stack after executing */
404
/* the TransformPQR procedure.  -mark- ... v -> v */
405
private int
406
cie_post_exec_tpqr(i_ctx_t *i_ctx_p)
407
{
408
    os_ptr op = osp;
409
    uint count = ref_stack_counttomark(&o_stack);
410
    ref vref;
411
 
412
    if (count < 2)
413
	return_error(e_unmatchedmark);
414
    vref = *op;
415
    ref_stack_pop(&o_stack, count - 1);
416
    *osp = vref;
417
    return 0;
418
}
419
 
420
/* Free the procs array and complete the joint caches. */
421
private int
422
cie_tpqr_finish(i_ctx_t *i_ctx_p)
423
{
424
    os_ptr op = osp;
425
    gs_state *pgs = r_ptr(op, gs_state);
426
    gs_cie_render *pcrd =
427
	(gs_cie_render *)gs_currentcolorrendering(pgs);  /* break const */
428
    int code;
429
 
430
    ifree_ref_array(op - 1, "cie_tpqr_finish");
431
    pcrd->TransformPQR = TransformPQR_from_cache;
432
    code = gs_cie_cs_complete(pgs, false);
433
    pop(2);
434
    return code;
435
}
436
 
437
/* Ws Bs Wd Bd Ps .transformPQR_scale_wb[012] Pd
438
 
439
   The default TransformPQR procedure is implemented in C, rather than
440
   PostScript, as a speed optimization.
441
 
442
   This TransformPQR implements a relative colorimetric intent by scaling
443
   the XYZ values relative to the white and black points.
444
*/
445
private int
446
ztpqr_scale_wb_common(i_ctx_t *i_ctx_p, int idx)
447
{
448
    os_ptr op = osp;
449
    double a[4], Ps; /* a[0] = ws, a[1] = bs, a[2] = wd, a[3] = bd */
450
    double result;
451
    int code;
452
    int i;
453
 
454
    code = real_param(op, &Ps);
455
    if (code < 0) return code;
456
 
457
    for (i = 0; i < 4; i++) {
458
	ref tmp;
459
 
460
	code = array_get(imemory, op - 4 + i, idx, &tmp);
461
	if (code >= 0)
462
	    code = real_param(&tmp, &a[i]);
463
	if (code < 0) return code;
464
    }
465
 
466
    if (a[0] == a[1])
467
	return_error(e_undefinedresult);
468
    result = a[3] + (a[2] - a[3]) * (Ps - a[1]) / (a[0] - a[1]);
469
    make_real(op - 4, result);
470
    pop(4);
471
    return 0;
472
}
473
 
474
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb0 Pd */
475
private int
476
ztpqr_scale_wb0(i_ctx_t *i_ctx_p)
477
{
478
    return ztpqr_scale_wb_common(i_ctx_p, 3);
479
}
480
 
481
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
482
private int
483
ztpqr_scale_wb1(i_ctx_t *i_ctx_p)
484
{
485
    return ztpqr_scale_wb_common(i_ctx_p, 4);
486
}
487
 
488
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
489
private int
490
ztpqr_scale_wb2(i_ctx_t *i_ctx_p)
491
{
492
    return ztpqr_scale_wb_common(i_ctx_p, 5);
493
}
494
 
495
/* ------ Initialization procedure ------ */
496
 
497
const op_def zcrd_l2_op_defs[] =
498
{
499
    op_def_begin_level2(),
500
    {"0currentcolorrendering", zcurrentcolorrendering},
501
    {"2.setcolorrendering1", zsetcolorrendering1},
502
    {"2.setdevicecolorrendering1", zsetdevicecolorrendering1},
503
    {"1.buildcolorrendering1", zbuildcolorrendering1},
504
    {"1.builddevicecolorrendering1", zbuilddevicecolorrendering1},
505
		/* Internal "operators" */
506
    {"1%cie_render_finish", cie_cache_render_finish},
507
    {"3%cie_exec_tpqr", cie_exec_tpqr},
508
    {"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
509
    {"1%cie_tpqr_finish", cie_tpqr_finish},
510
    {"5.TransformPQR_scale_WB0", ztpqr_scale_wb0},
511
    {"5.TransformPQR_scale_WB1", ztpqr_scale_wb1},
512
    {"5.TransformPQR_scale_WB2", ztpqr_scale_wb2},
513
    op_def_end(0)
514
};