1 /* Copyright (C) 1989, 2000 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: zcolor.c,v 1.21 2004/10/01 23:35:02 ghostgum Exp $ */
18 /* Color operators */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "estack.h"
23 #include "ialloc.h"
24 #include "igstate.h"
25 #include "iutil.h"
26 #include "store.h"
27 #include "gxfixed.h"
28 #include "gxmatrix.h"
29 #include "gzstate.h"
30 #include "gxdcolor.h" /* for gxpcolor.h */
31 #include "gxdevice.h"
32 #include "gxdevmem.h" /* for gxpcolor.h */
33 #include "gxcmap.h"
34 #include "gxcspace.h"
35 #include "gxcolor2.h"
36 #include "gxpcolor.h"
37 #include "idict.h"
38 #include "icolor.h"
39 #include "idparam.h"
40 #include "iname.h"
41
42 /* imported from gsht.c */
43 extern void gx_set_effective_transfer(gs_state *);
44
45 /* define the number of stack slots needed for zcolor_remap_one */
46 const int zcolor_remap_one_ostack = 4;
47 const int zcolor_remap_one_estack = 3;
48
49
50 /* utility to test whether a Pattern instance uses a base space */
51 private inline bool
pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)52 pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)
53 {
54 return pinst->type->procs.uses_base_space(
55 pinst->type->procs.get_pattern(pinst) );
56 }
57
58 /*
59 * - currentcolor <param1> ... <paramN>
60 *
61 * Return the current color. <paramN> may be a dictionary or a null
62 * object, if the current color space is a pattern color space. The
63 * other parameters will be numeric.
64 *
65 * Note that the results of this operator differ slightly from those of
66 * most currentcolor implementations. If a color component value is
67 * integral (e.g.: 0, 1), it will be pushed on the stack as an integer.
68 * Most currentcolor implementations, including the earlier
69 * implementation in Ghostscript, would push real objects for all
70 * color spaces except indexed color space. The approach taken here is
71 * equally legitimate, and avoids special handling of indexed color
72 * spaces.
73 */
74 private int
zcurrentcolor(i_ctx_t * i_ctx_p)75 zcurrentcolor(i_ctx_t * i_ctx_p)
76 {
77 os_ptr op = osp;
78 const gs_color_space * pcs = gs_currentcolorspace(igs);
79 const gs_client_color * pcc = gs_currentcolor(igs);
80 int i, n = cs_num_components(pcs);
81 bool push_pattern = n < 0;
82
83 /* check for pattern */
84 if (push_pattern) {
85 gs_pattern_instance_t * pinst = pcc->pattern;
86
87 if (pinst == 0 || !pattern_instance_uses_base_space(pinst))
88 n = 1;
89 else
90 n = -n;
91 }
92
93 /* check for sufficient space on the stack */
94 push(n);
95 op -= n - 1;
96
97 /* push the numeric operands, if any */
98 if (push_pattern)
99 --n;
100 for (i = 0; i < n; i++, op++) {
101 float rval = pcc->paint.values[i];
102 int ival = (int)rval;
103
104 /* the following handles indexed color spaces */
105 if (rval == ival)
106 make_int(op, ival);
107 else
108 make_real(op, rval);
109 }
110
111 /* push the pattern dictionary or null object, if appropriate */
112 if (push_pattern)
113 *op = istate->pattern;
114
115 return 0;
116 }
117
118 /*
119 * - .currentcolorspace <array>
120 *
121 * Return the current color space. Unlike the prior implementation, the
122 * istate->color_space.array field will now always have a legitimate
123 * (array) value.
124 */
125 private int
zcurrentcolorspace(i_ctx_t * i_ctx_p)126 zcurrentcolorspace(i_ctx_t * i_ctx_p)
127 {
128 os_ptr op = osp; /* required by "push" macro */
129
130 push(1);
131 if ( gs_color_space_get_index(igs->color_space) == gs_color_space_index_DeviceGray ) {
132 ref gray, graystr;
133 ref csa = istate->colorspace.array;
134 if (array_get(imemory, &csa, 0, &gray) >= 0 &&
135 r_has_type(&gray, t_name) &&
136 (name_string_ref(imemory, &gray, &graystr),
137 r_size(&graystr) == 10 &&
138 !memcmp(graystr.value.bytes, "DeviceGray", 10))) {
139
140 *op = istate->colorspace.array;
141 } else {
142 int code = ialloc_ref_array(op, a_all, 1, "currentcolorspace");
143 if (code < 0)
144 return code;
145 return name_enter_string(imemory, "DeviceGray", op->value.refs);
146 }
147 } else
148 *op = istate->colorspace.array;
149 return 0;
150 }
151
152 /*
153 * - .getuseciecolor <bool>
154 *
155 * Return the current setting of the use_cie_color graphic state parameter,
156 * which tracks the UseCIEColor page device parameter. This parameter may be
157 * read (via this operator) at all language leves, but may only be set (via
158 * the .setuseciecolor operator; see zcolor3.c) only in language level 3.
159 *
160 * We handle this parameter separately from the page device primarily for
161 * performance reasons (the parameter may be queried frequently), but as a
162 * side effect achieve proper behavior relative to the language level. The
163 * interpreter is always initialized with this parameter set to false, and
164 * it can only be updated (via setpagedevice) in language level 3.
165 */
166 private int
zgetuseciecolor(i_ctx_t * i_ctx_p)167 zgetuseciecolor(i_ctx_t * i_ctx_p)
168 {
169 os_ptr op = osp;
170
171 push(1);
172 *op = istate->use_cie_color;
173 return 0;
174 }
175
176 /*
177 * <param1> ... <paramN> setcolor -
178 *
179 * Set the current color. All of the parameters except the topmost (paramN) are
180 * numbers; the topmost (and possibly only) entry may be pattern dictionary or
181 * a null object.
182 *
183 * The use of one operator to set both patterns and "normal" colors is
184 * consistent with Adobe's documentation, but primarily reflects the use of
185 * gs_setcolor for both purposes in the graphic library. An alternate
186 * implementation would use a .setpattern operator, which would interface with
187 * gs_setpattern.
188 *
189 * This operator is hidden by a pseudo-operator of the same name, so it will
190 * only be invoked under controlled situations. Hence, it does no operand
191 * checking.
192 */
193 private int
zsetcolor(i_ctx_t * i_ctx_p)194 zsetcolor(i_ctx_t * i_ctx_p)
195 {
196 os_ptr op = osp;
197 const gs_color_space * pcs = gs_currentcolorspace(igs);
198 gs_client_color cc;
199 int n_comps, n_numeric_comps, num_offset = 0, code;
200 bool is_ptype2 = 0;
201
202 /* initialize the client color pattern pointer for GC */
203 cc.pattern = 0;
204
205 /* check for a pattern color space */
206 if ((n_comps = cs_num_components(pcs)) < 0) {
207 n_comps = -n_comps;
208 if (r_has_type(op, t_dictionary)) {
209 ref * pImpl;
210 int ptype;
211
212 dict_find_string(op, "Implementation", &pImpl);
213 cc.pattern = r_ptr(pImpl, gs_pattern_instance_t);
214 n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern)
215 ? n_comps - 1
216 : 0 );
217 (void)dict_int_param(op, "PatternType", 1, 2, 1, &ptype);
218 is_ptype2 = ptype == 2;
219 } else
220 n_numeric_comps = 0;
221 num_offset = 1;
222 } else
223 n_numeric_comps = n_comps;
224
225 /* gather the numeric operands */
226 float_params(op - num_offset, n_numeric_comps, cc.paint.values);
227
228 /* pass the color to the graphic library */
229 if ((code = gs_setcolor(igs, &cc)) >= 0) {
230
231 if (n_comps > n_numeric_comps) {
232 istate->pattern = *op; /* save pattern dict or null */
233 n_comps = n_numeric_comps + 1;
234 }
235 pop(n_comps);
236 }
237
238 return code;
239 }
240
241 /*
242 * <array> setcolorspace -
243 *
244 * Set the nominal color space. This color space will be pushd by the
245 * currentcolorspace operator, but is not directly used to pass color
246 * space information to the graphic library.
247 *
248 * This operator can only be called from within the setcolorspace
249 * pseudo-operator; the definition of the latter will override this
250 * definition. Because error cheching is performed by the pseudo-
251 * operator, it need not be repeated here.
252 */
253 private int
zsetcolorspace(i_ctx_t * i_ctx_p)254 zsetcolorspace(i_ctx_t * i_ctx_p)
255 {
256 os_ptr op = osp;
257
258 istate->colorspace.array = *op;
259 pop(1);
260 return 0;
261 }
262
263 /*
264 * <name> .includecolorspace -
265 *
266 * See the comment for gs_includecolorspace in gscolor2.c .
267 */
268 private int
zincludecolorspace(i_ctx_t * i_ctx_p)269 zincludecolorspace(i_ctx_t * i_ctx_p)
270 {
271 os_ptr op = osp;
272 ref nsref;
273 int code;
274
275 check_type(*op, t_name);
276 name_string_ref(imemory, op, &nsref);
277 code = gs_includecolorspace(igs, nsref.value.const_bytes, r_size(&nsref));
278 if (!code)
279 pop(1);
280 return code;
281 }
282
283
284 /*
285 * <int> .setdevcspace -
286 *
287 * Set a parameterless color space. This is now used to set the
288 * DeviceGray, DeviceRGB, and DeviceCMYK color spaces, rather than
289 * the setgray/setrgbcolor/setcmykcolor operators. All PostScript-based
290 * color space substitution will have been accomplished before this
291 * operator is called.
292 *
293 * The use of an integer to indicate the specific color space is
294 * historical and on the whole not particularly desirable, as it ties
295 * the PostScript code to a specific enumeration. This may be modified
296 * in the future.
297 *
298 * As with setcolorspace, this operator is called only under controlled
299 * circumstances, hence it does no operand error checking.
300 */
301 private int
zsetdevcspace(i_ctx_t * i_ctx_p)302 zsetdevcspace(i_ctx_t * i_ctx_p)
303 {
304
305 gs_color_space cs;
306 int code;
307
308 switch((gs_color_space_index)osp->value.intval) {
309 default: /* can't happen */
310 case gs_color_space_index_DeviceGray:
311 gs_cspace_init_DeviceGray(imemory, &cs);
312 break;
313
314 case gs_color_space_index_DeviceRGB:
315 gs_cspace_init_DeviceRGB(imemory, &cs);
316 break;
317
318 case gs_color_space_index_DeviceCMYK:
319 gs_cspace_init_DeviceCMYK(imemory, &cs);
320 break;
321 }
322 if ((code = gs_setcolorspace(igs, &cs)) >= 0)
323 pop(1);
324 return code;
325 }
326
327
328 /* - currenttransfer <proc> */
329 private int
zcurrenttransfer(i_ctx_t * i_ctx_p)330 zcurrenttransfer(i_ctx_t *i_ctx_p)
331 {
332 os_ptr op = osp;
333
334 push(1);
335 *op = istate->transfer_procs.gray;
336 return 0;
337 }
338
339 /*
340 * - processcolors <int> -
341 *
342 * Note: this is an undocumented operator that is not supported
343 * in Level 2.
344 */
345 private int
zprocesscolors(i_ctx_t * i_ctx_p)346 zprocesscolors(i_ctx_t * i_ctx_p)
347 {
348 os_ptr op = osp;
349
350 push(1);
351 make_int(op, gs_currentdevice(igs)->color_info.num_components);
352 return 0;
353 }
354
355 /* <proc> settransfer - */
356 private int
zsettransfer(i_ctx_t * i_ctx_p)357 zsettransfer(i_ctx_t * i_ctx_p)
358 {
359 os_ptr op = osp;
360 int code;
361
362 check_proc(*op);
363 check_ostack(zcolor_remap_one_ostack - 1);
364 check_estack(1 + zcolor_remap_one_estack);
365 istate->transfer_procs.red =
366 istate->transfer_procs.green =
367 istate->transfer_procs.blue =
368 istate->transfer_procs.gray = *op;
369 if ((code = gs_settransfer_remap(igs, gs_mapped_transfer, false)) < 0)
370 return code;
371 push_op_estack(zcolor_reset_transfer);
372 pop(1);
373 return zcolor_remap_one( i_ctx_p,
374 &istate->transfer_procs.gray,
375 igs->set_transfer.gray,
376 igs,
377 zcolor_remap_one_finish );
378 }
379
380
381 /*
382 * Internal routines
383 */
384
385 /*
386 * Prepare to remap one color component (also used for black generation
387 * and undercolor removal). Use the 'for' operator to gather the values.
388 * The caller must have done the necessary check_ostack and check_estack.
389 */
390 int
zcolor_remap_one(i_ctx_t * i_ctx_p,const ref * pproc,gx_transfer_map * pmap,const gs_state * pgs,op_proc_t finish_proc)391 zcolor_remap_one(
392 i_ctx_t * i_ctx_p,
393 const ref * pproc,
394 gx_transfer_map * pmap,
395 const gs_state * pgs,
396 op_proc_t finish_proc )
397 {
398 os_ptr op;
399
400 /*
401 * Detect the identity function, which is a common value for one or
402 * more of these functions.
403 */
404 if (r_size(pproc) == 0) {
405 gx_set_identity_transfer(pmap);
406 /*
407 * Even though we don't actually push anything on the e-stack, all
408 * clients do, so we return o_push_estack in this case. This is
409 * needed so that clients' finishing procedures will get run.
410 */
411 return o_push_estack;
412 }
413 op = osp += 4;
414 make_real(op - 3, 0);
415 make_int(op - 2, transfer_map_size - 1);
416 make_real(op - 1, 1);
417 *op = *pproc;
418 ++esp;
419 make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory),
420 pmap);
421 push_op_estack(finish_proc);
422 push_op_estack(zfor_samples);
423 return o_push_estack;
424 }
425
426 /* Store the result of remapping a component. */
427 private int
zcolor_remap_one_store(i_ctx_t * i_ctx_p,floatp min_value)428 zcolor_remap_one_store(i_ctx_t *i_ctx_p, floatp min_value)
429 {
430 int i;
431 gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map);
432
433 if (ref_stack_count(&o_stack) < transfer_map_size)
434 return_error(e_stackunderflow);
435 for (i = 0; i < transfer_map_size; i++) {
436 double v;
437 int code =
438 real_param(ref_stack_index(&o_stack, transfer_map_size - 1 - i),
439 &v);
440
441 if (code < 0)
442 return code;
443 pmap->values[i] =
444 (v < min_value ? float2frac(min_value) :
445 v >= 1.0 ? frac_1 :
446 float2frac(v));
447 }
448 ref_stack_pop(&o_stack, transfer_map_size);
449 esp--; /* pop pointer to transfer map */
450 return o_pop_estack;
451 }
452 int
zcolor_remap_one_finish(i_ctx_t * i_ctx_p)453 zcolor_remap_one_finish(i_ctx_t *i_ctx_p)
454 {
455 return zcolor_remap_one_store(i_ctx_p, 0.0);
456 }
457 int
zcolor_remap_one_signed_finish(i_ctx_t * i_ctx_p)458 zcolor_remap_one_signed_finish(i_ctx_t *i_ctx_p)
459 {
460 return zcolor_remap_one_store(i_ctx_p, -1.0);
461 }
462
463 /* Finally, reset the effective transfer functions and */
464 /* invalidate the current color. */
465 int
zcolor_reset_transfer(i_ctx_t * i_ctx_p)466 zcolor_reset_transfer(i_ctx_t *i_ctx_p)
467 {
468 gx_set_effective_transfer(igs);
469 return zcolor_remap_color(i_ctx_p);
470 }
471 int
zcolor_remap_color(i_ctx_t * i_ctx_p)472 zcolor_remap_color(i_ctx_t *i_ctx_p)
473 {
474 gx_unset_dev_color(igs);
475 return 0;
476 }
477
478 /*
479 * <param1> ... <paramN> .color_test <param1> ... <paramN>
480 *
481 * encode and decode color to allow mapping to be tested.
482 */
483 private int
zcolor_test(i_ctx_t * i_ctx_p)484 zcolor_test(i_ctx_t *i_ctx_p)
485 {
486 gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
487 gx_device *dev = gs_currentdevice(igs);
488 int ncomp = dev->color_info.num_components;
489 gx_color_index color;
490 os_ptr op = osp - (ncomp-1);
491 int i;
492 if (ref_stack_count(&o_stack) < ncomp)
493 return_error(e_stackunderflow);
494 for (i = 0; i < ncomp; i++) {
495 if (r_has_type(op+i, t_real))
496 cv[i] = (gx_color_value)
497 (op[i].value.realval * gx_max_color_value);
498 else if (r_has_type(op+i, t_integer))
499 cv[i] = (gx_color_value)
500 (op[i].value.intval * gx_max_color_value);
501 else
502 return_error(e_typecheck);
503 }
504 color = (*dev_proc(dev, encode_color)) (dev, cv);
505 (*dev_proc(dev, decode_color)) (dev, color, cv);
506 for (i = 0; i < ncomp; i++)
507 make_real(op+i, (float)cv[i] / (float)gx_max_color_value);
508 return 0;
509 }
510
511 /*
512 * <levels> .color_test_all <value0> ... <valueN>
513 *
514 * Test encode/decode color procedures for a range of values.
515 * Return value with the worst error in a single component.
516 */
517 private int
zcolor_test_all(i_ctx_t * i_ctx_p)518 zcolor_test_all(i_ctx_t *i_ctx_p)
519 {
520 os_ptr op = osp;
521 gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
522 gx_color_value cvout[GX_DEVICE_COLOR_MAX_COMPONENTS];
523 gx_color_value cvbad[GX_DEVICE_COLOR_MAX_COMPONENTS];
524 int counter[GX_DEVICE_COLOR_MAX_COMPONENTS];
525 gx_device *dev = gs_currentdevice(igs);
526 int ncomp = dev->color_info.num_components;
527 int steps;
528 int maxerror = 0;
529 int err;
530 int acceptable_error;
531 int linsep = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN;
532 int linsepfailed = 0;
533 int lsmaxerror = 0;
534 gx_color_index color, lscolor;
535 int i, j, k;
536 int finished = 0;
537
538 if (ncomp == 1)
539 acceptable_error = gx_max_color_value / dev->color_info.max_gray + 1;
540 else
541 acceptable_error = gx_max_color_value / dev->color_info.max_color + 1;
542
543 if (ref_stack_count(&o_stack) < 1)
544 return_error(e_stackunderflow);
545 if (!r_has_type(&osp[0], t_integer))
546 return_error(e_typecheck);
547 steps = osp[0].value.intval;
548 for (i = 0; i < ncomp; i++) {
549 counter[i] = 0;
550 cvbad[i] = 0;
551 }
552
553 dprintf1("Number of components = %d\n", ncomp);
554 dprintf1("Depth = %d\n", dev->color_info.depth);
555 dprintf2("max_gray = %d dither_grays = %d\n",
556 dev->color_info.max_gray, dev->color_info.dither_grays);
557 dprintf2("max_color = %d dither_colors = %d\n",
558 dev->color_info.max_color, dev->color_info.dither_colors);
559 dprintf1("polarity = %s\n",
560 dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE ? "Additive" :
561 dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE ?"Subtractive":
562 "Unknown");
563 /* Indicate color index value with all colorants = zero */
564 for (i = 0; i < ncomp; i++)
565 cv[i] = 0;
566 color = (*dev_proc(dev, encode_color)) (dev, cv);
567 dprintf1("Zero color index: %8x\n", color);
568
569 dprintf1("separable_and_linear = %s\n",
570 linsep == GX_CINFO_SEP_LIN_NONE ? "No" :
571 linsep == GX_CINFO_SEP_LIN ? "Yes" :
572 "Unknown");
573 if (dev->color_info.gray_index == GX_CINFO_COMP_INDEX_UNKNOWN)
574 dprintf("gray_index is unknown\n");
575 else
576 dprintf1("gray_index = %d\n", dev->color_info.gray_index);
577 if (linsep) {
578 dprintf(" Shift Mask Bits\n");
579 for (i = 0; i < ncomp; i++) {
580 dprintf3(" %5d %8x %4d\n",
581 (int)(dev->color_info.comp_shift[i]),
582 (int)(dev->color_info.comp_mask[i]),
583 (int)(dev->color_info.comp_bits[i]));
584 }
585 }
586
587 while (!finished) {
588 for (j = 0; j <= steps; j++) {
589 for (i = 0; i < ncomp; i++)
590 cv[i] = counter[i] * gx_max_color_value / steps;
591 color = (*dev_proc(dev, encode_color)) (dev, cv);
592 if (linsep) {
593 /* Derive it the other way */
594 lscolor = gx_default_encode_color(dev, cv);
595 if ((color != lscolor) && (linsepfailed < 5)) {
596 linsepfailed++;
597 dprintf("Failed separable_and_linear for");
598 for (i = 0; i < ncomp; i++)
599 dprintf1(" %d", cv[i]);
600 dprintf("\n");
601 dprintf2("encode_color=%x gx_default_encode_color=%x\n",
602 (int)color, (int)lscolor);
603 }
604 }
605 (*dev_proc(dev, decode_color)) (dev, color, cvout);
606 for (i = 0; i < ncomp; i++) {
607 err = (int)cvout[i] - (int)cv[i];
608 if (err < 0)
609 err = -err;
610 if (err > maxerror) {
611 maxerror = err;
612 for (k=0; k < ncomp; k++)
613 cvbad[k] = cv[k];
614 }
615 }
616 if (linsep) {
617 gx_default_decode_color(dev, color, cvout);
618 for (i = 0; i < ncomp; i++) {
619 err = (int)cvout[i] - (int)cv[i];
620 if (err < 0)
621 err = -err;
622 if (err > lsmaxerror) {
623 lsmaxerror = err;
624 }
625 }
626 }
627 counter[0] += 1;
628 }
629 counter[0] = 0;
630 i = 1;
631 while (i < ncomp) {
632 counter[i] += 1;
633 if (counter[i] > steps) {
634 counter[i] = 0;
635 i++;
636 }
637 else
638 break;
639 }
640 if (i >= ncomp)
641 finished = 1;
642 }
643
644 dprintf2("Maximum error %g %s\n",
645 (float)maxerror / (float)gx_max_color_value,
646 maxerror <= acceptable_error ? "is Ok" :
647 maxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
648
649 if (linsep)
650 dprintf2("Maximum linear_and_separable error %g %s\n",
651 (float)lsmaxerror / (float)gx_max_color_value,
652 lsmaxerror <= acceptable_error ? "is Ok" :
653 lsmaxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
654
655 /* push worst value */
656 push(ncomp-1);
657 op -= ncomp - 1;
658 for (i = 0; i < ncomp; i++)
659 make_real(op+i, (float)cvbad[i] / (float)gx_max_color_value);
660
661 return 0;
662 }
663
664
665 /* ------ Initialization procedure ------ */
666
667 const op_def zcolor_op_defs[] =
668 {
669 { "0currentcolor", zcurrentcolor },
670 { "0currentcolorspace", zcurrentcolorspace },
671 { "0.getuseciecolor", zgetuseciecolor },
672 { "1setcolor", zsetcolor },
673 { "1setcolorspace", zsetcolorspace },
674 { "1.setdevcspace", zsetdevcspace },
675
676 /* basic transfer operators */
677 { "0currenttransfer", zcurrenttransfer },
678 { "0processcolors", zprocesscolors },
679 { "1settransfer", zsettransfer },
680
681 /* internal operators */
682 { "1%zcolor_remap_one_finish", zcolor_remap_one_finish },
683 { "1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish },
684 { "0%zcolor_reset_transfer", zcolor_reset_transfer },
685 { "0%zcolor_remap_color", zcolor_remap_color },
686 { "0.color_test", zcolor_test },
687 { "1.color_test_all", zcolor_test_all },
688
689
690 /* high level device support */
691 { "0.includecolorspace", zincludecolorspace },
692 op_def_end(0)
693 };
694