1 /* Copyright (C) 1998, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gscspace.c,v 1.18 2004/08/19 19:33:09 stefan Exp $ */
18 /* Color space operators and support */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gsccolor.h"
24 #include "gsutil.h" /* for gs_next_ids */
25 #include "gxcmap.h"
26 #include "gxcspace.h"
27 #include "gxistate.h"
28 #include "gsovrc.h"
29 #include "gsstate.h"
30 #include "gsdevice.h"
31 #include "gxdevcli.h"
32 #include "gzstate.h"
33 #include "stream.h"
34
35 /*
36 * Define the standard color space types. We include DeviceCMYK in the base
37 * build because it's too awkward to omit it, but we don't provide any of
38 * the PostScript operator procedures (setcmykcolor, etc.) for dealing with
39 * it.
40 */
41 private const gs_color_space_type gs_color_space_type_DeviceGray = {
42 gs_color_space_index_DeviceGray, true, true,
43 &st_base_color_space, gx_num_components_1,
44 gx_no_base_space,
45 gx_init_paint_1, gx_restrict01_paint_1,
46 gx_same_concrete_space,
47 gx_concretize_DeviceGray, gx_remap_concrete_DGray,
48 gx_remap_DeviceGray, gx_no_install_cspace,
49 gx_spot_colors_set_overprint,
50 gx_no_adjust_cspace_count, gx_no_adjust_color_count,
51 gx_serialize_cspace_type,
52 gx_cspace_is_linear_default
53 };
54 private const gs_color_space_type gs_color_space_type_DeviceRGB = {
55 gs_color_space_index_DeviceRGB, true, true,
56 &st_base_color_space, gx_num_components_3,
57 gx_no_base_space,
58 gx_init_paint_3, gx_restrict01_paint_3,
59 gx_same_concrete_space,
60 gx_concretize_DeviceRGB, gx_remap_concrete_DRGB,
61 gx_remap_DeviceRGB, gx_no_install_cspace,
62 gx_spot_colors_set_overprint,
63 gx_no_adjust_cspace_count, gx_no_adjust_color_count,
64 gx_serialize_cspace_type,
65 gx_cspace_is_linear_default
66 };
67
68 private cs_proc_set_overprint(gx_set_overprint_DeviceCMYK);
69
70 private const gs_color_space_type gs_color_space_type_DeviceCMYK = {
71 gs_color_space_index_DeviceCMYK, true, true,
72 &st_base_color_space, gx_num_components_4,
73 gx_no_base_space,
74 gx_init_paint_4, gx_restrict01_paint_4,
75 gx_same_concrete_space,
76 gx_concretize_DeviceCMYK, gx_remap_concrete_DCMYK,
77 gx_remap_DeviceCMYK, gx_no_install_cspace,
78 gx_set_overprint_DeviceCMYK,
79 gx_no_adjust_cspace_count, gx_no_adjust_color_count,
80 gx_serialize_cspace_type,
81 gx_cspace_is_linear_default
82 };
83
84 /* Structure descriptors */
85 public_st_color_space();
86 public_st_base_color_space();
87
88
89 /* ------ Create/copy/destroy ------ */
90
91 void
gs_cspace_init(gs_color_space * pcs,const gs_color_space_type * pcstype,gs_memory_t * mem,bool isheap)92 gs_cspace_init(gs_color_space *pcs, const gs_color_space_type * pcstype,
93 gs_memory_t *mem, bool isheap)
94 {
95 pcs->type = pcstype;
96 pcs->pmem = isheap ? mem : NULL;
97 pcs->id = gs_next_ids(mem, 1);
98 }
99
100 int
gs_cspace_alloc(gs_color_space ** ppcspace,const gs_color_space_type * pcstype,gs_memory_t * mem)101 gs_cspace_alloc(gs_color_space ** ppcspace,
102 const gs_color_space_type * pcstype,
103 gs_memory_t * mem)
104 {
105 gs_color_space *pcspace =
106 gs_alloc_struct(mem, gs_color_space, &st_color_space,
107 "gs_cspace_alloc");
108
109 if (pcspace == 0)
110 return_error(gs_error_VMerror);
111 if (pcstype != 0)
112 gs_cspace_init(pcspace, pcstype, mem, true);
113 *ppcspace = pcspace;
114 return 0;
115 }
116
117 int
gs_cspace_init_DeviceGray(const gs_memory_t * mem,gs_color_space * pcs)118 gs_cspace_init_DeviceGray(const gs_memory_t *mem, gs_color_space *pcs)
119 {
120 /* parameterless color space; no re-entrancy problems */
121 static gs_color_space dev_gray_proto;
122
123 if (dev_gray_proto.id == 0)
124 gs_cspace_init( &dev_gray_proto,
125 &gs_color_space_type_DeviceGray,
126 (gs_memory_t *)mem, false );
127 *pcs = dev_gray_proto;
128 return 0;
129 }
130 int
gs_cspace_build_DeviceGray(gs_color_space ** ppcspace,gs_memory_t * pmem)131 gs_cspace_build_DeviceGray(gs_color_space ** ppcspace, gs_memory_t * pmem)
132 {
133 int code = gs_cspace_alloc(ppcspace, NULL, pmem);
134
135 if (code >= 0)
136 code = gs_cspace_init_DeviceGray(pmem, *ppcspace);
137 return code;
138 }
139
140 int
gs_cspace_init_DeviceRGB(const gs_memory_t * mem,gs_color_space * pcs)141 gs_cspace_init_DeviceRGB(const gs_memory_t *mem, gs_color_space *pcs)
142 {
143 /* parameterless color space; no re-entrancy problems */
144 static gs_color_space dev_rgb_proto;
145
146 if (dev_rgb_proto.id == 0)
147 gs_cspace_init( &dev_rgb_proto,
148 &gs_color_space_type_DeviceRGB,
149 (gs_memory_t *)mem, false );
150 *pcs = dev_rgb_proto;
151 return 0;
152 }
153 int
gs_cspace_build_DeviceRGB(gs_color_space ** ppcspace,gs_memory_t * pmem)154 gs_cspace_build_DeviceRGB(gs_color_space ** ppcspace, gs_memory_t * pmem)
155 {
156 int code = gs_cspace_alloc(ppcspace, NULL, pmem);
157
158 if (code >= 0)
159 code = gs_cspace_init_DeviceRGB(pmem, *ppcspace);
160 return code;
161 }
162
163 int
gs_cspace_init_DeviceCMYK(const gs_memory_t * mem,gs_color_space * pcs)164 gs_cspace_init_DeviceCMYK(const gs_memory_t *mem, gs_color_space *pcs)
165 {
166 /* parameterless color space; no re-entrancy problems */
167 static gs_color_space dev_cmyk_proto;
168
169 if (dev_cmyk_proto.id == 0)
170 gs_cspace_init( &dev_cmyk_proto,
171 &gs_color_space_type_DeviceCMYK,
172 (gs_memory_t *)mem, false );
173 *pcs = dev_cmyk_proto;
174 return 0;
175 }
176 int
gs_cspace_build_DeviceCMYK(gs_color_space ** ppcspace,gs_memory_t * pmem)177 gs_cspace_build_DeviceCMYK(gs_color_space ** ppcspace, gs_memory_t * pmem)
178 {
179 int code = gs_cspace_alloc(ppcspace, NULL, pmem);
180
181 if (code >= 0)
182 code = gs_cspace_init_DeviceCMYK(pmem, *ppcspace);
183 return code;
184 }
185
186 /*
187 * Copy just enough of a color space object. This will do the right thing
188 * for copying color spaces into the base or alternate color space of a
189 * compound color space when legal, but it can't check that the operation is
190 * actually legal.
191 */
192 inline private void
cs_copy(gs_color_space * pcsto,const gs_color_space * pcsfrom)193 cs_copy(gs_color_space *pcsto, const gs_color_space *pcsfrom)
194 {
195 memcpy(pcsto, pcsfrom, pcsfrom->type->stype->ssize);
196 }
197
198 /* Copy a color space into one newly allocated by the caller. */
199 void
gs_cspace_init_from(gs_color_space * pcsto,const gs_color_space * pcsfrom)200 gs_cspace_init_from(gs_color_space * pcsto, const gs_color_space * pcsfrom)
201 {
202 cs_copy(pcsto, pcsfrom);
203 (*pcsto->type->adjust_cspace_count)(pcsto, 1);
204 }
205
206 /* Assign a color space into a previously initialized one. */
207 void
gs_cspace_assign(gs_color_space * pdest,const gs_color_space * psrc)208 gs_cspace_assign(gs_color_space * pdest, const gs_color_space * psrc)
209 {
210 /* check for a = a */
211 if (pdest == psrc)
212 return;
213 (*psrc->type->adjust_cspace_count)(psrc, 1);
214 (*pdest->type->adjust_cspace_count)(pdest, -1);
215 cs_copy(pdest, psrc);
216 }
217
218
219 /* Prepare to free a color space. */
220 void
gs_cspace_release(gs_color_space * pcs)221 gs_cspace_release(gs_color_space * pcs)
222 {
223 (*pcs->type->adjust_cspace_count)(pcs, -1);
224 }
225
226 /* ------ Accessors ------ */
227
228 /* Get the index of a color space. */
229 gs_color_space_index
gs_color_space_get_index(const gs_color_space * pcs)230 gs_color_space_get_index(const gs_color_space * pcs)
231 {
232 return pcs->type->index;
233 }
234
235 /* Get the number of components in a color space. */
236 int
gs_color_space_num_components(const gs_color_space * pcs)237 gs_color_space_num_components(const gs_color_space * pcs)
238 {
239 return cs_num_components(pcs);
240 }
241
242 /* Restrict a color to its legal range. */
243 void
gs_color_space_restrict_color(gs_client_color * pcc,const gs_color_space * pcs)244 gs_color_space_restrict_color(gs_client_color *pcc, const gs_color_space *pcs)
245 {
246 cs_restrict_color(pcc, pcs);
247 }
248
249 int
gx_num_components_1(const gs_color_space * pcs)250 gx_num_components_1(const gs_color_space * pcs)
251 {
252 return 1;
253 }
254 int
gx_num_components_3(const gs_color_space * pcs)255 gx_num_components_3(const gs_color_space * pcs)
256 {
257 return 3;
258 }
259 int
gx_num_components_4(const gs_color_space * pcs)260 gx_num_components_4(const gs_color_space * pcs)
261 {
262 return 4;
263 }
264
265 /*
266 * For color spaces that have a base or alternative color space, return that
267 * color space. Otherwise return null.
268 */
269 const gs_color_space *
gs_cspace_base_space(const gs_color_space * pcspace)270 gs_cspace_base_space(const gs_color_space * pcspace)
271 {
272 return cs_base_space(pcspace);
273 }
274
275 const gs_color_space *
gx_no_base_space(const gs_color_space * pcspace)276 gx_no_base_space(const gs_color_space * pcspace)
277 {
278 return NULL;
279 }
280
281 /* ------ Other implementation procedures ------ */
282
283 /* Null color space installation procedure. */
284 int
gx_no_install_cspace(const gs_color_space * pcs,gs_state * pgs)285 gx_no_install_cspace(const gs_color_space * pcs, gs_state * pgs)
286 {
287 return 0;
288 }
289
290 /*
291 * Push an overprint compositor onto the current device indicating that,
292 * at most, the spot color parameters are to be preserved.
293 *
294 * This routine should be used for all Device, CIEBased, and ICCBased
295 * color spaces, except for DeviceCMKY. The latter color space requires a
296 * special verson that supports overprint mode.
297 */
298 int
gx_spot_colors_set_overprint(const gs_color_space * pcs,gs_state * pgs)299 gx_spot_colors_set_overprint(const gs_color_space * pcs, gs_state * pgs)
300 {
301 gs_imager_state * pis = (gs_imager_state *)pgs;
302 gs_overprint_params_t params;
303
304 if ((params.retain_any_comps = pis->overprint))
305 params.retain_spot_comps = true;
306 pgs->effective_overprint_mode = 0;
307 return gs_state_update_overprint(pgs, ¶ms);
308 }
309
310
311 private bool
check_single_comp(int comp,frac targ_val,int ncomps,const frac * pval)312 check_single_comp(int comp, frac targ_val, int ncomps, const frac * pval)
313 {
314 int i;
315
316 for (i = 0; i < ncomps; i++) {
317 if ( (i != comp && pval[i] != frac_0) ||
318 (i == comp && pval[i] != targ_val) )
319 return false;
320 }
321 return true;
322 }
323
324 /*
325 * Determine if the current color model is a "DeviceCMYK" color model, and
326 * if so what are its process color components. This information is required
327 * only if overprint is true and overprint mode is set to 1.
328 *
329 * A color model is considered a "DeviceCMYK" color model if it supports the
330 * cyan, magenta, yellow, and black color components, and maps the DeviceCMYK
331 * color model components directly to these color components. Note that this
332 * does not require any particular component order, allows for additional
333 * spot color components, and does admit DeviceN color spaces if they have
334 * the requisite behavior.
335 *
336 * If the color model is a "DeviceCMYK" color model, return the set of
337 * process color components; otherwise return 0.
338 */
339 private gx_color_index
check_cmyk_color_model_comps(gx_device * dev)340 check_cmyk_color_model_comps(gx_device * dev)
341 {
342 gx_device_color_info * pcinfo = &dev->color_info;
343 int ncomps = pcinfo->num_components;
344 int cyan_c, magenta_c, yellow_c, black_c;
345 const gx_cm_color_map_procs * pprocs;
346 cm_map_proc_cmyk((*map_cmyk));
347 frac frac_14 = frac_1 / 4;
348 frac out[GX_DEVICE_COLOR_MAX_COMPONENTS];
349 gx_color_index process_comps;
350
351 /* check for the appropriate components */
352 if ( ncomps < 4 ||
353 (cyan_c = dev_proc(dev, get_color_comp_index)(
354 dev,
355 "Cyan",
356 sizeof("Cyan") - 1,
357 NO_COMP_NAME_TYPE )) < 0 ||
358 cyan_c == GX_DEVICE_COLOR_MAX_COMPONENTS ||
359 (magenta_c = dev_proc(dev, get_color_comp_index)(
360 dev,
361 "Magenta",
362 sizeof("Magenta") - 1,
363 NO_COMP_NAME_TYPE )) < 0 ||
364 magenta_c == GX_DEVICE_COLOR_MAX_COMPONENTS ||
365 (yellow_c = dev_proc(dev, get_color_comp_index)(
366 dev,
367 "Yellow",
368 sizeof("Yellow") - 1,
369 NO_COMP_NAME_TYPE )) < 0 ||
370 yellow_c == GX_DEVICE_COLOR_MAX_COMPONENTS ||
371 (black_c = dev_proc(dev, get_color_comp_index)(
372 dev,
373 "Black",
374 sizeof("Black") - 1,
375 NO_COMP_NAME_TYPE )) < 0 ||
376 black_c == GX_DEVICE_COLOR_MAX_COMPONENTS )
377 return 0;
378
379 /* check the mapping */
380 if ( (pprocs = dev_proc(dev, get_color_mapping_procs)(dev)) == 0 ||
381 (map_cmyk = pprocs->map_cmyk) == 0 )
382 return 0;
383
384 map_cmyk(dev, frac_14, frac_0, frac_0, frac_0, out);
385 if (!check_single_comp(cyan_c, frac_14, ncomps, out))
386 return 0;
387 map_cmyk(dev, frac_0, frac_14, frac_0, frac_0, out);
388 if (!check_single_comp(magenta_c, frac_14, ncomps, out))
389 return 0;
390 map_cmyk(dev, frac_0, frac_0, frac_14, frac_0, out);
391 if (!check_single_comp(yellow_c, frac_14, ncomps, out))
392 return false;
393 map_cmyk(dev, frac_0, frac_0, frac_0, frac_14, out);
394 if (!check_single_comp(black_c, frac_14, ncomps, out))
395 return 0;
396
397 process_comps = ((gx_color_index)1 << cyan_c)
398 | ((gx_color_index)1 << magenta_c)
399 | ((gx_color_index)1 << yellow_c)
400 | ((gx_color_index)1 << black_c);
401 pcinfo->opmode = GX_CINFO_OPMODE;
402 pcinfo->process_comps = process_comps;
403 return process_comps;
404 }
405
406 /*
407 * This set_overprint method is unique. If overprint is true, overprint
408 * mode is set to 1, the process color model has DeviceCMYK behavior (see
409 * the comment ahead of gx_is_cmyk_color_model above), and the device
410 * color is set, the device color needs to be considered in setting up
411 * the set of drawn components.
412 */
413 private int
gx_set_overprint_DeviceCMYK(const gs_color_space * pcs,gs_state * pgs)414 gx_set_overprint_DeviceCMYK(const gs_color_space * pcs, gs_state * pgs)
415 {
416 gx_device * dev = pgs->device;
417 gx_device_color_info * pcinfo = (dev == 0 ? 0 : &dev->color_info);
418 gx_color_index drawn_comps = 0;
419 gs_overprint_params_t params;
420
421 /* check if we require special handling */
422 if ( !pgs->overprint ||
423 pgs->overprint_mode != 1 ||
424 pcinfo == 0 ||
425 pcinfo->opmode == GX_CINFO_OPMODE_NOT )
426 return gx_spot_colors_set_overprint(pcs, pgs);
427
428 /* check if color model behavior must be determined */
429 if (pcinfo->opmode == GX_CINFO_OPMODE_UNKNOWN)
430 drawn_comps = check_cmyk_color_model_comps(dev);
431 else
432 drawn_comps = pcinfo->process_comps;
433 if (drawn_comps == 0)
434 return gx_spot_colors_set_overprint(pcs, pgs);
435
436 /* correct for any zero'ed color components */
437 pgs->effective_overprint_mode = 1;
438 if (color_is_set(pgs->dev_color)) {
439 gx_color_index nz_comps;
440 int code;
441 dev_color_proc_get_nonzero_comps((*procp));
442
443 procp = pgs->dev_color->type->get_nonzero_comps;
444 if ((code = procp(pgs->dev_color, dev, &nz_comps)) < 0)
445 return code;
446 drawn_comps &= nz_comps;
447 }
448
449 params.retain_any_comps = true;
450 params.retain_spot_comps = false;
451 params.drawn_comps = drawn_comps;
452 return gs_state_update_overprint(pgs, ¶ms);
453 }
454
455
456 /* Null reference count adjustment procedure. */
457 void
gx_no_adjust_cspace_count(const gs_color_space * pcs,int delta)458 gx_no_adjust_cspace_count(const gs_color_space * pcs, int delta)
459 {
460 }
461
462 /* A stub for a color mapping linearity check, when it is inapplicable. */
463 int
gx_cspace_no_linear(gs_direct_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)464 gx_cspace_no_linear(gs_direct_color_space *cs, const gs_imager_state * pis,
465 gx_device * dev,
466 const gs_client_color *c0, const gs_client_color *c1,
467 const gs_client_color *c2, const gs_client_color *c3,
468 float smoothness)
469 {
470 return_error(gs_error_rangecheck);
471 }
472
473 private inline int
cc2dc(gs_direct_color_space * cs,const gs_imager_state * pis,gx_device * dev,gx_device_color * dc,const gs_client_color * cc)474 cc2dc(gs_direct_color_space *cs, const gs_imager_state * pis, gx_device *dev,
475 gx_device_color *dc, const gs_client_color *cc)
476 {
477 return cs->type->remap_color(cc, (const gs_color_space *)cs, dc, pis, dev, gs_color_select_texture);
478 }
479
480 private inline void
interpolate_cc(gs_client_color * c,const gs_client_color * c0,const gs_client_color * c1,double t,int n)481 interpolate_cc(gs_client_color *c,
482 const gs_client_color *c0, const gs_client_color *c1, double t, int n)
483 {
484 int i;
485
486 for (i = 0; i < n; i++)
487 c->paint.values[i] = c0->paint.values[i] * t + c1->paint.values[i] * (1 - t);
488 }
489
490 private inline bool
is_dc_nearly_linear(const gx_device * dev,const gx_device_color * c,const gx_device_color * c0,const gx_device_color * c1,double t,int n,float smoothness)491 is_dc_nearly_linear(const gx_device *dev, const gx_device_color *c,
492 const gx_device_color *c0, const gx_device_color *c1,
493 double t, int n, float smoothness)
494 {
495 if (c0->type == &gx_dc_type_data_pure) {
496 int i;
497 gx_color_index pure0 = c0->colors.pure;
498 gx_color_index pure1 = c1->colors.pure;
499 gx_color_index pure = c->colors.pure;
500
501 for (i = 0; i < n; i++) {
502 int shift = dev->color_info.comp_shift[i];
503 int mask = (1 << dev->color_info.comp_bits[i]) - 1;
504 int max_color = (i == dev->color_info.gray_index ? dev->color_info.max_gray
505 : dev->color_info.max_color);
506 int b0 = (pure0 >> shift) & mask, b1 = (pure1 >> shift) & mask;
507 int b = (pure >> shift) & mask;
508 double bb = b0 * t + b1 * (1 - t);
509
510 if (any_abs(b - bb) > max_color * smoothness)
511 return false;
512 }
513 return true;
514 } else {
515 /* Halftones must not paint with fill_linear_color_*. */
516 return false;
517 }
518 }
519
520 /* Default color mapping linearity check, a 2-points case. */
521 private int
gx_cspace_is_linear_in_line(gs_direct_color_space * cs,const gs_imager_state * pis,gx_device * dev,const gs_client_color * c0,const gs_client_color * c1,float smoothness)522 gx_cspace_is_linear_in_line(gs_direct_color_space *cs, const gs_imager_state * pis,
523 gx_device *dev,
524 const gs_client_color *c0, const gs_client_color *c1,
525 float smoothness)
526 {
527 gs_client_color c01a, c01b;
528 gx_device_color d[2], d01a, d01b;
529 int n = cs->type->num_components((const gs_color_space *)cs);
530 int code;
531
532 code = cc2dc(cs, pis, dev, &d[0], c0);
533 if (code < 0)
534 return code;
535 code = cc2dc(cs, pis, dev, &d[1], c1);
536 if (code < 0)
537 return code;
538 interpolate_cc(&c01a, c0, c1, 0.3, n);
539 code = cc2dc(cs, pis, dev, &d01a, &c01a);
540 if (code < 0)
541 return code;
542 if (!is_dc_nearly_linear(dev, &d01a, &d[0], &d[1], 0.3, n, smoothness))
543 return 0;
544 interpolate_cc(&c01b, c0, c1, 0.7, n);
545 code = cc2dc(cs, pis, dev, &d01b, &c01b);
546 if (code < 0)
547 return code;
548 if (!is_dc_nearly_linear(dev, &d01b, &d[0], &d[1], 0.7, n, smoothness))
549 return 0;
550 return 1;
551 }
552
553 /* Default color mapping linearity check, a triangle case. */
554 private int
gx_cspace_is_linear_in_triangle(gs_direct_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)555 gx_cspace_is_linear_in_triangle(gs_direct_color_space *cs, const gs_imager_state * pis,
556 gx_device *dev,
557 const gs_client_color *c0, const gs_client_color *c1,
558 const gs_client_color *c2, float smoothness)
559 {
560 /* We check 4 points - the median center, and middle points of 3 sides.
561 Hopely this is enough for reasonable color spaces and color renderings.
562 Note it gives 7 points for a quadrangle. */
563 gs_client_color c01, c12, c20, c012;
564 gx_device_color d[3], d01, d12, d20, d012;
565 int n = cs->type->num_components((const gs_color_space *)cs);
566 int code;
567
568 code = cc2dc(cs, pis, dev, &d[0], c0);
569 if (code < 0)
570 return code;
571 code = cc2dc(cs, pis, dev, &d[1], c1);
572 if (code < 0)
573 return code;
574 code = cc2dc(cs, pis, dev, &d[2], c2);
575 if (code < 0)
576 return code;
577
578 interpolate_cc(&c01, c0, c1, 0.5, n);
579 code = cc2dc(cs, pis, dev, &d01, &c01);
580 if (code < 0)
581 return code;
582 if (!is_dc_nearly_linear(dev, &d01, &d[0], &d[1], 0.5, n, smoothness))
583 return 0;
584
585 interpolate_cc(&c012, c2, &c01, 2.0 / 3, n);
586 code = cc2dc(cs, pis, dev, &d012, &c012);
587 if (code < 0)
588 return code;
589 if (!is_dc_nearly_linear(dev, &d012, &d[2], &d01, 2.0 / 3, n, smoothness))
590 return 0;
591
592 interpolate_cc(&c12, c1, c2, 0.5, n);
593 code = cc2dc(cs, pis, dev, &d12, &c12);
594 if (code < 0)
595 return code;
596 if (!is_dc_nearly_linear(dev, &d12, &d[1], &d[2], 0.5, n, smoothness))
597 return 0;
598
599 interpolate_cc(&c20, c2, c0, 0.5, n);
600 code = cc2dc(cs, pis, dev, &d20, &c20);
601 if (code < 0)
602 return code;
603 if (!is_dc_nearly_linear(dev, &d20, &d[2], &d[0], 0.5, n, smoothness))
604 return 0;
605 return 1;
606 }
607
608 /* Default color mapping linearity check. */
609 int
gx_cspace_is_linear_default(gs_direct_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)610 gx_cspace_is_linear_default(gs_direct_color_space *cs, const gs_imager_state * pis,
611 gx_device *dev,
612 const gs_client_color *c0, const gs_client_color *c1,
613 const gs_client_color *c2, const gs_client_color *c3,
614 float smoothness)
615 {
616 /* Assuming 2 <= nc <= 4. We don't need other cases. */
617 /* With nc == 4 assuming a convex plain quadrangle in the client color space. */
618 int code;
619
620 if (dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN)
621 return_error(gs_error_rangecheck);
622 if (c2 == NULL)
623 return gx_cspace_is_linear_in_line(cs, pis, dev, c0, c1, smoothness);
624 code = gx_cspace_is_linear_in_triangle(cs, pis, dev, c0, c1, c2, smoothness);
625 if (code <= 0)
626 return code;
627 if (c3 == NULL)
628 return 1;
629 return gx_cspace_is_linear_in_triangle(cs, pis, dev, c1, c2, c3, smoothness);
630 }
631
632 /* Serialization. */
633 int
gx_serialize_cspace_type(const gs_color_space * pcs,stream * s)634 gx_serialize_cspace_type(const gs_color_space * pcs, stream * s)
635 {
636 const gs_color_space_type * type = pcs->type;
637 uint n;
638 return sputs(s, (const byte *)&type->index, sizeof(type->index), &n);
639 }
640
641 /* GC procedures */
642
643 private
ENUM_PTRS_BEGIN_PROC(color_space_enum_ptrs)644 ENUM_PTRS_BEGIN_PROC(color_space_enum_ptrs)
645 {
646 EV_CONST gs_color_space *pcs = vptr;
647
648 return ENUM_USING(*pcs->type->stype, vptr, size, index);
649 ENUM_PTRS_END_PROC
650 }
651 private
RELOC_PTRS_WITH(color_space_reloc_ptrs,gs_color_space * pcs)652 RELOC_PTRS_WITH(color_space_reloc_ptrs, gs_color_space *pcs)
653 {
654 RELOC_USING(*pcs->type->stype, vptr, size);
655 }
656 RELOC_PTRS_END
657