/src/ghostpdl/base/gsequivc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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 | | /* Routines for determining equivalent color for spot colors */ |
18 | | |
19 | | #include "math_.h" |
20 | | #include "gdevprn.h" |
21 | | #include "gsparam.h" |
22 | | #include "gstypes.h" |
23 | | #include "gxdcconv.h" |
24 | | #include "gdevdevn.h" |
25 | | #include "gsequivc.h" |
26 | | #include "gzstate.h" |
27 | | #include "gsstate.h" |
28 | | #include "gscspace.h" |
29 | | #include "gxcspace.h" |
30 | | #include "gsicc_manage.h" |
31 | | #include "gxdevsop.h" |
32 | | |
33 | | /* |
34 | | * These routines are part of the logic for determining an equivalent |
35 | | * process color model color for a spot color. The definition of a |
36 | | * Separation or DeviceN color space include a tint transform function. |
37 | | * This tint transform function is used if the specified spot or separation |
38 | | * colorant is not present. We want to be able to display the spot colors |
39 | | * on our RGB or CMYK display. We are using the tint transform function |
40 | | * to determine a CMYK equivalent to the spot color. Current only CMYK |
41 | | * equivalent colors are supported. This is because the CMYK is the only |
42 | | * standard subtractive color space. |
43 | | * |
44 | | * This process consists of the following steps: |
45 | | * |
46 | | * 1. Whenever new spot colors are found, set status flags indicating |
47 | | * that we have one or more spot colors for which we need to determine an |
48 | | * equivalent color. New spot colors can either be explicitly specified by |
49 | | * the SeparationColorNames device parameter or they may be detected by the |
50 | | * device's get_color_comp_index routine. |
51 | | * |
52 | | * 2. Whenever a Separation or DeviceN color space is installed, the |
53 | | * update_spot_equivalent_colors device proc is called. This allows the |
54 | | * device to check if the color space contains a spot color for which the |
55 | | * device does not know the equivalent CMYK color. The routine |
56 | | * update_spot_equivalent_cmyk_colors is provided for this task (and the |
57 | | * next item). |
58 | | * |
59 | | * 3. For each spot color for which an equivalent color is not known, we |
60 | | * do the following: |
61 | | * a. Create a copy of the color space and change the copy so that it |
62 | | * uses its alternate colorspace. |
63 | | * b. Create a copy of the current gs_gstate and modify its color |
64 | | * mapping (cmap) procs to use a special set of 'capture' procs. |
65 | | * c. Based upon the type of color space (Separation or DeviceN) create |
66 | | * a 'color' which consists of the desired spot color set to 100% and |
67 | | * and other components set to zero. |
68 | | * d. Call the remap_color routine using our modified color space and |
69 | | * state structures. Since we have forced the use of the alternate |
70 | | * color space, we will eventually execute one of the 'capture' color |
71 | | * space mapping procs. This will give us either a gray, RGB, or |
72 | | * CMYK color which is equivalent to the original spot color. If the |
73 | | * color is gray or RGB we convert it to CMYK. |
74 | | * e. Save the equivalent CMYK color in the device structure. |
75 | | * |
76 | | * 4. When a page is to be displayed or a file created, the saved equivalent |
77 | | * color is used as desired. It can be written into the output file. It |
78 | | * may also be used to provide color values which can be combined with the |
79 | | * process color model components for a pixel, to correctly display spot |
80 | | * colors on a monitor. (Note: Overprinting effects with spot colors are |
81 | | * not correctly displayed on an RGB monitor if the device simply uses an RGB |
82 | | * process color model. Instead it is necessary to use a subtractive process |
83 | | * color model and save both process color and spot color data and then |
84 | | * convert the overall result to RGB for display.) |
85 | | * |
86 | | * For this process to work properly, the following changes need to made to |
87 | | * the device. |
88 | | * |
89 | | * 1. The device source module needs to include gsequivc.h for a definition |
90 | | * of the relevant structures and routines. An equivalent_cmyk_color_params |
91 | | * structure needs to be added to the device's structure definition and |
92 | | * it needs to be initialized. For examples see the definition of the |
93 | | * psd_device structure in src/gdevpsd.c and the definitions of the |
94 | | * gs_psdrgb_device and gs_psdcmyk_devices devices in the same module. |
95 | | * 2. Logic needs to be added to the device's get_color_comp_index and |
96 | | * put_param routines to check if any separations have been added to the |
97 | | * device. For examples see code fragments in psd_get_color_comp_index and |
98 | | * psd_put_params in src/gdevpsd.c. |
99 | | * 3. The device needs to have its own version of the |
100 | | * update_spot_equivalent_colors routine. For examples see the definition |
101 | | * of the device_procs macro and the psd_update_spot_equivalent_colors |
102 | | * routine in src/gdevpsd.c. |
103 | | * 4. The device then uses the saved equivalent color values when its output |
104 | | * is created. For example see the psd_write_header routine in |
105 | | * src/gdevpsd.c. |
106 | | */ |
107 | | |
108 | | #define compare_color_names(name, name_size, str, str_size) \ |
109 | 512 | (name_size == str_size && \ |
110 | 512 | (strncmp((const char *)name, (const char *)str, name_size) == 0)) |
111 | | |
112 | | static void |
113 | | update_Separation_spot_equivalent_cmyk_colors(gx_device * pdev, |
114 | | const gs_gstate * pgs, const gs_color_space * pcs, |
115 | | gs_devn_params * pdevn_params, |
116 | | equivalent_cmyk_color_params * pparams) |
117 | 131 | { |
118 | 131 | int i; |
119 | | |
120 | | /* |
121 | | * Check if the color space's separation name matches any of the |
122 | | * separations for which we need an equivalent CMYK color. |
123 | | */ |
124 | 153 | for (i = 0; i < pdevn_params->separations.num_separations; i++) { |
125 | 153 | if (pparams->color[i].color_info_valid == false) { |
126 | 131 | const devn_separation_name * dev_sep_name = |
127 | 131 | &(pdevn_params->separations.names[i]); |
128 | 131 | unsigned int cs_sep_name_size; |
129 | 131 | unsigned char * pcs_sep_name; |
130 | | |
131 | 131 | pcs_sep_name = (unsigned char *)pcs->params.separation.sep_name; |
132 | 131 | cs_sep_name_size = strlen(pcs->params.separation.sep_name); |
133 | 131 | if (compare_color_names(dev_sep_name->data, dev_sep_name->size, |
134 | 131 | pcs_sep_name, cs_sep_name_size)) { |
135 | 131 | gs_color_space temp_cs = *pcs; |
136 | 131 | gs_client_color client_color; |
137 | | |
138 | | /* |
139 | | * Create a copy of the color space and then modify it |
140 | | * to force the use of the alternate color space. |
141 | | */ |
142 | 131 | temp_cs.params.separation.use_alt_cspace = true; |
143 | 131 | client_color.paint.values[0] = 1.0; |
144 | 131 | capture_spot_equivalent_cmyk_colors(pdev, pgs, &client_color, |
145 | 131 | &temp_cs, i, pparams); |
146 | 131 | break; |
147 | 131 | } |
148 | 131 | } |
149 | 153 | } |
150 | 131 | } |
151 | | |
152 | | /* This is used for getting the equivalent CMYK values for the spots that |
153 | | may exist in a DeviceN output ICC profile */ |
154 | | static int |
155 | | update_ICC_spot_equivalent_cmyk_colors(gx_device * pdev, |
156 | | const gs_gstate * pgs, const gs_color_space * pcs, |
157 | | gs_devn_params * pdevn_params, |
158 | | equivalent_cmyk_color_params * pparams) |
159 | 0 | { |
160 | 0 | int i, j; |
161 | 0 | cmm_dev_profile_t *dev_profile; |
162 | 0 | int code; |
163 | 0 | gs_client_color client_color; |
164 | | |
165 | |
|
166 | 0 | code = dev_proc(pdev, get_profile)(pdev, &dev_profile); |
167 | 0 | if (code < 0) |
168 | 0 | return code; |
169 | | /* |
170 | | * Check if the ICC spot names matche any of the |
171 | | * separations for which we need an equivalent CMYK color. |
172 | | */ |
173 | 0 | for (i = 0; i < pdevn_params->separations.num_separations; i++) { |
174 | 0 | if (pparams->color[i].color_info_valid == false) { |
175 | 0 | const devn_separation_name * dev_sep_name = |
176 | 0 | &(pdevn_params->separations.names[i]); |
177 | 0 | gsicc_colorname_t *name_entry; |
178 | |
|
179 | 0 | name_entry = dev_profile->spotnames->head; |
180 | |
|
181 | 0 | for (j = 0; j < dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE]->num_comps; j++) { |
182 | 0 | client_color.paint.values[j] = 0.0; |
183 | 0 | } |
184 | 0 | for (j = 0; j < dev_profile->spotnames->count; j++) { |
185 | 0 | if (compare_color_names(dev_sep_name->data, dev_sep_name->size, |
186 | 0 | name_entry->name, name_entry->length)) { |
187 | | /* |
188 | | * Create a copy of the color space and then modify it |
189 | | * to force the use of the alternate color space. |
190 | | */ |
191 | 0 | client_color.paint.values[j] = 1.0; |
192 | 0 | capture_spot_equivalent_cmyk_colors(pdev, pgs, &client_color, |
193 | 0 | pcs, i, pparams); |
194 | 0 | break; |
195 | 0 | } |
196 | | /* Did not match, grab the next one */ |
197 | 0 | name_entry = name_entry->next; |
198 | 0 | } |
199 | 0 | } |
200 | 0 | } |
201 | 0 | return 0; |
202 | 0 | } |
203 | | |
204 | | static void |
205 | | update_DeviceN_spot_equivalent_cmyk_colors(gx_device * pdev, |
206 | | const gs_gstate * pgs, const gs_color_space * pcs, |
207 | | gs_devn_params * pdevn_params, |
208 | | equivalent_cmyk_color_params * pparams) |
209 | 46 | { |
210 | 46 | int i; |
211 | 46 | unsigned int j; |
212 | 46 | unsigned int cs_sep_name_size; |
213 | 46 | unsigned char * pcs_sep_name; |
214 | | |
215 | | /* |
216 | | * Check if the color space contains components named 'None'. If so then |
217 | | * our capture logic does not work properly. When present, the 'None' |
218 | | * components contain alternate color information. However this info is |
219 | | * specified as part of the 'color' and not part of the color space. Thus |
220 | | * we do not have this data when this routine is called. See the |
221 | | * description of DeviceN color spaces in section 4.5 of the PDF spec. |
222 | | * In this situation we exit rather than produce invalid values. |
223 | | */ |
224 | 176 | for (j = 0; j < pcs->params.device_n.num_components; j++) { |
225 | 134 | pcs_sep_name = (unsigned char *)pcs->params.device_n.names[j]; |
226 | 134 | cs_sep_name_size = strlen(pcs->params.device_n.names[j]); |
227 | | |
228 | 134 | if (compare_color_names("None", 4, pcs_sep_name, cs_sep_name_size)) { |
229 | | /* If we are going out to a device that supports devn colors |
230 | | then it is possible that any preview that such a device creates |
231 | | will be in error due to the lack of the proper mappings from |
232 | | the full DeviceN colors (whicn can include one or more \None |
233 | | enrties). Display a warning about this if in debug mode */ |
234 | | #ifdef DEBUG |
235 | | if (dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_devn, NULL, 0)) |
236 | | gs_warn("Separation preview may be inaccurate due to presence of \\None colorants"); |
237 | | #endif |
238 | 4 | return; |
239 | 4 | } |
240 | 134 | } |
241 | | |
242 | | /* |
243 | | * Check if the color space's separation names matches any of the |
244 | | * separations for which we need an equivalent CMYK color. |
245 | | */ |
246 | 166 | for (i = 0; i < pdevn_params->separations.num_separations; i++) { |
247 | 124 | if (pparams->color[i].color_info_valid == false) { |
248 | 124 | const devn_separation_name * dev_sep_name = |
249 | 124 | &(pdevn_params->separations.names[i]); |
250 | | |
251 | 247 | for (j = 0; j < pcs->params.device_n.num_components; j++) { |
252 | 247 | pcs_sep_name = (unsigned char *)pcs->params.device_n.names[j]; |
253 | 247 | cs_sep_name_size = strlen(pcs->params.device_n.names[j]); |
254 | 247 | if (compare_color_names(dev_sep_name->data, dev_sep_name->size, |
255 | 247 | pcs_sep_name, cs_sep_name_size)) { |
256 | 124 | gs_color_space temp_cs = *pcs; |
257 | 124 | gs_client_color client_color; |
258 | | |
259 | | /* |
260 | | * Create a copy of the color space and then modify it |
261 | | * to force the use of the alternate color space. |
262 | | */ |
263 | 124 | memset(&client_color, 0, sizeof(client_color)); |
264 | 124 | temp_cs.params.device_n.use_alt_cspace = true; |
265 | 124 | client_color.paint.values[j] = 1.0; |
266 | 124 | capture_spot_equivalent_cmyk_colors(pdev, pgs, &client_color, |
267 | 124 | &temp_cs, i, pparams); |
268 | 124 | break; |
269 | 124 | } |
270 | 247 | } |
271 | 124 | } |
272 | 124 | } |
273 | 42 | } |
274 | | |
275 | | static bool check_all_colors_known(int num_spot, |
276 | | equivalent_cmyk_color_params * pparams) |
277 | 177 | { |
278 | 397 | for (num_spot--; num_spot >= 0; num_spot--) |
279 | 243 | if (pparams->color[num_spot].color_info_valid == false) |
280 | 23 | return false; |
281 | 154 | return true; |
282 | 177 | } |
283 | | |
284 | | /* If possible, update the equivalent CMYK color for a spot color */ |
285 | | int |
286 | | update_spot_equivalent_cmyk_colors(gx_device * pdev, const gs_gstate * pgs, const gs_color_space * pcs_in, |
287 | | gs_devn_params * pdevn_params, equivalent_cmyk_color_params * pparams) |
288 | 9.20k | { |
289 | 9.20k | const gs_color_space * pcs = pcs_in; |
290 | 9.20k | cmm_dev_profile_t *dev_profile; |
291 | 9.20k | int code; |
292 | | |
293 | 9.20k | code = dev_proc(pdev, get_profile)(pdev, &dev_profile); |
294 | 9.20k | if (code < 0) |
295 | 0 | return code; |
296 | | |
297 | | /* If all of the color_info is valid then there is nothing to do. */ |
298 | 9.20k | if (pparams->all_color_info_valid) |
299 | 9.02k | return 0; |
300 | | |
301 | | /* Verify that we really have some separations. */ |
302 | 177 | if (pdevn_params->separations.num_separations == 0) { |
303 | 0 | pparams->all_color_info_valid = true; |
304 | 0 | return 0; |
305 | 0 | } |
306 | | |
307 | | /* If the caller apssed in NULL for the colour space, use the current colour space */ |
308 | 177 | if (pcs_in == NULL) |
309 | 0 | pcs = gs_currentcolorspace_inline(pgs); |
310 | | |
311 | | /* |
312 | | * Verify that the given color space is a Separation or a DeviceN color |
313 | | * space. If so then when check if the color space contains a separation |
314 | | * color for which we need a CMYK equivalent. |
315 | | */ |
316 | 177 | if (pcs != NULL) { |
317 | 177 | if (pcs->type->index == gs_color_space_index_Separation) { |
318 | 131 | update_Separation_spot_equivalent_cmyk_colors(pdev, pgs, pcs, |
319 | 131 | pdevn_params, pparams); |
320 | 131 | pparams->all_color_info_valid = check_all_colors_known |
321 | 131 | (pdevn_params->separations.num_separations, pparams); |
322 | 131 | } |
323 | 46 | else if (pcs->type->index == gs_color_space_index_DeviceN) { |
324 | 46 | update_DeviceN_spot_equivalent_cmyk_colors(pdev, pgs, pcs, |
325 | 46 | pdevn_params, pparams); |
326 | 46 | pparams->all_color_info_valid = check_all_colors_known |
327 | 46 | (pdevn_params->separations.num_separations, pparams); |
328 | 46 | } else if (pcs->type->index == gs_color_space_index_ICC && |
329 | 0 | dev_profile->spotnames != NULL) { |
330 | | /* In this case, we are trying to set up the equivalent colors |
331 | | for the spots in the output ICC profile */ |
332 | 0 | code = update_ICC_spot_equivalent_cmyk_colors(pdev, pgs, pcs, |
333 | 0 | pdevn_params, |
334 | 0 | pparams); |
335 | 0 | if (code < 0) |
336 | 0 | return code; |
337 | 0 | pparams->all_color_info_valid = check_all_colors_known |
338 | 0 | (pdevn_params->separations.num_separations, pparams); |
339 | 0 | } |
340 | 177 | } |
341 | 177 | return 0; |
342 | 177 | } |
343 | | |
344 | | static void |
345 | | save_spot_equivalent_cmyk_color(int sep_num, |
346 | | equivalent_cmyk_color_params * pparams, const frac cmyk[4]) |
347 | 198 | { |
348 | 198 | pparams->color[sep_num].c = cmyk[0]; |
349 | 198 | pparams->color[sep_num].m = cmyk[1]; |
350 | 198 | pparams->color[sep_num].y = cmyk[2]; |
351 | 198 | pparams->color[sep_num].k = cmyk[3]; |
352 | 198 | pparams->color[sep_num].color_info_valid = true; |
353 | 198 | } |
354 | | |
355 | | /* |
356 | | * A structure definition for a device for capturing equivalent colors |
357 | | */ |
358 | | typedef struct color_capture_device_s { |
359 | | gx_device_common; |
360 | | gx_prn_device_common; |
361 | | /* ... device-specific parameters ... */ |
362 | | /* The following values are needed by the cmap procs for saving data */ |
363 | | int sep_num; /* Number of the separation being captured */ |
364 | | /* Pointer to original device's equivalent CMYK colors */ |
365 | | equivalent_cmyk_color_params * pequiv_cmyk_colors; |
366 | | } color_capture_device; |
367 | | |
368 | | /* |
369 | | * Replacement routines for the cmap procs. These routines will capture the |
370 | | * equivalent color. |
371 | | */ |
372 | | static cmap_proc_gray(cmap_gray_capture_cmyk_color); |
373 | | static cmap_proc_rgb(cmap_rgb_capture_cmyk_color); |
374 | | static cmap_proc_cmyk(cmap_cmyk_capture_cmyk_color); |
375 | | static cmap_proc_separation(cmap_separation_capture_cmyk_color); |
376 | | static cmap_proc_devicen(cmap_devicen_capture_cmyk_color); |
377 | | |
378 | | static const gx_color_map_procs cmap_capture_cmyk_color = { |
379 | | cmap_gray_capture_cmyk_color, |
380 | | cmap_rgb_capture_cmyk_color, |
381 | | cmap_cmyk_capture_cmyk_color, |
382 | | cmap_separation_capture_cmyk_color, |
383 | | cmap_devicen_capture_cmyk_color |
384 | | }; |
385 | | |
386 | | static void |
387 | | cmap_gray_capture_cmyk_color(frac gray, gx_device_color * pdc, |
388 | | const gs_gstate * pgs, gx_device * dev, gs_color_select_t select) |
389 | 0 | { |
390 | 0 | equivalent_cmyk_color_params * pparams = |
391 | 0 | ((color_capture_device *)dev)->pequiv_cmyk_colors; |
392 | 0 | int sep_num = ((color_capture_device *)dev)->sep_num; |
393 | 0 | frac cmyk[4]; |
394 | |
|
395 | 0 | cmyk[0] = cmyk[1] = cmyk[2] = frac_0; |
396 | 0 | cmyk[3] = frac_1 - gray; |
397 | 0 | save_spot_equivalent_cmyk_color(sep_num, pparams, cmyk); |
398 | 0 | } |
399 | | |
400 | | static void |
401 | | cmap_rgb_capture_cmyk_color(frac r, frac g, frac b, gx_device_color * pdc, |
402 | | const gs_gstate * pgs, gx_device * dev, gs_color_select_t select) |
403 | 0 | { |
404 | 0 | equivalent_cmyk_color_params * pparams = |
405 | 0 | ((color_capture_device *)dev)->pequiv_cmyk_colors; |
406 | 0 | int sep_num = ((color_capture_device *)dev)->sep_num; |
407 | 0 | frac cmyk[4]; |
408 | |
|
409 | 0 | color_rgb_to_cmyk(r, g, b, pgs, cmyk, dev->memory); |
410 | 0 | save_spot_equivalent_cmyk_color(sep_num, pparams, cmyk); |
411 | 0 | } |
412 | | |
413 | | static void |
414 | | cmap_cmyk_capture_cmyk_color(frac c, frac m, frac y, frac k, gx_device_color * pdc, |
415 | | const gs_gstate * pgs, gx_device * dev, gs_color_select_t select, |
416 | | const gs_color_space *pcs) |
417 | 198 | { |
418 | 198 | equivalent_cmyk_color_params * pparams = |
419 | 198 | ((color_capture_device *)dev)->pequiv_cmyk_colors; |
420 | 198 | int sep_num = ((color_capture_device *)dev)->sep_num; |
421 | 198 | frac cmyk[4]; |
422 | | |
423 | 198 | cmyk[0] = c; |
424 | 198 | cmyk[1] = m; |
425 | 198 | cmyk[2] = y; |
426 | 198 | cmyk[3] = k; |
427 | 198 | save_spot_equivalent_cmyk_color(sep_num, pparams, cmyk); |
428 | 198 | } |
429 | | |
430 | | static void |
431 | | cmap_separation_capture_cmyk_color(frac all, gx_device_color * pdc, |
432 | | const gs_gstate * pgs, gx_device * dev, gs_color_select_t select, |
433 | | const gs_color_space *pcs) |
434 | 0 | { |
435 | 0 | dmprintf(pgs->memory, "cmap_separation_capture_cmyk_color - this routine should not be executed\n"); |
436 | 0 | } |
437 | | |
438 | | /* The call to this is actually going to occur if we happen to be using a |
439 | | named color profile and doing a replacement. Since the destination profile |
440 | | will have been CMYK based during the swap out to find the equivalent color, we can |
441 | | go ahead and just grab the cmyk portion */ |
442 | | static void |
443 | | cmap_devicen_capture_cmyk_color(const frac * pcc, gx_device_color * pdc, |
444 | | const gs_gstate * pgs, gx_device * dev, gs_color_select_t select, |
445 | | const gs_color_space *pcs) |
446 | 0 | { |
447 | 0 | equivalent_cmyk_color_params * pparams = |
448 | 0 | ((color_capture_device *)dev)->pequiv_cmyk_colors; |
449 | 0 | int sep_num = ((color_capture_device *)dev)->sep_num; |
450 | |
|
451 | 0 | save_spot_equivalent_cmyk_color(sep_num, pparams, pcc); |
452 | 0 | } |
453 | | |
454 | | /* |
455 | | * Note: The color space (pcs) has already been modified to use the |
456 | | * alternate color space. |
457 | | */ |
458 | | void |
459 | | capture_spot_equivalent_cmyk_colors(gx_device * pdev, const gs_gstate * pgs, |
460 | | const gs_client_color * pcc, const gs_color_space * pcs, |
461 | | int sep_num, equivalent_cmyk_color_params * pparams) |
462 | 255 | { |
463 | 255 | gs_gstate temp_state = *((const gs_gstate *)pgs); |
464 | 255 | color_capture_device temp_device = { 0 }; |
465 | 255 | gx_device_color dev_color; |
466 | 255 | gsicc_rendering_param_t render_cond; |
467 | 255 | cmm_dev_profile_t *dev_profile; |
468 | 255 | cmm_profile_t *curr_output_profile; |
469 | 255 | cmm_dev_profile_t temp_profile = { /* Initialize to 0's/NULL's */ |
470 | 255 | { 0 } /* device_profile[] */, 0 /* proof_profile */, |
471 | 255 | 0 /* link_profile */, 0 /* oi_profile */, |
472 | 255 | 0 /* blend_profile */, 0 /* postren_profile */, |
473 | 255 | { {0} } /* rendercond[] */, 0 /* devicegraytok */, |
474 | 255 | 0 /* graydection */, 0 /* pageneutralcolor */, |
475 | 255 | 0 /* usefastcolor */, 0 /* blacktext */, 0 /* blackvector */, |
476 | 255 | 0.0 /* blackthresholdL */, 0.0 /* blackthresholdC */, |
477 | 255 | 0 /* supports_devn */, 0 /* overprint_control */, |
478 | 255 | 0 /* spotnames */, 0 /* prebandthreshold */, 0 /* memory */, |
479 | 255 | { 0 } /* rc_header */ |
480 | 255 | }; |
481 | | |
482 | 255 | dev_proc(pdev, get_profile)(pdev, &dev_profile); |
483 | 255 | gsicc_extract_profile(pdev->graphics_type_tag, |
484 | 255 | dev_profile, &(curr_output_profile), &render_cond); |
485 | | |
486 | | /* If the output profile is not CMYK based (which can happen during overprint |
487 | | simulation. In particular when the blending space is RGB or Gray based. |
488 | | Think of the case where the file has transparency and we are in an RGB |
489 | | page group), then just use DefaultCMYK */ |
490 | 255 | if (curr_output_profile->data_cs != gsCMYK) |
491 | 0 | curr_output_profile = pgs->icc_manager->default_cmyk; |
492 | | |
493 | | /* |
494 | | * Create a temp device. The primary purpose of this device is pass the |
495 | | * separation number and a pointer to the original device's equivalent |
496 | | * color parameters. Since we only using this device for a very specific |
497 | | * purpose, we only set up the color_info structure and our data. |
498 | | */ |
499 | 255 | temp_device.color_info = pdev->color_info; |
500 | 255 | temp_device.sep_num = sep_num; |
501 | 255 | temp_device.pequiv_cmyk_colors = pparams; |
502 | 255 | temp_device.memory = pgs->memory; |
503 | | |
504 | 255 | temp_profile.usefastcolor = false; /* This avoids a few headaches */ |
505 | 255 | temp_profile.blacktext = false; |
506 | 255 | temp_profile.blackvector = false; |
507 | 255 | temp_profile.prebandthreshold = true; |
508 | 255 | temp_profile.supports_devn = false; |
509 | 255 | temp_profile.rendercond[0] = render_cond; |
510 | 255 | temp_profile.rendercond[1] = render_cond; |
511 | 255 | temp_profile.rendercond[2] = render_cond; |
512 | 255 | temp_profile.rendercond[3] = render_cond; |
513 | 255 | temp_device.icc_struct = &temp_profile; |
514 | | |
515 | | /* The equivalent CMYK colors are used for |
516 | | the preview of the composite image and as such should not rely |
517 | | upon the output profile if our output profile is a DeviceN profile. |
518 | | For example, if our output profile was CMYK + OG then if we use |
519 | | the device profile here we may not get CMYK values that |
520 | | even come close to the color we want to simulate. So, for this |
521 | | case we go ahead and use the default CMYK profile and let the user |
522 | | beware. Note that the actual separations will be correct however |
523 | | for the CMYK + OG values. */ |
524 | | |
525 | 255 | if (curr_output_profile->data_cs == gsNCHANNEL) { |
526 | 0 | temp_profile.device_profile[GS_DEFAULT_DEVICE_PROFILE] = |
527 | 0 | temp_state.icc_manager->default_cmyk; |
528 | 255 | } else { |
529 | 255 | temp_profile.device_profile[GS_DEFAULT_DEVICE_PROFILE] = |
530 | 255 | curr_output_profile; |
531 | 255 | } |
532 | 255 | set_dev_proc(&temp_device, get_profile, gx_default_get_profile); |
533 | | |
534 | | /* |
535 | | * Create a temp copy of the gs_gstate. We do this so that we |
536 | | * can modify the color space mapping (cmap) procs. We use our |
537 | | * replacment procs to capture the color. The installation of a |
538 | | * Separation or DeviceN color space also sets a use_alt_cspace flag |
539 | | * in the state. We also need to set this to use the alternate space. |
540 | | */ |
541 | 255 | temp_state.cmap_procs = &cmap_capture_cmyk_color; |
542 | 255 | temp_state.color_component_map.use_alt_cspace = true; |
543 | | |
544 | | /* Now capture the color */ |
545 | 255 | pcs->type->remap_color (pcc, pcs, &dev_color, &temp_state, |
546 | 255 | (gx_device *)&temp_device, gs_color_select_texture); |
547 | 255 | } |
548 | | |
549 | | /* Used for detecting if we are trying to find the equivalant color during |
550 | | named color replacement */ |
551 | | bool |
552 | | named_color_equivalent_cmyk_colors(const gs_gstate * pgs) |
553 | 0 | { |
554 | 0 | return pgs->cmap_procs == &cmap_capture_cmyk_color; |
555 | 0 | } |