1 /* Copyright (C) 2001-2008 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
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.
12 */
13 
14 /* $Id: zicc.c 9380 2009-01-21 15:34:55Z ken $ */
15 /* ICCBased color operators */
16 
17 #include "math_.h"
18 #include "memory_.h"
19 #include "ghost.h"
20 #include "oper.h"
21 #include "gsstruct.h"
22 #include "gxcspace.h"		/* gscolor2.h requires gscspace.h */
23 #include "stream.h"
24 #include "files.h"
25 #include "gscolor2.h"
26 #include "icc.h"
27 #include "gsicc.h"
28 #include "estack.h"
29 #include "idict.h"
30 #include "idparam.h"
31 #include "igstate.h"
32 #include "icie.h"
33 #include "ialloc.h"
34 #include "zicc.h"
35 
seticc(i_ctx_t * i_ctx_p,int ncomps,ref * ICCdict,float * range_buff)36 int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff)
37 {
38     os_ptr                  op = osp;
39     int edepth = ref_stack_count(&e_stack);
40     int                     code, reuse_op = 0;
41     gs_color_space *        pcs;
42     gs_color_space *  palt_cs;
43     int                     i;
44     gs_cie_icc *            picc_info;
45     ref *                   pstrmval;
46     stream *                s = 0L;
47 
48     palt_cs = gs_currentcolorspace(igs);
49     /* verify the DataSource entry */
50     if (dict_find_string(ICCdict, "DataSource", &pstrmval) <= 0)
51         return_error(e_undefined);
52     check_read_file(s, pstrmval);
53 
54     /* build the color space object */
55     code = gs_cspace_build_CIEICC(&pcs, NULL, gs_state_memory(igs));
56     if (code < 0)
57         return code;
58     picc_info = pcs->params.icc.picc_info;
59     picc_info->num_components = ncomps;
60     picc_info->instrp = s;
61     picc_info->file_id = (s->read_id | s->write_id);
62     for (i = 0; i < ncomps; i++) {
63         picc_info->Range.ranges[i].rmin = range_buff[2 * i];
64         picc_info->Range.ranges[i].rmax = range_buff[2 * i + 1];
65 
66     }
67 
68     /* record the current space as the alternative color space */
69     pcs->base_space = palt_cs;
70     rc_increment(palt_cs);
71 
72     code = gx_load_icc_profile(picc_info);
73     if (code < 0)
74 	return code;
75 
76     /* If the input space to this profile is CIELAB, then we need to adjust the limits */
77     /* See ICC spec ICC.1:2004-10 Section 6.3.4.2 and 6.4 */
78     if(picc_info->plu->e_inSpace == icSigLabData)
79     {
80         picc_info->Range.ranges[0].rmin = 0.0;
81         picc_info->Range.ranges[0].rmax = 100.0;
82 
83         picc_info->Range.ranges[1].rmin = -128.0;
84         picc_info->Range.ranges[1].rmax = 127.0;
85 
86         picc_info->Range.ranges[2].rmin = -128.0;
87         picc_info->Range.ranges[2].rmax = 127.0;
88 
89     }
90     /* If the input space is icSigXYZData, then we should do the limits based upon the white point of the profile.  */
91     if(picc_info->plu->e_inSpace == icSigXYZData)
92     {
93 	for (i = 0; i < 3; i++)
94 	{
95 	    picc_info->Range.ranges[i].rmin = 0;
96 	}
97 
98 	picc_info->Range.ranges[0].rmax = picc_info->common.points.WhitePoint.u;
99 	picc_info->Range.ranges[1].rmax = picc_info->common.points.WhitePoint.v;
100     	picc_info->Range.ranges[2].rmax = picc_info->common.points.WhitePoint.w;
101     }
102 
103     code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs,
104 			   (gs_cie_common *)picc_info, igs);
105     if (code < 0)
106 	return code;
107 
108     return cie_set_finish( i_ctx_p,
109                            pcs,
110                            &istate->colorspace.procs.cie,
111                            edepth,
112                            code );
113 }
114 
115 /*
116  *   <dict>  .seticcspace  -
117  *
118  * Create an ICCBased color space and set it to be the current color space.
119  *
120  * The PostScript structure of an ICCBased color space is that same as that
121  * for a CIEBased* color space:
122  *
123  *     [ /ICCBased <dictionary> ]
124  *
125  * As is the for other .setcie*space operators, the operand dictionary rather
126  * than the complete color space array is on the stack when this operator
127  * is inovked.
128  *
129  * At the time this procedure is called, the alternative color space for
130  * the ICCBased color space is expected to be the current color space,
131  * whether that space was explicitly specified or implied by the number
132  * of components in the ICCBased color space dictionary. This is consistent
133  * with the handling of alternative spaces in Separation, DeviceN, and
134  * Indexed color spaces. Unlike the "zset*space" routines for those spaces,
135  * however, the current code does not attempt to build the color space
136  * "in place" in the graphic state.
137  *
138  * The procedure that invokes this operator will already have checked that
139  * the operand is a dictionary, is readable, and defines the key /N
140  * (number of components).
141  */
142 static int
zseticcspace(i_ctx_t * i_ctx_p)143 zseticcspace(i_ctx_t * i_ctx_p)
144 {
145     os_ptr                  op = osp;
146     int                     code;
147     gs_color_space *  palt_cs;
148     ref *                   pnval;
149     ref *                   pstrmval;
150     stream *                s;
151     int                     i, ncomps;
152     float                   range_buff[8];
153     static const float      dflt_range[8] = { 0, 1,   0, 1,   0, 1,   0, 1 };
154 
155     code = dict_find_string(op, "N", &pnval);
156     if (code < 0)
157 	return code;
158 
159     ncomps = pnval->value.intval;
160 
161     if (2*ncomps > sizeof(range_buff)/sizeof(range_buff[0]))
162         return_error(e_rangecheck);
163 
164     /* verify the DataSource entry */
165     if (dict_find_string(op, "DataSource", &pstrmval) <= 0)
166         return_error(e_undefined);
167     check_read_file(s, pstrmval);
168 
169     /*
170      * Verify that the current color space can be a alternative color space.
171      * The check for ICCBased color space is a hack to avoid introducing yet
172      * another category indicator into the gs_color_space_type structur.
173      */
174     palt_cs = gs_currentcolorspace(igs);
175     if ( !palt_cs->type->can_be_alt_space                                ||
176          gs_color_space_get_index(palt_cs) == gs_color_space_index_CIEICC  )
177         return_error(e_rangecheck);
178 
179     /*
180      * Fetch and verify the Range array.
181      *
182      * The PDF documentation is unclear as to the purpose of this array.
183      * Essentially all that is stated is that "These values must match the
184      * information in the ICC profile" (PDF Reference, 2nd ed., p. 174).
185      * If that is the case, why not use the information in the profile?
186      * The only reason we can think of is range specification is intended
187      * to be used to limit the range of values passed to the alternate
188      * color space (the range may be smaller than the native range of values
189      * provided by that color space).
190      *
191      * Because the icclib code will perform normalization based on color
192      * space, we use the range values only to restrict the set of input
193      * values; they are not used for normalization.
194      */
195     code = dict_floats_param( imemory,
196 			      op,
197                               "Range",
198                               2 * ncomps,
199                               range_buff,
200                               dflt_range );
201     for (i = 0; i < 2 * ncomps && range_buff[i + 1] >= range_buff[i]; i += 2)
202         ;
203     if (i != 2 * ncomps)
204         return_error(e_rangecheck);
205 
206     return seticc(i_ctx_p, ncomps, op, range_buff);
207 }
208 
209 
210 const op_def    zicc_ll3_op_defs[] = {
211     op_def_begin_ll3(),
212     { "1.seticcspace", zseticcspace },
213     op_def_end(0)
214 };
215