/src/ghostpdl/base/gsicc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, 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 "gsicc_manage.h" |
33 | | #include "gxdevice.h" |
34 | | #include "gsccolor.h" |
35 | | #include "gxdevsop.h" |
36 | | |
37 | | #define SAVEICCPROFILE 0 |
38 | | |
39 | | /* |
40 | | * Color space methods for ICCBased color spaces. |
41 | | ICC spaces are now considered to be concrete in that |
42 | | they always provide a mapping to a specified destination |
43 | | profile. As such they will have their own remap functions. |
44 | | These will simply potentially implement the transfer function, |
45 | | apply any alpha value, and or end up going through halftoning. |
46 | | There will not be any heuristic remap of rgb to gray etc */ |
47 | | |
48 | | static cs_proc_num_components(gx_num_components_ICC); |
49 | | static cs_proc_init_color(gx_init_ICC); |
50 | | static cs_proc_restrict_color(gx_restrict_ICC); |
51 | | static cs_proc_concretize_color(gx_concretize_ICC); |
52 | | static cs_proc_remap_color(gx_remap_ICC); |
53 | | static cs_proc_install_cspace(gx_install_ICC); |
54 | | static cs_proc_remap_concrete_color(gx_remap_concrete_ICC); |
55 | | static cs_proc_final(gx_final_ICC); |
56 | | static cs_proc_serialize(gx_serialize_ICC); |
57 | | static cs_proc_is_linear(gx_cspace_is_linear_ICC); |
58 | | static cs_proc_set_overprint(gx_set_overprint_ICC); |
59 | | static cs_proc_polarity(gx_polarity_ICC); |
60 | | cs_proc_remap_color(gx_remap_ICC_imagelab); |
61 | | |
62 | | const gs_color_space_type gs_color_space_type_ICC = { |
63 | | gs_color_space_index_ICC, /* index */ |
64 | | true, /* can_be_base_space */ |
65 | | true, /* can_be_alt_space */ |
66 | | &st_base_color_space, /* stype - structure descriptor */ |
67 | | gx_num_components_ICC, /* num_components */ |
68 | | gx_init_ICC, /* init_color */ |
69 | | gx_restrict_ICC, /* restrict_color */ |
70 | | gx_same_concrete_space, /* concrete_space */ |
71 | | gx_concretize_ICC, /* concreteize_color */ |
72 | | gx_remap_concrete_ICC, /* remap_concrete_color */ |
73 | | gx_remap_ICC, /* remap_color */ |
74 | | gx_install_ICC, /* install_cpsace */ |
75 | | gx_set_overprint_ICC, /* set_overprint */ |
76 | | gx_final_ICC, /* final */ |
77 | | gx_no_adjust_color_count, /* adjust_color_count */ |
78 | | gx_serialize_ICC, /* serialize */ |
79 | | gx_cspace_is_linear_ICC, |
80 | | gx_polarity_ICC |
81 | | }; |
82 | | |
83 | | static inline void |
84 | | gsicc_remap_fast(gx_device *dev, unsigned short *psrc, unsigned short *psrc_cm, |
85 | | gsicc_link_t *icc_link) |
86 | 233M | { |
87 | 233M | (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_cm, 2); |
88 | 233M | } |
89 | | |
90 | | /* ICC color mapping linearity check, a 2-points case. Check only the 1/2 point */ |
91 | | static int |
92 | | gx_icc_is_linear_in_line(const gs_color_space *cs, const gs_gstate * pgs, |
93 | | gx_device *dev, |
94 | | const gs_client_color *c0, const gs_client_color *c1, |
95 | | float smoothness, gsicc_link_t *icclink) |
96 | 22.2M | { |
97 | 22.2M | int nsrc = cs->type->num_components(cs); |
98 | 22.2M | cmm_dev_profile_t *dev_profile; |
99 | 22.2M | int ndes; |
100 | 22.2M | int code; |
101 | 22.2M | unsigned short src0[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
102 | 22.2M | unsigned short src1[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
103 | 22.2M | unsigned short src01[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
104 | 22.2M | unsigned short des0[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
105 | 22.2M | unsigned short des1[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
106 | 22.2M | unsigned short des01[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
107 | 22.2M | unsigned short interp_des; |
108 | 22.2M | unsigned short max_diff = (unsigned short) max(1, 65535 * smoothness); |
109 | 22.2M | int k; |
110 | | |
111 | 22.2M | code = dev_proc(dev, get_profile)(dev, &(dev_profile)); |
112 | 22.2M | if (code < 0) |
113 | 0 | return code; |
114 | 22.2M | ndes = gsicc_get_device_profile_comps(dev_profile); |
115 | | |
116 | | /* Get us to ushort and get mid point */ |
117 | 107M | for (k = 0; k < nsrc; k++) { |
118 | 85.0M | src0[k] = (unsigned short) (c0->paint.values[k]*65535); |
119 | 85.0M | src1[k] = (unsigned short) (c1->paint.values[k]*65535); |
120 | 85.0M | src01[k] = ((unsigned int) src0[k] + (unsigned int) src1[k]) >> 1; |
121 | 85.0M | } |
122 | | /* Transform the end points and the interpolated point */ |
123 | 22.2M | gsicc_remap_fast(dev, &(src0[0]), &(des0[0]), icclink); |
124 | 22.2M | gsicc_remap_fast(dev, &(src1[0]), &(des1[0]), icclink); |
125 | 22.2M | gsicc_remap_fast(dev, &(src01[0]), &(des01[0]), icclink); |
126 | | /* Interpolate 1/2 value in des space and compare */ |
127 | 72.7M | for (k = 0; k < ndes; k++) { |
128 | 50.6M | interp_des = (des0[k] + des1[k]) >> 1; |
129 | 50.6M | if (any_abs((signed int) interp_des - (signed int) des01[k]) > max_diff) |
130 | 137k | return false; |
131 | 50.6M | } |
132 | 22.1M | return 1; |
133 | 22.2M | } |
134 | | |
135 | | /* Default icc color mapping linearity check, a triangle case. */ |
136 | | static int |
137 | | gx_icc_is_linear_in_triangle(const gs_color_space *cs, const gs_gstate * pgs, |
138 | | gx_device *dev, |
139 | | const gs_client_color *c0, const gs_client_color *c1, |
140 | | const gs_client_color *c2, float smoothness, gsicc_link_t *icclink) |
141 | 23.7M | { |
142 | | /* Check 4 points middle points of 3 sides and middle of one side with |
143 | | other point. We avoid divisions this way. */ |
144 | 23.7M | unsigned short src0[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
145 | 23.7M | unsigned short src1[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
146 | 23.7M | unsigned short src2[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
147 | 23.7M | unsigned short des0[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
148 | 23.7M | unsigned short des1[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
149 | 23.7M | unsigned short des2[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
150 | 23.7M | unsigned short src01[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
151 | 23.7M | unsigned short src12[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
152 | 23.7M | unsigned short src02[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
153 | 23.7M | unsigned short src012[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
154 | 23.7M | unsigned short des01[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
155 | 23.7M | unsigned short des12[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
156 | 23.7M | unsigned short des02[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
157 | 23.7M | unsigned short des012[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
158 | 23.7M | int nsrc = cs->type->num_components(cs); |
159 | 23.7M | int ndes, code; |
160 | 23.7M | unsigned short max_diff = (unsigned short) max(1, 65535 * smoothness); |
161 | 23.7M | unsigned int interp_des; |
162 | 23.7M | int k; |
163 | 23.7M | cmm_dev_profile_t *dev_profile; |
164 | | |
165 | 23.7M | code = dev_proc(dev, get_profile)(dev, &(dev_profile)); |
166 | 23.7M | if (code < 0) |
167 | 0 | return code; |
168 | 23.7M | ndes = gsicc_get_device_profile_comps(dev_profile); |
169 | | |
170 | | /* This needs to be optimized. And range corrected */ |
171 | 113M | for (k = 0; k < nsrc; k++){ |
172 | 90.1M | src0[k] = (unsigned short) (c0->paint.values[k]*65535); |
173 | 90.1M | src1[k] = (unsigned short) (c1->paint.values[k]*65535); |
174 | 90.1M | src2[k] = (unsigned short) (c2->paint.values[k]*65535); |
175 | 90.1M | src01[k] = (src0[k] + src1[k]) >> 1; |
176 | 90.1M | src02[k] = (src0[k] + src2[k]) >> 1; |
177 | 90.1M | src12[k] = (src1[k] + src2[k]) >> 1; |
178 | 90.1M | src012[k] = (src12[k] + src0[k]) >> 1; |
179 | 90.1M | } |
180 | | /* Map the points */ |
181 | 23.7M | gsicc_remap_fast(dev, &(src0[0]), &(des0[0]), icclink); |
182 | 23.7M | gsicc_remap_fast(dev, &(src1[0]), &(des1[0]), icclink); |
183 | 23.7M | gsicc_remap_fast(dev, &(src2[0]), &(des2[0]), icclink); |
184 | 23.7M | gsicc_remap_fast(dev, &(src01[0]), &(des01[0]), icclink); |
185 | 23.7M | gsicc_remap_fast(dev, &(src12[0]), &(des12[0]), icclink); |
186 | 23.7M | gsicc_remap_fast(dev, &(src02[0]), &(des02[0]), icclink); |
187 | 23.7M | gsicc_remap_fast(dev, &(src012[0]), &(des012[0]), icclink); |
188 | | /* Interpolate in des space and check it */ |
189 | 80.2M | for (k = 0; k < ndes; k++){ |
190 | 56.5M | interp_des = (des0[k] + des1[k]) >> 1; |
191 | 56.5M | if (any_abs((signed int) interp_des - (signed int) des01[k]) > max_diff) |
192 | 70.5k | return false; |
193 | 56.4M | interp_des = (des0[k] + des2[k]) >> 1; |
194 | 56.4M | if (any_abs((signed int) interp_des - (signed int) des02[k]) > max_diff) |
195 | 53.8k | return false; |
196 | 56.4M | interp_des = (des1[k] + des2[k]) >> 1; |
197 | 56.4M | if (any_abs((signed int) interp_des - (signed int) des12[k]) > max_diff) |
198 | 1.31k | return false; |
199 | | /* 12 with 0 */ |
200 | 56.4M | interp_des = (des0[k] + interp_des) >> 1; |
201 | 56.4M | if (any_abs((signed int) interp_des - (signed int) des012[k]) > max_diff) |
202 | 1.25k | return false; |
203 | 56.4M | } |
204 | 23.6M | return 1; |
205 | 23.7M | } |
206 | | |
207 | | /* ICC color mapping linearity check. */ |
208 | | int |
209 | | gx_cspace_is_linear_ICC(const gs_color_space *cs, const gs_gstate * pgs, |
210 | | gx_device *dev, |
211 | | const gs_client_color *c0, const gs_client_color *c1, |
212 | | const gs_client_color *c2, const gs_client_color *c3, |
213 | | float smoothness, gsicc_link_t *icclink) |
214 | 52.4M | { |
215 | | /* Assuming 2 <= nc <= 4. We don't need other cases. */ |
216 | | /* With nc == 4 assuming a convex plain quadrangle in the client color space. */ |
217 | 52.4M | int code; |
218 | | |
219 | | /* Do a quick check if we are in a halftone situation. If yes, |
220 | | then we should not be doing this linear check */ |
221 | 52.4M | if (gx_device_must_halftone(dev)) return 0; |
222 | 52.4M | if (icclink->is_identity) return 1; /* Transform is identity, linear! */ |
223 | | |
224 | 46.0M | if (!colors_are_separable_and_linear(&dev->color_info)) |
225 | 0 | return_error(gs_error_rangecheck); |
226 | 46.0M | if (c2 == NULL) |
227 | 22.2M | return gx_icc_is_linear_in_line(cs, pgs, dev, c0, c1, smoothness, icclink); |
228 | 23.7M | code = gx_icc_is_linear_in_triangle(cs, pgs, dev, c0, c1, c2, |
229 | 23.7M | smoothness, icclink); |
230 | 23.7M | if (code <= 0) |
231 | 126k | return code; |
232 | 23.6M | if (c3 == NULL) |
233 | 23.6M | return 1; |
234 | 0 | return gx_icc_is_linear_in_triangle(cs, pgs, dev, c1, c2, c3, |
235 | 0 | smoothness, icclink); |
236 | 23.6M | } |
237 | | /* |
238 | | * Return the number of components used by a ICCBased color space - 1, 3, or 4 |
239 | | */ |
240 | | static int |
241 | | gx_num_components_ICC(const gs_color_space * pcs) |
242 | 114M | { |
243 | 114M | return pcs->cmm_icc_profile_data->num_comps; |
244 | 114M | } |
245 | | |
246 | | /* Get the polarity of the ICC Based space */ |
247 | | static gx_color_polarity_t |
248 | | gx_polarity_ICC(const gs_color_space * pcs) |
249 | 2 | { |
250 | 2 | switch (pcs->cmm_icc_profile_data->data_cs) { |
251 | 0 | case gsUNDEFINED: |
252 | 0 | case gsNAMED: |
253 | 0 | return GX_CINFO_POLARITY_UNKNOWN; |
254 | 0 | case gsGRAY: |
255 | 2 | case gsRGB: |
256 | 2 | case gsCIELAB: |
257 | 2 | case gsCIEXYZ: |
258 | 2 | return GX_CINFO_POLARITY_ADDITIVE; |
259 | 0 | case gsCMYK: |
260 | 0 | case gsNCHANNEL: |
261 | 0 | return GX_CINFO_POLARITY_SUBTRACTIVE; |
262 | 0 | default: |
263 | 0 | return GX_CINFO_POLARITY_UNKNOWN; |
264 | 2 | } |
265 | 2 | } |
266 | | |
267 | | /* |
268 | | * Set the initial client color for an ICCBased color space. The convention |
269 | | * suggested by the ICC specification is to set all components to 0. |
270 | | */ |
271 | | static void |
272 | | gx_init_ICC(gs_client_color * pcc, const gs_color_space * pcs) |
273 | 24.0M | { |
274 | 24.0M | int i, ncomps = pcs->cmm_icc_profile_data->num_comps; |
275 | | |
276 | 60.7M | for (i = 0; i < ncomps; ++i) |
277 | 36.6M | pcc->paint.values[i] = 0.0; |
278 | | |
279 | | /* make sure that [ 0, ... 0] is in range */ |
280 | 24.0M | gx_restrict_ICC(pcc, pcs); |
281 | 24.0M | } |
282 | | |
283 | | /* |
284 | | * Restrict an color to the range specified for an ICCBased color space. |
285 | | */ |
286 | | static void |
287 | | gx_restrict_ICC(gs_client_color * pcc, const gs_color_space * pcs) |
288 | 143M | { |
289 | 143M | int i, ncomps = pcs->cmm_icc_profile_data->num_comps; |
290 | 143M | const gs_range * ranges = pcs->cmm_icc_profile_data->Range.ranges; |
291 | | |
292 | 533M | for (i = 0; i < ncomps; ++i) { |
293 | 390M | double v = pcc->paint.values[i]; |
294 | 390M | double rmin = ranges[i].rmin, rmax = ranges[i].rmax; |
295 | | |
296 | 390M | if (v < rmin) |
297 | 842k | pcc->paint.values[i] = rmin; |
298 | 389M | else if (v > rmax) |
299 | 5.47M | pcc->paint.values[i] = rmax; |
300 | 390M | } |
301 | 143M | } |
302 | | |
303 | | static int |
304 | | gx_remap_concrete_icc_devicen(const gs_color_space * pcs, const frac * pconc, |
305 | | gx_device_color * pdc, const gs_gstate * pgs, |
306 | | gx_device * dev, gs_color_select_t select, |
307 | | const cmm_dev_profile_t *dev_profile) |
308 | 0 | { |
309 | | /* Check if this is a device with a DeviceN ICC profile. In this case, |
310 | | we need to do some special stuff */ |
311 | 0 | int code = 0; |
312 | |
|
313 | 0 | if (dev_profile->spotnames != NULL && |
314 | 0 | !dev_profile->spotnames->equiv_cmyk_set) { |
315 | | /* This means that someone has specified a DeviceN (Ncolor) |
316 | | ICC destination profile for this device and we still need to set |
317 | | up the equivalent CMYK colors for the spot colors that are present. |
318 | | This allows us to have some sort of composite viewing of the spot |
319 | | colors as they would colorimetrically appear. */ |
320 | 0 | code = gsicc_set_devicen_equiv_colors(dev, pgs, |
321 | 0 | dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE]); |
322 | 0 | dev_profile->spotnames->equiv_cmyk_set = true; |
323 | 0 | } |
324 | 0 | gx_remap_concrete_devicen(pconc, pdc, pgs, dev, select, pcs); |
325 | 0 | return code; |
326 | 0 | } |
327 | | |
328 | | /* If the color is already concretized, then we are in the color space |
329 | | defined by the device profile. The remaining things to do would |
330 | | be to potentially apply alpha, apply the transfer function, and |
331 | | do any halftoning. The remap is based upon the ICC profile defined |
332 | | in the device profile entry of the profile manager. */ |
333 | | int |
334 | | gx_remap_concrete_ICC(const gs_color_space * pcs, const frac * pconc, |
335 | | gx_device_color * pdc, const gs_gstate * pgs, |
336 | | gx_device * dev, gs_color_select_t select, |
337 | | const cmm_dev_profile_t *dev_profile) |
338 | 508M | { |
339 | 508M | switch (gsicc_get_device_profile_comps(dev_profile)) { |
340 | 48.5M | case 1: |
341 | 48.5M | return gx_remap_concrete_DGray(pcs, pconc, pdc, pgs, dev, select, dev_profile); |
342 | 376M | case 3: |
343 | 376M | return gx_remap_concrete_DRGB(pcs, pconc, pdc, pgs, dev, select, dev_profile); |
344 | 82.8M | case 4: |
345 | 82.8M | return gx_remap_concrete_DCMYK(pcs, pconc, pdc, pgs, dev, select, dev_profile); |
346 | 0 | default: |
347 | | /* This is a special case where we have a source color and our |
348 | | output profile must be DeviceN. We will need to map our |
349 | | colorants to the proper planes */ |
350 | 0 | return gx_remap_concrete_icc_devicen(pcs, pconc, pdc, pgs, dev, select, dev_profile); |
351 | 508M | } |
352 | 508M | } |
353 | | |
354 | | /* |
355 | | * To device space |
356 | | */ |
357 | | int |
358 | | gx_remap_ICC_with_link(const gs_client_color * pcc, const gs_color_space * pcs, |
359 | | gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev, |
360 | | gs_color_select_t select, gsicc_link_t *icc_link) |
361 | 461M | { |
362 | 461M | cmm_dev_profile_t *dev_profile; |
363 | 461M | unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS], psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
364 | 461M | unsigned short *psrc_temp; |
365 | 461M | frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
366 | 461M | int k,i; |
367 | | #ifdef DEBUG |
368 | | int num_src_comps; |
369 | | #endif |
370 | 461M | int num_des_comps; |
371 | 461M | int code; |
372 | | |
373 | 461M | code = dev_proc(dev, get_profile)(dev, &dev_profile); |
374 | 461M | if (code < 0) |
375 | 0 | return code; |
376 | 461M | if (dev_profile == NULL) |
377 | 0 | return gs_throw(gs_error_Fatal, "Attempting to do ICC remap with no profile"); |
378 | 461M | if (icc_link == NULL) |
379 | 0 | return gs_throw(gs_error_Fatal, "Attempting to do ICC remap with no link"); |
380 | | |
381 | | /* Need to clear out psrc_cm in case we have separation bands that are |
382 | | not color managed */ |
383 | 461M | memset(psrc_cm,0,sizeof(unsigned short)*GS_CLIENT_COLOR_MAX_COMPONENTS); |
384 | | |
385 | | /* This needs to be optimized */ |
386 | 461M | if (pcs->cmm_icc_profile_data->data_cs == gsCIELAB || |
387 | 461M | pcs->cmm_icc_profile_data->islab) { |
388 | 444 | psrc[0] = (unsigned short) (pcc->paint.values[0]*65535.0/100.0); |
389 | 444 | psrc[1] = (unsigned short) ((pcc->paint.values[1]+128)/255.0*65535.0); |
390 | 444 | psrc[2] = (unsigned short) ((pcc->paint.values[2]+128)/255.0*65535.0); |
391 | 461M | } else { |
392 | 1.85G | for (k = 0; k < pcs->cmm_icc_profile_data->num_comps; k++){ |
393 | 1.39G | psrc[k] = (unsigned short) (pcc->paint.values[k]*65535.0); |
394 | 1.39G | } |
395 | 461M | } |
396 | 461M | num_des_comps = gsicc_get_device_profile_comps(dev_profile); |
397 | 461M | if (icc_link->is_identity) { |
398 | 331M | psrc_temp = &(psrc[0]); |
399 | 331M | } else { |
400 | | /* Transform the color */ |
401 | 129M | psrc_temp = &(psrc_cm[0]); |
402 | 129M | (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2); |
403 | 129M | } |
404 | | #ifdef DEBUG |
405 | | if (!icc_link->is_identity) { |
406 | | num_src_comps = pcs->cmm_icc_profile_data->num_comps; |
407 | | if_debug0m(gs_debug_flag_icc, dev->memory, "[icc] remap [ "); |
408 | | for (k = 0; k < num_src_comps; k++) { |
409 | | if_debug1m(gs_debug_flag_icc, dev->memory, "%d ", psrc[k]); |
410 | | } |
411 | | if_debug0m(gs_debug_flag_icc, dev->memory, "] --> [ "); |
412 | | for (k = 0; k < num_des_comps; k++) { |
413 | | if_debug1m(gs_debug_flag_icc, dev->memory, "%d ", psrc_temp[k]); |
414 | | } |
415 | | if_debug0m(gs_debug_flag_icc, dev->memory, "]\n"); |
416 | | } else { |
417 | | num_src_comps = pcs->cmm_icc_profile_data->num_comps; |
418 | | if_debug0m(gs_debug_flag_icc, dev->memory, "[icc] Identity mapping\n"); |
419 | | if_debug0m(gs_debug_flag_icc, dev->memory, "[icc] [ "); |
420 | | for (k = 0; k < num_src_comps; k++) { |
421 | | if_debug1m(gs_debug_flag_icc, dev->memory, "%d ", psrc[k]); |
422 | | } |
423 | | if_debug0m(gs_debug_flag_icc, dev->memory, "]\n"); |
424 | | } |
425 | | #endif |
426 | | /* Now do the remap for ICC which amounts to the alpha application |
427 | | the transfer function and potentially the halftoning */ |
428 | | /* Right now we need to go from unsigned short to frac. I really |
429 | | would like to avoid this sort of stuff. That will come. */ |
430 | 1.83G | for (k = 0; k < num_des_comps; k++){ |
431 | 1.37G | conc[k] = ushort2frac(psrc_temp[k]); |
432 | 1.37G | } |
433 | | /* In case there are extra components beyond the ICC ones */ |
434 | 464M | for (k = num_des_comps; k < dev->color_info.num_components; k++) { |
435 | 2.65M | conc[k] = 0; |
436 | 2.65M | } |
437 | 461M | gx_remap_concrete_ICC(pcs, conc, pdc, pgs, dev, select, dev_profile); |
438 | | |
439 | | /* Save original color space and color info into dev color */ |
440 | 461M | i = pcs->cmm_icc_profile_data->num_comps; |
441 | 1.85G | for (i--; i >= 0; i--) |
442 | 1.39G | pdc->ccolor.paint.values[i] = pcc->paint.values[i]; |
443 | 461M | pdc->ccolor_valid = true; |
444 | 461M | return 0; |
445 | 461M | } |
446 | | |
447 | | int |
448 | | gx_remap_ICC(const gs_client_color * pcc, const gs_color_space * pcs, |
449 | | gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev, |
450 | | gs_color_select_t select) |
451 | 187M | { |
452 | 187M | gsicc_link_t *icc_link; |
453 | 187M | gsicc_rendering_param_t rendering_params; |
454 | 187M | cmm_dev_profile_t *dev_profile; |
455 | 187M | int code; |
456 | | |
457 | 187M | color_replace_t param; |
458 | 187M | param.pcc = pcc; |
459 | 187M | param.pcs = pcs; |
460 | 187M | param.pdc = pdc; |
461 | 187M | param.pgs = pgs; |
462 | 187M | param.pdf14_iccprofile = NULL; |
463 | | |
464 | | /* Try color replacement. If successful (>0) then no |
465 | | ICC color management for this color. */ |
466 | 187M | if (dev_proc(pgs->device, dev_spec_op)(pgs->device, |
467 | 187M | gxdso_replacecolor, ¶m, sizeof(color_replace_t)) > 0) |
468 | 0 | return 0; |
469 | | |
470 | 187M | code = dev_proc(dev, get_profile)(dev, &dev_profile); |
471 | 187M | if (code < 0) |
472 | 0 | return code; |
473 | 187M | if (dev_profile == NULL) |
474 | 0 | return gs_throw(gs_error_Fatal, "Attempting to do ICC remap with no profile"); |
475 | | |
476 | 187M | rendering_params.black_point_comp = pgs->blackptcomp; |
477 | 187M | rendering_params.graphics_type_tag = dev->graphics_type_tag; |
478 | 187M | rendering_params.override_icc = false; |
479 | 187M | rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; |
480 | 187M | rendering_params.rendering_intent = pgs->renderingintent; |
481 | 187M | rendering_params.cmm = gsCMM_DEFAULT; |
482 | | /* Get a link from the cache, or create if it is not there. Need to get 16 bit profile */ |
483 | 187M | icc_link = gsicc_get_link(pgs, dev, pcs, NULL, &rendering_params, pgs->memory); |
484 | 187M | if (icc_link == NULL) { |
485 | | #ifdef DEBUG |
486 | | gs_warn("Could not create ICC link: Check profiles"); |
487 | | #endif |
488 | 140k | return_error(gs_error_unknownerror); |
489 | 140k | } |
490 | | |
491 | 187M | code = gx_remap_ICC_with_link(pcc, pcs, pdc, pgs, dev, select, icc_link); |
492 | | /* Release the link */ |
493 | 187M | gsicc_release_link(icc_link); |
494 | 187M | return code; |
495 | 187M | } |
496 | | |
497 | | /* |
498 | | * Same as above, but there is no rescale of CIELAB colors. This is needed |
499 | | since the rescale is not needed when the source data is image based. |
500 | | The DeviceN image rendering case uses the remap proc vs. the ICC based method |
501 | | which handles the remapping itself. |
502 | | */ |
503 | | int |
504 | | gx_remap_ICC_imagelab(const gs_client_color * pcc, const gs_color_space * pcs, |
505 | | gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev, |
506 | | gs_color_select_t select) |
507 | 0 | { |
508 | 0 | gsicc_link_t *icc_link; |
509 | 0 | gsicc_rendering_param_t rendering_params; |
510 | 0 | unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS], psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
511 | 0 | unsigned short *psrc_temp; |
512 | 0 | frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
513 | 0 | int k,i; |
514 | 0 | int num_des_comps; |
515 | 0 | int code; |
516 | 0 | cmm_dev_profile_t *dev_profile; |
517 | |
|
518 | 0 | code = dev_proc(dev, get_profile)(dev, &dev_profile); |
519 | 0 | if (code < 0) |
520 | 0 | return code; |
521 | 0 | num_des_comps = gsicc_get_device_profile_comps(dev_profile); |
522 | 0 | rendering_params.black_point_comp = pgs->blackptcomp; |
523 | 0 | rendering_params.graphics_type_tag = dev->graphics_type_tag; |
524 | 0 | rendering_params.override_icc = false; |
525 | 0 | rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; |
526 | 0 | rendering_params.rendering_intent = pgs->renderingintent; |
527 | 0 | rendering_params.cmm = gsCMM_DEFAULT; |
528 | | /* Need to clear out psrc_cm in case we have separation bands that are |
529 | | not color managed */ |
530 | 0 | memset(psrc_cm, 0, sizeof(unsigned short)*GS_CLIENT_COLOR_MAX_COMPONENTS); |
531 | |
|
532 | 0 | for (k = 0; k < pcs->cmm_icc_profile_data->num_comps; k++) |
533 | 0 | psrc[k] = (unsigned short) (pcc->paint.values[k]*65535.0); |
534 | | |
535 | | /* Get a link from the cache, or create if it is not there. Need to get 16 bit profile */ |
536 | 0 | icc_link = gsicc_get_link(pgs, dev, pcs, NULL, &rendering_params, pgs->memory); |
537 | 0 | if (icc_link == NULL) { |
538 | | #ifdef DEBUG |
539 | | gs_warn("Could not create ICC link: Check profiles"); |
540 | | #endif |
541 | 0 | return_error(gs_error_unknownerror); |
542 | 0 | } |
543 | 0 | if (icc_link->is_identity) { |
544 | 0 | psrc_temp = &(psrc[0]); |
545 | 0 | } else { |
546 | | /* Transform the color */ |
547 | 0 | psrc_temp = &(psrc_cm[0]); |
548 | 0 | (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2); |
549 | 0 | } |
550 | | /* Release the link */ |
551 | 0 | gsicc_release_link(icc_link); |
552 | | /* Now do the remap for ICC which amounts to the alpha application |
553 | | the transfer function and potentially the halftoning */ |
554 | | /* Right now we need to go from unsigned short to frac. I really |
555 | | would like to avoid this sort of stuff. That will come. */ |
556 | 0 | for (k = 0; k < num_des_comps; k++){ |
557 | 0 | conc[k] = ushort2frac(psrc_temp[k]); |
558 | 0 | } |
559 | | /* We have to worry about extra colorants in the device. */ |
560 | 0 | for (k = num_des_comps; k < dev->color_info.num_components; k++) { |
561 | 0 | conc[k] = 0; |
562 | 0 | } |
563 | 0 | gx_remap_concrete_ICC(pcs, conc, pdc, pgs, dev, select, dev_profile); |
564 | | |
565 | | /* Save original color space and color info into dev color */ |
566 | 0 | i = pcs->cmm_icc_profile_data->num_comps; |
567 | 0 | for (i--; i >= 0; i--) |
568 | 0 | pdc->ccolor.paint.values[i] = pcc->paint.values[i]; |
569 | 0 | pdc->ccolor_valid = true; |
570 | 0 | return 0; |
571 | 0 | } |
572 | | |
573 | | /* Convert an ICCBased color space to a concrete color space. */ |
574 | | |
575 | | static int |
576 | | gx_concretize_ICC( |
577 | | const gs_client_color * pcc, |
578 | | const gs_color_space * pcs, |
579 | | frac * pconc, |
580 | | const gs_gstate * pgs, |
581 | | gx_device *dev) |
582 | 46.7M | { |
583 | | |
584 | 46.7M | gsicc_link_t *icc_link; |
585 | 46.7M | gsicc_rendering_param_t rendering_params; |
586 | 46.7M | unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS], psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
587 | 46.7M | int k; |
588 | 46.7M | unsigned short *psrc_temp; |
589 | 46.7M | int num_des_comps; |
590 | 46.7M | int code; |
591 | 46.7M | cmm_dev_profile_t *dev_profile; |
592 | | |
593 | 46.7M | code = dev_proc(dev, get_profile)(dev, &dev_profile); |
594 | 46.7M | if (code < 0) |
595 | 0 | return code; |
596 | 46.7M | num_des_comps = gsicc_get_device_profile_comps(dev_profile); |
597 | | /* Define the rendering intents. */ |
598 | 46.7M | rendering_params.black_point_comp = pgs->blackptcomp; |
599 | 46.7M | rendering_params.graphics_type_tag = dev->graphics_type_tag; |
600 | 46.7M | rendering_params.override_icc = false; |
601 | 46.7M | rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; |
602 | 46.7M | rendering_params.rendering_intent = pgs->renderingintent; |
603 | 46.7M | rendering_params.cmm = gsCMM_DEFAULT; |
604 | 187M | for (k = 0; k < pcs->cmm_icc_profile_data->num_comps; k++) { |
605 | 141M | psrc[k] = (unsigned short) (pcc->paint.values[k]*65535.0); |
606 | 141M | } |
607 | | /* Get a link from the cache, or create if it is not there. Get 16 bit profile */ |
608 | 46.7M | icc_link = gsicc_get_link(pgs, dev, pcs, NULL, &rendering_params, pgs->memory); |
609 | 46.7M | if (icc_link == NULL) { |
610 | | #ifdef DEBUG |
611 | | gs_warn("Could not create ICC link: Check profiles"); |
612 | | #endif |
613 | 5.80k | return_error(gs_error_unknownerror); |
614 | 5.80k | } |
615 | | /* Transform the color */ |
616 | 46.7M | if (icc_link->is_identity) { |
617 | 4.20M | psrc_temp = &(psrc[0]); |
618 | 42.5M | } else { |
619 | | /* Transform the color */ |
620 | 42.5M | psrc_temp = &(psrc_cm[0]); |
621 | 42.5M | (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2); |
622 | 42.5M | } |
623 | | /* This needs to be optimized */ |
624 | 184M | for (k = 0; k < num_des_comps; k++) { |
625 | 138M | pconc[k] = float2frac(((float) psrc_temp[k])/65535.0); |
626 | 138M | } |
627 | | /* We have to worry about extra colorants in the device. */ |
628 | 46.7M | for (k = num_des_comps; k < dev->color_info.num_components; k++) { |
629 | 483 | pconc[k] = 0; |
630 | 483 | } |
631 | | |
632 | | /* Release the link */ |
633 | 46.7M | gsicc_release_link(icc_link); |
634 | 46.7M | return 0; |
635 | 46.7M | } |
636 | | |
637 | | /* |
638 | | * Finalize the contents of an ICC color space. Now that color space |
639 | | * objects have straightforward reference counting discipline, there's |
640 | | * nothing special about it. In the previous state of affairs, the |
641 | | * argument in favor of correct reference counting spoke of "an |
642 | | * unintuitive but otherwise legitimate state of affairs". |
643 | | */ |
644 | | static void |
645 | | gx_final_ICC(gs_color_space * pcs) |
646 | 19.4M | { |
647 | 19.4M | if (pcs->cmm_icc_profile_data != NULL) { |
648 | 19.4M | gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, -1, "gx_final_ICC"); |
649 | 19.4M | pcs->cmm_icc_profile_data = NULL; |
650 | 19.4M | } |
651 | 19.4M | } |
652 | | |
653 | | /* |
654 | | * Install an ICCBased color space. |
655 | | * |
656 | | * Note that an ICCBased color space must be installed before it is known if |
657 | | * the ICC profile or the alternate color space is to be used. |
658 | | */ |
659 | | static int |
660 | | gx_install_ICC(gs_color_space * pcs, gs_gstate * pgs) |
661 | 2.62M | { |
662 | | /* update the stub information used by the joint caches */ |
663 | 2.62M | return 0; |
664 | 2.62M | } |
665 | | |
666 | | /* |
667 | | * Constructor for ICCBased color space. As with the other color space |
668 | | * constructors, this provides only minimal initialization. |
669 | | */ |
670 | | int |
671 | | gs_cspace_build_ICC( |
672 | | gs_color_space ** ppcspace, |
673 | | void * client_data, |
674 | | gs_memory_t * pmem ) |
675 | 1.84M | { |
676 | 1.84M | gs_color_space *pcspace = gs_cspace_alloc(pmem, &gs_color_space_type_ICC); |
677 | 1.84M | if (!pcspace) { |
678 | 0 | return_error(gs_error_VMerror); |
679 | 0 | } |
680 | 1.84M | *ppcspace = pcspace; |
681 | | |
682 | 1.84M | return 0; |
683 | 1.84M | } |
684 | | |
685 | | /* ---------------- Serialization. -------------------------------- */ |
686 | | |
687 | | static int |
688 | | gx_serialize_ICC(const gs_color_space * pcs, stream * s) |
689 | 71.8k | { |
690 | 71.8k | gsicc_serialized_profile_t *profile__serial; |
691 | 71.8k | uint n; |
692 | 71.8k | int code = gx_serialize_cspace_type(pcs, s); |
693 | | |
694 | 71.8k | if (code < 0) |
695 | 0 | return code; |
696 | 71.8k | profile__serial = (gsicc_serialized_profile_t*) pcs->cmm_icc_profile_data; |
697 | 71.8k | code = sputs(s, (byte *)profile__serial, GSICC_SERIALIZED_SIZE, &n); |
698 | 71.8k | return(code); |
699 | 71.8k | } |
700 | | |
701 | | /* Overprint. Here we may have either spot colors or CMYK colors. */ |
702 | | static int |
703 | | gx_set_overprint_ICC(const gs_color_space * pcs, gs_gstate * pgs) |
704 | 624k | { |
705 | 624k | gx_device *dev = pgs->device; |
706 | 624k | gx_device_color_info *pcinfo = (dev == 0 ? 0 : &dev->color_info); |
707 | 624k | bool cs_ok; |
708 | 624k | cmm_dev_profile_t *dev_profile; |
709 | 624k | bool gray_to_k; |
710 | 624k | bool op = pgs->is_fill_color ? pgs->overprint : pgs->stroke_overprint; |
711 | | |
712 | 624k | if (dev == 0 || pcinfo == NULL || !op || |
713 | 624k | gx_get_opmsupported(dev) == GX_CINFO_OPMSUPPORTED_NOT) |
714 | 620k | return gx_set_no_overprint(pgs); |
715 | | |
716 | 4.17k | dev_proc(dev, get_profile)(dev, &dev_profile); |
717 | 4.17k | gray_to_k = dev_profile->devicegraytok; |
718 | | |
719 | | /* Possibly do CMYK based overprinting if profile is CMYK based or if we |
720 | | are gray source based and doing gray to k mapping |
721 | | (Ghent GWG 3.0 Gray Overprint Patch (030_Gray_K_black_OP_x1a.pdf) */ |
722 | 4.17k | if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) |
723 | 0 | cs_ok = (pcs->cmm_icc_profile_data->data_cs == gsRGB); |
724 | 4.17k | else |
725 | 4.17k | cs_ok = ((pcs->cmm_icc_profile_data->data_cs == gsCMYK) || |
726 | 4.17k | (pcs->cmm_icc_profile_data->data_cs == gsGRAY && gray_to_k)); |
727 | | |
728 | 4.17k | if_debug4m(gs_debug_flag_overprint, pgs->memory, |
729 | 4.17k | "[overprint] gx_set_overprint_ICC. cs_ok = %d is_fill_color = %d overprint = %d stroke_overprint = %d \n", |
730 | 4.17k | cs_ok, pgs->is_fill_color, pgs->overprint, pgs->stroke_overprint); |
731 | | |
732 | 4.17k | if (cs_ok) |
733 | 1.50k | { |
734 | 1.50k | if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) |
735 | 0 | return gx_set_overprint_rgb(pcs, pgs); |
736 | 1.50k | else |
737 | 1.50k | return gx_set_overprint_cmyk(pcs, pgs); |
738 | 1.50k | } |
739 | | |
740 | | /* In this case, we still need to maintain any spot |
741 | | colorant channels. Per Table 7.14. */ |
742 | 2.66k | if (dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0)) |
743 | 2.65k | return gx_set_spot_only_overprint(pgs); |
744 | | |
745 | 8 | return gx_set_no_overprint(pgs); |
746 | 2.66k | } |
747 | | |
748 | | int |
749 | | gx_default_get_profile(const gx_device *dev, cmm_dev_profile_t **profile) |
750 | 1.71G | { |
751 | 1.71G | *profile = dev->icc_struct; |
752 | 1.71G | return 0; |
753 | 1.71G | } |
754 | | |
755 | | /* Adjust the color model of the device to match that of the profile. Used by |
756 | | vector based devices and the tiff scaled devices. Only valid for bit depths |
757 | | of 8n/component. Note the caller likely will need to update its procs */ |
758 | | int |
759 | | gx_change_color_model(gx_device *dev, int num_comps, int bit_depth) |
760 | 0 | { |
761 | 0 | int k; |
762 | |
|
763 | 0 | if (!((num_comps == 1) || (num_comps == 3) || (num_comps == 4))) |
764 | 0 | return_error(gs_error_unknownerror); |
765 | | |
766 | 0 | dev->color_info.max_components = num_comps; |
767 | 0 | dev->color_info.num_components = num_comps; |
768 | 0 | dev->color_info.depth = num_comps * bit_depth; |
769 | |
|
770 | 0 | if (num_comps == 4) { |
771 | 0 | dev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; |
772 | 0 | } else { |
773 | 0 | dev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE; |
774 | 0 | } |
775 | |
|
776 | 0 | for (k = 0; k < num_comps; k++) { |
777 | 0 | dev->color_info.comp_shift[k] = bit_depth * (3 - k); |
778 | 0 | dev->color_info.comp_bits[k] = bit_depth; |
779 | 0 | dev->color_info.comp_mask[k] = |
780 | 0 | ((gx_color_index)255) << dev->color_info.comp_shift[k]; |
781 | 0 | } |
782 | |
|
783 | 0 | return 0; |
784 | 0 | } |