xref: /plan9/sys/src/cmd/gs/src/zicc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2001 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: zicc.c,v 1.7 2004/08/04 19:36:13 stefan Exp $ */
18 /* ICCBased color operators */
19 
20 #include "math_.h"
21 #include "memory_.h"
22 #include "ghost.h"
23 #include "oper.h"
24 #include "gsstruct.h"
25 #include "gxcspace.h"		/* gscolor2.h requires gscspace.h */
26 #include "stream.h"
27 #include "files.h"
28 #include "gscolor2.h"
29 #include "gsicc.h"
30 #include "estack.h"
31 #include "idict.h"
32 #include "idparam.h"
33 #include "igstate.h"
34 #include "icie.h"
35 #include "ialloc.h"
36 
37 /*
38  *   <dict>  .seticcspace  -
39  *
40  * Create an ICCBased color space and set it to be the current color space.
41  *
42  * The PostScript structure of an ICCBased color space is that same as that
43  * for a CIEBased* color space:
44  *
45  *     [ /ICCBased <dictionary> ]
46  *
47  * As is the for other .setcie*space operators, the operand dictionary rather
48  * than the complete color space array is on the stack when this operator
49  * is inovked.
50  *
51  * At the time this procedure is called, the alternative color space for
52  * the ICCBased color space is expected to be the current color space,
53  * whether that space was explicitly specified or implied by the number
54  * of components in the ICCBased color space dictionary. This is consistent
55  * with the handling of alternative spaces in Separation, DeviceN, and
56  * Indexed color spaces. Unlike the "zset*space" routines for those spaces,
57  * however, the current code does not attempt to build the color space
58  * "in place" in the graphic state.
59  *
60  * The procedure that invokes this operator will already have checked that
61  * the operand is a dictionary, is readable, and defines the key /N
62  * (number of components).
63  */
64 private int
zseticcspace(i_ctx_t * i_ctx_p)65 zseticcspace(i_ctx_t * i_ctx_p)
66 {
67     os_ptr                  op = osp;
68     int edepth = ref_stack_count(&e_stack);
69     int                     code;
70     gs_color_space *        pcs;
71     const gs_color_space *  palt_cs;
72     ref *                   pnval;
73     ref *                   pstrmval;
74     stream *                s;
75     int                     i, ncomps;
76     gs_cie_icc *            picc_info;
77     float                   range_buff[8];
78     static const float      dflt_range[8] = { 0, 1,   0, 1,   0, 1,   0, 1 };
79 
80     dict_find_string(op, "N", &pnval);
81     ncomps = pnval->value.intval;
82 
83     /* verify the DataSource entry */
84     if (dict_find_string(op, "DataSource", &pstrmval) <= 0)
85         return_error(e_undefined);
86     check_read_file(s, pstrmval);
87 
88     /*
89      * Verify that the current color space can be a alternative color space.
90      * The check for ICCBased color space is a hack to avoid introducing yet
91      * another category indicator into the gs_color_space_type structur.
92      */
93     palt_cs = gs_currentcolorspace(igs);
94     if ( !palt_cs->type->can_be_alt_space                                ||
95          gs_color_space_get_index(palt_cs) == gs_color_space_index_CIEICC  )
96         return_error(e_rangecheck);
97 
98     /*
99      * Fetch and verify the Range array.
100      *
101      * The PDF documentation is unclear as to the purpose of this array.
102      * Essentially all that is stated is that "These values must match the
103      * information in the ICC profile" (PDF Reference, 2nd ed., p. 174).
104      * If that is the case, why not use the information in the profile?
105      * The only reason we can think of is range specification is intended
106      * to be used to limit the range of values passed to the alternate
107      * color space (the range may be smaller than the native range of values
108      * provided by that color space).
109      *
110      * Because the icclib code will perform normalization based on color
111      * space, we use the range values only to restrict the set of input
112      * values; they are not used for normalization.
113      */
114     code = dict_floats_param( imemory,
115 			      op,
116                               "Range",
117                               2 * ncomps,
118                               range_buff,
119                               dflt_range );
120     for (i = 0; i < 2 * ncomps && range_buff[i + 1] >= range_buff[i]; i += 2)
121         ;
122     if (i != 2 * ncomps)
123         return_error(e_rangecheck);
124 
125     /* build the color space object */
126     code = gs_cspace_build_CIEICC(&pcs, NULL, gs_state_memory(igs));
127     if (code < 0)
128         return code;
129     picc_info = pcs->params.icc.picc_info;
130     picc_info->num_components = ncomps;
131     picc_info->instrp = s;
132     picc_info->file_id = (s->read_id | s->write_id);
133     for (i = 0; i < ncomps; i++) {
134         picc_info->Range.ranges[i].rmin = range_buff[2 * i];
135         picc_info->Range.ranges[i].rmax = range_buff[2 * i + 1];
136 
137     }
138 
139     /* record the current space as the alternative color space */
140     memmove( &pcs->params.icc.alt_space,
141              palt_cs,
142              sizeof(pcs->params.icc.alt_space) );
143     /*
144      * Increment reference counts for current cspace since it is the
145      * alternate color space for the ICC space.
146      */
147     gx_increment_cspace_count(palt_cs);
148 
149     code = gx_load_icc_profile(picc_info);
150     if (code < 0)
151 	return code;
152 
153     code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs,
154 			   (gs_cie_common *)picc_info, igs);
155     if (code < 0)
156 	return code;
157 
158     return cie_set_finish( i_ctx_p,
159                            pcs,
160                            &istate->colorspace.procs.cie,
161                            edepth,
162                            code );
163 }
164 
165 
166 const op_def    zicc_ll3_op_defs[] = {
167     op_def_begin_ll3(),
168     { "1.seticcspace", zseticcspace },
169     op_def_end(0)
170 };
171