1 /* Copyright (C) 2001-2012 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,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Implementation of the ICCBased color space family */
18 
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsstruct.h"
24 #include "stream.h"
25 #include "gxcspace.h"		/* for gxcie.c */
26 #include "gxarith.h"
27 #include "gxcie.h"
28 #include "gzstate.h"
29 #include "gsicc.h"
30 #include "gsicc_cache.h"
31 #include "gsicc_cms.h"
32 #include "gxdevice.h"
33 
34 #define SAVEICCPROFILE 0
35 
36 /*
37  * Color space methods for ICCBased color spaces.
38    ICC spaces are now considered to be concrete in that
39    they always provide a mapping to a specified destination
40    profile.  As such they will have their own remap functions.
41    These will simply potentially implement the transfer function,
42    apply any alpha value, and or end up going through halftoning.
43    There will not be any heuristic remap of rgb to gray etc */
44 
45 static cs_proc_num_components(gx_num_components_ICC);
46 static cs_proc_init_color(gx_init_ICC);
47 static cs_proc_restrict_color(gx_restrict_ICC);
48 static cs_proc_concretize_color(gx_concretize_ICC);
49 static cs_proc_remap_color(gx_remap_ICC);
50 static cs_proc_install_cspace(gx_install_ICC);
51 static cs_proc_remap_concrete_color(gx_remap_concrete_ICC);
52 static cs_proc_final(gx_final_ICC);
53 static cs_proc_serialize(gx_serialize_ICC);
54 static cs_proc_is_linear(gx_cspace_is_linear_ICC);
55 static cs_proc_set_overprint(gx_set_overprint_ICC);
56 cs_proc_remap_color(gx_remap_ICC_imagelab);
57 
58 const gs_color_space_type gs_color_space_type_ICC = {
59     gs_color_space_index_ICC,       /* index */
60     true,                           /* can_be_base_space */
61     true,                           /* can_be_alt_space */
62     &st_base_color_space,           /* stype - structure descriptor */
63     gx_num_components_ICC,          /* num_components */
64     gx_init_ICC,                    /* init_color */
65     gx_restrict_ICC,                /* restrict_color */
66     gx_same_concrete_space,         /* concrete_space */
67     gx_concretize_ICC,              /* concreteize_color */
68     gx_remap_concrete_ICC,          /* remap_concrete_color */
69     gx_remap_ICC,                   /* remap_color */
70     gx_install_ICC,                 /* install_cpsace */
71     gx_set_overprint_ICC,           /* set_overprint */
72     gx_final_ICC,                   /* final */
73     gx_no_adjust_color_count,       /* adjust_color_count */
74     gx_serialize_ICC,               /* serialize */
75     gx_cspace_is_linear_ICC
76 };
77 
78 static inline void
gsicc_remap_fast(gx_device * dev,unsigned short * psrc,unsigned short * psrc_cm,gsicc_link_t * icc_link)79 gsicc_remap_fast(gx_device *dev, unsigned short *psrc, unsigned short *psrc_cm,
80                  gsicc_link_t *icc_link)
81 {
82     (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_cm, 2);
83 }
84 
85 /* ICC color mapping linearity check, a 2-points case. Check only the 1/2 point */
86 static int
gx_icc_is_linear_in_line(const gs_color_space * cs,const gs_imager_state * pis,gx_device * dev,const gs_client_color * c0,const gs_client_color * c1,float smoothness,gsicc_link_t * icclink)87 gx_icc_is_linear_in_line(const gs_color_space *cs, const gs_imager_state * pis,
88                         gx_device *dev,
89                         const gs_client_color *c0, const gs_client_color *c1,
90                         float smoothness, gsicc_link_t *icclink)
91 {
92     int nsrc = cs->type->num_components(cs);
93     cmm_dev_profile_t *dev_profile;
94     int ndes;
95     int code;
96     unsigned short src0[GS_CLIENT_COLOR_MAX_COMPONENTS];
97     unsigned short src1[GS_CLIENT_COLOR_MAX_COMPONENTS];
98     unsigned short src01[GS_CLIENT_COLOR_MAX_COMPONENTS];
99     unsigned short des0[GS_CLIENT_COLOR_MAX_COMPONENTS];
100     unsigned short des1[GS_CLIENT_COLOR_MAX_COMPONENTS];
101     unsigned short des01[GS_CLIENT_COLOR_MAX_COMPONENTS];
102     unsigned short interp_des;
103     unsigned short max_diff = (unsigned short) max(1, 65535 * smoothness);
104     int k;
105 
106     code = dev_proc(dev, get_profile)(dev, &(dev_profile));
107     ndes = gsicc_get_device_profile_comps(dev_profile);
108 
109     /* Get us to ushort and get mid point */
110     for (k = 0; k < nsrc; k++) {
111         src0[k] = (unsigned short) (c0->paint.values[k]*65535);
112         src1[k] = (unsigned short) (c1->paint.values[k]*65535);
113         src01[k] = ((unsigned int) src0[k] + (unsigned int) src1[k]) >> 1;
114     }
115     /* Transform the end points and the interpolated point */
116     gsicc_remap_fast(dev, &(src0[0]), &(des0[0]), icclink);
117     gsicc_remap_fast(dev, &(src1[0]), &(des1[0]), icclink);
118     gsicc_remap_fast(dev, &(src01[0]), &(des01[0]), icclink);
119     /* Interpolate 1/2 value in des space and compare */
120     for (k = 0; k < ndes; k++) {
121         interp_des = (des0[k] + des1[k]) >> 1;
122         if (any_abs((signed int) interp_des - (signed int) des01[k]) > max_diff)
123             return false;
124     }
125     return 1;
126 }
127 
128 /* Default icc color mapping linearity check, a triangle case. */
129 static int
gx_icc_is_linear_in_triangle(const gs_color_space * cs,const gs_imager_state * pis,gx_device * dev,const gs_client_color * c0,const gs_client_color * c1,const gs_client_color * c2,float smoothness,gsicc_link_t * icclink)130 gx_icc_is_linear_in_triangle(const gs_color_space *cs, const gs_imager_state * pis,
131                 gx_device *dev,
132                 const gs_client_color *c0, const gs_client_color *c1,
133                 const gs_client_color *c2, float smoothness, gsicc_link_t *icclink)
134 {
135     /* Check 4 points middle points of 3 sides and middle of one side with
136        other point.  We avoid divisions this way. */
137     unsigned short src0[GS_CLIENT_COLOR_MAX_COMPONENTS];
138     unsigned short src1[GS_CLIENT_COLOR_MAX_COMPONENTS];
139     unsigned short src2[GS_CLIENT_COLOR_MAX_COMPONENTS];
140     unsigned short des0[GS_CLIENT_COLOR_MAX_COMPONENTS];
141     unsigned short des1[GS_CLIENT_COLOR_MAX_COMPONENTS];
142     unsigned short des2[GS_CLIENT_COLOR_MAX_COMPONENTS];
143     unsigned short src01[GS_CLIENT_COLOR_MAX_COMPONENTS];
144     unsigned short src12[GS_CLIENT_COLOR_MAX_COMPONENTS];
145     unsigned short src02[GS_CLIENT_COLOR_MAX_COMPONENTS];
146     unsigned short src012[GS_CLIENT_COLOR_MAX_COMPONENTS];
147     unsigned short des01[GS_CLIENT_COLOR_MAX_COMPONENTS];
148     unsigned short des12[GS_CLIENT_COLOR_MAX_COMPONENTS];
149     unsigned short des02[GS_CLIENT_COLOR_MAX_COMPONENTS];
150     unsigned short des012[GS_CLIENT_COLOR_MAX_COMPONENTS];
151     int nsrc = cs->type->num_components(cs);
152     int ndes, code;
153     unsigned short max_diff = (unsigned short) max(1, 65535 * smoothness);
154     unsigned int interp_des;
155     int k;
156     cmm_dev_profile_t *dev_profile;
157 
158     code = dev_proc(dev, get_profile)(dev, &(dev_profile));
159     ndes = gsicc_get_device_profile_comps(dev_profile);
160 
161     /* This needs to be optimized. And range corrected */
162     for (k = 0; k < nsrc; k++){
163         src0[k] = (unsigned short) (c0->paint.values[k]*65535);
164         src1[k] = (unsigned short) (c1->paint.values[k]*65535);
165         src2[k] = (unsigned short) (c2->paint.values[k]*65535);
166         src01[k] = (src0[k] + src1[k]) >> 1;
167         src02[k] = (src0[k] + src2[k]) >> 1;
168         src12[k] = (src1[k] + src2[k]) >> 1;
169         src012[k] = (src12[k] + src0[k]) >> 1;
170     }
171     /* Map the points */
172     gsicc_remap_fast(dev, &(src0[0]), &(des0[0]), icclink);
173     gsicc_remap_fast(dev, &(src1[0]), &(des1[0]), icclink);
174     gsicc_remap_fast(dev, &(src2[0]), &(des2[0]), icclink);
175     gsicc_remap_fast(dev, &(src01[0]), &(des01[0]), icclink);
176     gsicc_remap_fast(dev, &(src12[0]), &(des12[0]), icclink);
177     gsicc_remap_fast(dev, &(src02[0]), &(des02[0]), icclink);
178     gsicc_remap_fast(dev, &(src012[0]), &(des012[0]), icclink);
179     /* Interpolate in des space and check it */
180     for (k = 0; k < ndes; k++){
181         interp_des = (des0[k] + des1[k]) >> 1;
182         if (any_abs((signed int) interp_des - (signed int) des01[k]) > max_diff)
183             return false;
184         interp_des = (des0[k] + des2[k]) >> 1;
185         if (any_abs((signed int) interp_des - (signed int) des02[k]) > max_diff)
186             return false;
187         interp_des = (des1[k] + des2[k]) >> 1;
188         if (any_abs((signed int) interp_des - (signed int) des12[k]) > max_diff)
189             return false;
190         /* 12 with 0 */
191         interp_des = (des0[k] + interp_des) >> 1;
192         if (any_abs((signed int) interp_des - (signed int) des012[k]) > max_diff)
193             return false;
194     }
195     return 1;
196 }
197 
198 /* ICC color mapping linearity check. */
199 int
gx_cspace_is_linear_ICC(const gs_color_space * cs,const gs_imager_state * pis,gx_device * dev,const gs_client_color * c0,const gs_client_color * c1,const gs_client_color * c2,const gs_client_color * c3,float smoothness,gsicc_link_t * icclink)200 gx_cspace_is_linear_ICC(const gs_color_space *cs, const gs_imager_state * pis,
201                 gx_device *dev,
202                 const gs_client_color *c0, const gs_client_color *c1,
203                 const gs_client_color *c2, const gs_client_color *c3,
204                 float smoothness, gsicc_link_t *icclink)
205 {
206     /* Assuming 2 <= nc <= 4. We don't need other cases. */
207     /* With nc == 4 assuming a convex plain quadrangle in the client color space. */
208     int code;
209 
210     /* Do a quick check if we are in a halftone situation. If yes,
211        then we should not be doing this linear check */
212     if (gx_device_must_halftone(dev)) return 0;
213     if (icclink->is_identity) return 1; /* Transform is identity, linear! */
214 
215     if (dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN)
216         return_error(gs_error_rangecheck);
217     if (c2 == NULL)
218         return gx_icc_is_linear_in_line(cs, pis, dev, c0, c1, smoothness, icclink);
219     code = gx_icc_is_linear_in_triangle(cs, pis, dev, c0, c1, c2,
220                                             smoothness, icclink);
221     if (code <= 0)
222         return code;
223     if (c3 == NULL)
224         return 1;
225     return gx_icc_is_linear_in_triangle(cs, pis, dev, c1, c2, c3,
226                                                 smoothness, icclink);
227 }
228 /*
229  * Return the number of components used by a ICCBased color space - 1, 3, or 4
230  */
231 static int
gx_num_components_ICC(const gs_color_space * pcs)232 gx_num_components_ICC(const gs_color_space * pcs)
233 {
234     return pcs->cmm_icc_profile_data->num_comps;
235 }
236 
237 /*
238  * Set the initial client color for an ICCBased color space. The convention
239  * suggested by the ICC specification is to set all components to 0.
240  */
241 static void
gx_init_ICC(gs_client_color * pcc,const gs_color_space * pcs)242 gx_init_ICC(gs_client_color * pcc, const gs_color_space * pcs)
243 {
244     int     i, ncomps = pcs->cmm_icc_profile_data->num_comps;
245 
246     for (i = 0; i < ncomps; ++i)
247         pcc->paint.values[i] = 0.0;
248 
249     /* make sure that [ 0, ... 0] is in range */
250     gx_restrict_ICC(pcc, pcs);
251 }
252 
253 /*
254  * Restrict an color to the range specified for an ICCBased color space.
255  */
256 static void
gx_restrict_ICC(gs_client_color * pcc,const gs_color_space * pcs)257 gx_restrict_ICC(gs_client_color * pcc, const gs_color_space * pcs)
258 {
259     int                 i, ncomps = pcs->cmm_icc_profile_data->num_comps;
260     const gs_range *    ranges = pcs->cmm_icc_profile_data->Range.ranges;
261 
262     for (i = 0; i < ncomps; ++i) {
263         floatp  v = pcc->paint.values[i];
264         floatp  rmin = ranges[i].rmin, rmax = ranges[i].rmax;
265 
266         if (v < rmin)
267             pcc->paint.values[i] = rmin;
268         else if (v > rmax)
269             pcc->paint.values[i] = rmax;
270     }
271 }
272 
273 /* If the color is already concretized, then we are in the color space
274    defined by the device profile.  The remaining things to do would
275    be to potentially apply alpha, apply the transfer function, and
276    do any halftoning.  The remap is based upon the ICC profile defined
277    in the device profile entry of the profile manager. */
278 int
gx_remap_concrete_ICC(const frac * pconc,const gs_color_space * pcs,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)279 gx_remap_concrete_ICC(const frac * pconc, const gs_color_space * pcs,
280         gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
281                           gs_color_select_t select)
282 {
283     int num_colorants;
284     int code;
285     cmm_dev_profile_t *dev_profile;
286 
287     code = dev_proc(dev, get_profile)(dev, &dev_profile);
288     num_colorants = gsicc_get_device_profile_comps(dev_profile);
289     switch( num_colorants ) {
290         case 1:
291             code = gx_remap_concrete_DGray(pconc, pcs, pdc, pis, dev, select);
292             break;
293         case 3:
294             code = gx_remap_concrete_DRGB(pconc, pcs, pdc, pis, dev, select);
295             break;
296         case 4:
297             code = gx_remap_concrete_DCMYK(pconc, pcs, pdc, pis, dev, select);
298             break;
299         default:
300             /* Need to do some work on integrating DeviceN and the new ICC flow */
301             /* code = gx_remap_concrete_DeviceN(pconc, pcs, pdc, pis, dev, select); */
302             code = -1;
303             break;
304         }
305     return code;
306     }
307 
308 /*
309  * To device space
310  */
311 int
gx_remap_ICC(const gs_client_color * pcc,const gs_color_space * pcs,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)312 gx_remap_ICC(const gs_client_color * pcc, const gs_color_space * pcs,
313         gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
314                 gs_color_select_t select)
315 {
316     gsicc_link_t *icc_link;
317     gsicc_rendering_param_t rendering_params;
318     unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS], psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS];
319     unsigned short *psrc_temp;
320     frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
321     int k,i;
322 #ifdef DEBUG
323     int num_src_comps;
324 #endif
325     int num_des_comps;
326     int code;
327     cmm_dev_profile_t *dev_profile;
328 
329     code = dev_proc(dev, get_profile)(dev, &dev_profile);
330     num_des_comps = gsicc_get_device_profile_comps(dev_profile);
331     rendering_params.black_point_comp = BP_ON;
332     rendering_params.graphics_type_tag = dev->graphics_type_tag;
333     /* Need to figure out which one rules here on rendering intent.  The
334        source of the device */
335     rendering_params.rendering_intent = pis->renderingintent;
336 
337     /* Need to clear out psrc_cm in case we have separation bands that are
338        not color managed */
339     memset(psrc_cm,0,sizeof(unsigned short)*GS_CLIENT_COLOR_MAX_COMPONENTS);
340 
341      /* This needs to be optimized */
342     if (pcs->cmm_icc_profile_data->data_cs == gsCIELAB ||
343         pcs->cmm_icc_profile_data->islab) {
344         psrc[0] = (unsigned short) (pcc->paint.values[0]*65535.0/100.0);
345         psrc[1] = (unsigned short) ((pcc->paint.values[1]+128)/255.0*65535.0);
346         psrc[2] = (unsigned short) ((pcc->paint.values[2]+128)/255.0*65535.0);
347     } else {
348         for (k = 0; k < pcs->cmm_icc_profile_data->num_comps; k++){
349             psrc[k] = (unsigned short) (pcc->paint.values[k]*65535.0);
350         }
351     }
352     /* Get a link from the cache, or create if it is not there. Need to get 16 bit profile */
353     icc_link = gsicc_get_link(pis, dev, pcs, NULL, &rendering_params, pis->memory);
354     if (icc_link == NULL) {
355         return gs_rethrow(-1, "Could not create ICC link:  Check profiles");
356     }
357     if (icc_link->is_identity) {
358         psrc_temp = &(psrc[0]);
359     } else {
360         /* Transform the color */
361         psrc_temp = &(psrc_cm[0]);
362         (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2);
363     }
364 #ifdef DEBUG
365     if (!icc_link->is_identity) {
366         num_src_comps = pcs->cmm_icc_profile_data->num_comps;
367         if_debug0(gs_debug_flag_icc,"[icc] remap [ ");
368         for (k = 0; k < num_src_comps; k++) {
369             if_debug1(gs_debug_flag_icc, "%d ",psrc[k]);
370         }
371         if_debug0(gs_debug_flag_icc,"] --> [ ");
372         for (k = 0; k < num_des_comps; k++) {
373             if_debug1(gs_debug_flag_icc, "%d ",psrc_temp[k]);
374         }
375         if_debug0(gs_debug_flag_icc,"]\n");
376     }
377 #endif
378     /* Release the link */
379     gsicc_release_link(icc_link);
380     /* Now do the remap for ICC which amounts to the alpha application
381        the transfer function and potentially the halftoning */
382     /* Right now we need to go from unsigned short to frac.  I really
383        would like to avoid this sort of stuff.  That will come. */
384     for ( k = 0; k < num_des_comps; k++){
385         conc[k] = ushort2frac(psrc_temp[k]);
386     }
387     gx_remap_concrete_ICC(conc, pcs, pdc, pis, dev, select);
388 
389     /* Save original color space and color info into dev color */
390     i = pcs->cmm_icc_profile_data->num_comps;
391     for (i--; i >= 0; i--)
392         pdc->ccolor.paint.values[i] = pcc->paint.values[i];
393     pdc->ccolor_valid = true;
394     return 0;
395 }
396 
397 /*
398  * Same as above, but there is no rescale of CIELAB colors.  This is needed
399    since the rescale is not needed when the source data is image based.
400    The DeviceN image rendering case uses the remap proc vs. the ICC based method
401    which handles the remapping itself.
402  */
403 int
gx_remap_ICC_imagelab(const gs_client_color * pcc,const gs_color_space * pcs,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)404 gx_remap_ICC_imagelab(const gs_client_color * pcc, const gs_color_space * pcs,
405         gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
406                 gs_color_select_t select)
407 {
408     gsicc_link_t *icc_link;
409     gsicc_rendering_param_t rendering_params;
410     unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS], psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS];
411     unsigned short *psrc_temp;
412     frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
413     int k,i;
414     int num_des_comps;
415     int code;
416     cmm_dev_profile_t *dev_profile;
417 
418     code = dev_proc(dev, get_profile)(dev, &dev_profile);
419     num_des_comps = gsicc_get_device_profile_comps(dev_profile);
420     rendering_params.black_point_comp = BP_ON;
421     rendering_params.graphics_type_tag = dev->graphics_type_tag;
422     /* Need to figure out which one rules here on rendering intent.  The
423        source of the device */
424     rendering_params.rendering_intent = pis->renderingintent;
425 
426     /* Need to clear out psrc_cm in case we have separation bands that are
427        not color managed */
428     memset(psrc_cm,0,sizeof(unsigned short)*GS_CLIENT_COLOR_MAX_COMPONENTS);
429 
430     for (k = 0; k < pcs->cmm_icc_profile_data->num_comps; k++)
431         psrc[k] = (unsigned short) (pcc->paint.values[k]*65535.0);
432 
433     /* Get a link from the cache, or create if it is not there. Need to get 16 bit profile */
434     icc_link = gsicc_get_link(pis, dev, pcs, NULL, &rendering_params, pis->memory);
435     if (icc_link == NULL) {
436         return gs_rethrow(-1, "Could not create ICC link:  Check profiles");
437     }
438     if (icc_link->is_identity) {
439         psrc_temp = &(psrc[0]);
440     } else {
441         /* Transform the color */
442         psrc_temp = &(psrc_cm[0]);
443         (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2);
444     }
445     /* Release the link */
446     gsicc_release_link(icc_link);
447     /* Now do the remap for ICC which amounts to the alpha application
448        the transfer function and potentially the halftoning */
449     /* Right now we need to go from unsigned short to frac.  I really
450        would like to avoid this sort of stuff.  That will come. */
451     for ( k = 0; k < num_des_comps; k++){
452         conc[k] = ushort2frac(psrc_temp[k]);
453     }
454     gx_remap_concrete_ICC(conc, pcs, pdc, pis, dev, select);
455 
456     /* Save original color space and color info into dev color */
457     i = pcs->cmm_icc_profile_data->num_comps;
458     for (i--; i >= 0; i--)
459         pdc->ccolor.paint.values[i] = pcc->paint.values[i];
460     pdc->ccolor_valid = true;
461     return 0;
462 }
463 
464 /* Convert an ICCBased color space to a concrete color space. */
465 
466 static int
gx_concretize_ICC(const gs_client_color * pcc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis,gx_device * dev)467 gx_concretize_ICC(
468     const gs_client_color * pcc,
469     const gs_color_space *  pcs,
470     frac *                  pconc,
471     const gs_imager_state * pis,
472     gx_device *dev)
473     {
474 
475     gsicc_link_t *icc_link;
476     gsicc_rendering_param_t rendering_params;
477     unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS], psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS];
478     int k;
479     unsigned short *psrc_temp;
480     int num_des_comps;
481     int code;
482     cmm_dev_profile_t *dev_profile;
483 
484     code = dev_proc(dev, get_profile)(dev, &dev_profile);
485     num_des_comps = gsicc_get_device_profile_comps(dev_profile);
486     /* Define the rendering intents.  MJV to fix */
487     rendering_params.black_point_comp = BP_ON;
488     rendering_params.graphics_type_tag = dev->graphics_type_tag;
489     rendering_params.rendering_intent = pis->renderingintent;
490     for (k = 0; k < pcs->cmm_icc_profile_data->num_comps; k++) {
491         psrc[k] = (unsigned short) (pcc->paint.values[k]*65535.0);
492     }
493     /* Get a link from the cache, or create if it is not there. Get 16 bit profile */
494     icc_link = gsicc_get_link(pis, dev, pcs, NULL, &rendering_params, pis->memory);
495     if (icc_link == NULL) {
496         return gs_rethrow(-1, "Could not create ICC link:  Check profiles");
497     }
498     /* Transform the color */
499     if (icc_link->is_identity) {
500         psrc_temp = &(psrc[0]);
501     } else {
502         /* Transform the color */
503         psrc_temp = &(psrc_cm[0]);
504         (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2);
505     }
506     /* This needs to be optimized */
507     for (k = 0; k < num_des_comps; k++){
508         pconc[k] = float2frac(((float) psrc_temp[k])/65535.0);
509     }
510     /* Release the link */
511     gsicc_release_link(icc_link);
512     return 0;
513 }
514 
515         /*
516  * Finalize the contents of an ICC color space. Now that color space
517  * objects have straightforward reference counting discipline, there's
518  * nothing special about it. In the previous state of affairs, the
519  * argument in favor of correct reference counting spoke of "an
520  * unintuitive but otherwise legitimate state of affairs".
521          */
522 static void
gx_final_ICC(const gs_color_space * pcs)523 gx_final_ICC(const gs_color_space * pcs)
524 {
525     if (pcs->cmm_icc_profile_data != NULL) {
526         rc_decrement_only(pcs->cmm_icc_profile_data, "gx_final_ICC");
527     }
528 }
529 
530 /*
531  * Install an ICCBased color space.
532  *
533  * Note that an ICCBased color space must be installed before it is known if
534  * the ICC profile or the alternate color space is to be used.
535  */
536 static int
gx_install_ICC(gs_color_space * pcs,gs_state * pgs)537 gx_install_ICC(gs_color_space * pcs, gs_state * pgs)
538 {
539     /* update the stub information used by the joint caches */
540     return 0;
541 }
542 
543 /*
544  * Constructor for ICCBased color space. As with the other color space
545  * constructors, this provides only minimal initialization.
546  */
547 int
gs_cspace_build_ICC(gs_color_space ** ppcspace,void * client_data,gs_memory_t * pmem)548 gs_cspace_build_ICC(
549     gs_color_space **   ppcspace,
550     void *              client_data,
551     gs_memory_t *       pmem )
552 {
553     gs_color_space *pcspace = gs_cspace_alloc(pmem, &gs_color_space_type_ICC);
554     *ppcspace = pcspace;
555 
556     return 0;
557 }
558 
559 /* ---------------- Serialization. -------------------------------- */
560 
561 static int
gx_serialize_ICC(const gs_color_space * pcs,stream * s)562 gx_serialize_ICC(const gs_color_space * pcs, stream * s)
563 {
564     gsicc_serialized_profile_t *profile__serial;
565     uint n;
566     int code = gx_serialize_cspace_type(pcs, s);
567 
568     if (code < 0)
569         return code;
570     profile__serial = (gsicc_serialized_profile_t*) pcs->cmm_icc_profile_data;
571     code = sputs(s, (byte *)profile__serial, sizeof(gsicc_serialized_profile_t), &n);
572     return(code);
573 }
574 
575 /* Overprint.  Here we may have either spot colors or CMYK colors. */
576 static int
gx_set_overprint_ICC(const gs_color_space * pcs,gs_state * pgs)577 gx_set_overprint_ICC(const gs_color_space * pcs, gs_state * pgs)
578 {
579     gx_device *             dev = pgs->device;
580     gx_device_color_info *  pcinfo = (dev == 0 ? 0 : &dev->color_info);
581 
582     /* check if we require special handling */
583     if ( !pgs->overprint                      ||
584          pgs->overprint_mode != 1             ||
585          pcinfo == 0                          ||
586          pcs->cmm_icc_profile_data->data_cs != gsCMYK ||
587          pcinfo->opmode == GX_CINFO_OPMODE_NOT  )
588         return gx_spot_colors_set_overprint(pcs, pgs);
589 
590     if (pcinfo->opmode == GX_CINFO_OPMODE_RGB ||
591         pcinfo->opmode == GC_CINFO_OPMODE_RGB_SET) {
592         return gx_set_overprint_rgb(pcs, pgs);
593     } else {
594         return gx_set_overprint_cmyk(pcs, pgs);
595     }
596 }
597 
598 int
gx_default_get_profile(gx_device * dev,cmm_dev_profile_t ** profile)599 gx_default_get_profile(gx_device *dev, cmm_dev_profile_t **profile)
600 {
601     *profile = dev->icc_struct;
602     return 0;
603 }
604