Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gscspace.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Color space operators and support */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gsstruct.h"
22
#include "gsccolor.h"
23
#include "gsutil.h"   /* for gs_next_ids */
24
#include "gxcmap.h"
25
#include "gxcspace.h"
26
#include "gxgstate.h"
27
#include "gsovrc.h"
28
#include "gsstate.h"
29
#include "gsdevice.h"
30
#include "gxdevcli.h"
31
#include "gzstate.h"
32
#include "stream.h"
33
#include "gsnamecl.h"  /* Custom color call back define */
34
#include "gsicc.h"
35
#include "gsicc_manage.h"
36
#include "string_.h"
37
#include "strmio.h"         /* needed for sfclose */
38
#include "gsicc_cache.h"    /* Needed for gsicc_get_icc_buff_hash */
39
40
static cs_proc_install_cspace(gx_install_DeviceGray);
41
static cs_proc_install_cspace(gx_install_DeviceRGB);
42
static cs_proc_install_cspace(gx_install_DeviceCMYK);
43
/*
44
 * Define the standard color space types.  We include DeviceCMYK in the base
45
 * build because it's too awkward to omit it, but we don't provide any of
46
 * the PostScript operator procedures (setcmykcolor, etc.) for dealing with
47
 * it.
48
 */
49
static const gs_color_space_type gs_color_space_type_DeviceGray = {
50
    gs_color_space_index_DeviceGray, true, true,
51
    &st_base_color_space, gx_num_components_1,
52
    gx_init_paint_1, gx_restrict01_paint_1,
53
    gx_same_concrete_space,
54
    gx_concretize_DeviceGray, gx_remap_concrete_DGray,
55
    gx_remap_DeviceGray, gx_install_DeviceGray,
56
    gx_spot_colors_set_overprint,
57
    NULL, gx_no_adjust_color_count,
58
    gx_serialize_cspace_type,
59
    gx_cspace_is_linear_default, gx_polarity_additive
60
};
61
static const gs_color_space_type gs_color_space_type_DeviceRGB = {
62
    gs_color_space_index_DeviceRGB, true, true,
63
    &st_base_color_space, gx_num_components_3,
64
    gx_init_paint_3, gx_restrict01_paint_3,
65
    gx_same_concrete_space,
66
    gx_concretize_DeviceRGB, gx_remap_concrete_DRGB,
67
    gx_remap_DeviceRGB, gx_install_DeviceRGB,
68
    gx_spot_colors_set_overprint,
69
    NULL, gx_no_adjust_color_count,
70
    gx_serialize_cspace_type,
71
    gx_cspace_is_linear_default, gx_polarity_additive
72
};
73
74
static cs_proc_set_overprint(gx_set_overprint_DeviceCMYK);
75
76
static const gs_color_space_type gs_color_space_type_DeviceCMYK = {
77
    gs_color_space_index_DeviceCMYK, true, true,
78
    &st_base_color_space, gx_num_components_4,
79
    gx_init_paint_4, gx_restrict01_paint_4,
80
    gx_same_concrete_space,
81
    gx_concretize_DeviceCMYK, gx_remap_concrete_DCMYK,
82
    gx_remap_DeviceCMYK, gx_install_DeviceCMYK,
83
    gx_set_overprint_DeviceCMYK,
84
    NULL, gx_no_adjust_color_count,
85
    gx_serialize_cspace_type,
86
    gx_cspace_is_linear_default, gx_polarity_subtractive
87
};
88
89
/* Structure descriptors */
90
public_st_color_space();
91
public_st_base_color_space();
92
93
/* ------ Create/copy/destroy ------ */
94
95
/* Ghostscript object finalizers can be called many times and hence
96
 * must be idempotent. */
97
static void
98
gs_cspace_final(const gs_memory_t *cmem, void *vptr)
99
10.3M
{
100
10.3M
    gs_color_space *pcs = (gs_color_space *)vptr;
101
10.3M
    (void)cmem; /* unused */
102
103
10.3M
    if (pcs->interpreter_free_cspace_proc != NULL) {
104
584k
        (*pcs->interpreter_free_cspace_proc) ((gs_memory_t *)cmem, pcs);
105
584k
        pcs->interpreter_free_cspace_proc = NULL;
106
584k
    }
107
10.3M
    if (pcs->type->final)
108
5.78M
        pcs->type->final(pcs);
109
10.3M
    if_debug2m('c', cmem, "[c]cspace final "PRI_INTPTR" %d\n", (intptr_t)pcs, (int)pcs->id);
110
10.3M
    rc_decrement_only_cs(pcs->base_space, "gs_cspace_final");
111
10.3M
    pcs->base_space = NULL;
112
10.3M
    if (pcs->params.device_n.devn_process_space != NULL) {
113
0
        rc_decrement_only_cs(pcs->params.device_n.devn_process_space, "gs_cspace_final");
114
0
        pcs->params.device_n.devn_process_space = NULL;
115
0
    }
116
    /* No need to decrement the ICC profile data.  It is handled
117
       by the finalize of the ICC space which is called above using
118
       pcs->type->final(pcs);  */
119
10.3M
}
120
121
static gs_color_space *
122
gs_cspace_alloc_with_id(gs_memory_t *mem, ulong id,
123
                   const gs_color_space_type *pcstype)
124
10.3M
{
125
10.3M
    gs_color_space *pcs;
126
127
10.3M
    rc_alloc_struct_1(pcs, gs_color_space, &st_color_space, mem, return NULL,
128
10.3M
                      "gs_cspace_alloc_with_id");
129
10.3M
    if_debug3m('c', mem, "[c]cspace alloc "PRI_INTPTR" %s %d\n",
130
10.3M
               (intptr_t)pcs, pcstype->stype->sname, pcstype->index);
131
10.3M
    pcs->type = pcstype;
132
10.3M
    pcs->id = id;
133
10.3M
    pcs->base_space = NULL;
134
10.3M
    pcs->pclient_color_space_data = NULL;
135
10.3M
    pcs->interpreter_data = NULL;
136
10.3M
    pcs->interpreter_free_cspace_proc = NULL;
137
10.3M
    pcs->cmm_icc_profile_data = NULL;
138
10.3M
    pcs->icc_equivalent = NULL;
139
10.3M
    pcs->params.device_n.devn_process_space = NULL;
140
10.3M
    return pcs;
141
10.3M
}
142
143
static cs_proc_install_cspace(gx_install_DeviceGray);
144
static cs_proc_install_cspace(gx_install_DeviceRGB);
145
static cs_proc_install_cspace(gx_install_DeviceCMYK);
146
147
/*
148
 * Generic allocation function for colorspace implementations. Return
149
 * NULL on allocation failure.
150
 */
151
gs_color_space *
152
gs_cspace_alloc(gs_memory_t *mem, const gs_color_space_type *pcstype)
153
1.46M
{
154
1.46M
    return gs_cspace_alloc_with_id(mem, gs_next_ids(mem, 1), pcstype);
155
1.46M
}
156
157
/* Constructors for simple device color spaces. */
158
159
gs_color_space *
160
gs_cspace_new_DeviceGray(gs_memory_t *mem)
161
6.06M
{
162
6.06M
    return gs_cspace_alloc_with_id(mem, cs_DeviceGray_id,
163
6.06M
                                   &gs_color_space_type_DeviceGray);
164
6.06M
}
165
166
gs_color_space *
167
gs_cspace_new_DeviceRGB(gs_memory_t *mem)
168
1.80M
{
169
1.80M
    return gs_cspace_alloc_with_id(mem, cs_DeviceRGB_id,
170
1.80M
                                   &gs_color_space_type_DeviceRGB);
171
1.80M
}
172
gs_color_space *
173
gs_cspace_new_DeviceCMYK(gs_memory_t *mem)
174
980k
{
175
980k
    return gs_cspace_alloc_with_id(mem, cs_DeviceCMYK_id,
176
980k
                                   &gs_color_space_type_DeviceCMYK);
177
980k
}
178
179
/* For use in initializing ICC color spaces for XPS */
180
gs_color_space *
181
gs_cspace_new_scrgb(gs_memory_t *pmem, gs_gstate * pgs)
182
0
{
183
0
    gs_color_space *pcspace = gs_cspace_alloc(pmem, &gs_color_space_type_ICC);
184
0
    cmm_profile_t *profile;
185
0
    stream *str;
186
0
    int code;
187
188
0
    if (pcspace == NULL)
189
0
        return pcspace;
190
191
0
    code = gsicc_open_search(SCRGB, strlen(SCRGB), pmem, pmem->gs_lib_ctx->profiledir,
192
0
        pmem->gs_lib_ctx->profiledir_len, &str);
193
194
0
    if (code < 0 || str == NULL) {
195
0
        rc_decrement(pcspace, "gs_cspace_new_scrgb");
196
0
        return NULL;
197
0
    }
198
199
0
    pcspace->cmm_icc_profile_data = gsicc_profile_new(str, pmem, SCRGB, strlen(SCRGB));
200
0
    code = sfclose(str);
201
0
    if (pcspace->cmm_icc_profile_data == NULL) {
202
0
        rc_decrement(pcspace, "gs_cspace_new_scrgb");
203
0
        return NULL;
204
0
    }
205
206
    /* Get the profile handle */
207
0
    pcspace->cmm_icc_profile_data->profile_handle =
208
0
        gsicc_get_profile_handle_buffer(pcspace->cmm_icc_profile_data->buffer,
209
0
            pcspace->cmm_icc_profile_data->buffer_size, pmem);
210
0
    if (!pcspace->cmm_icc_profile_data->profile_handle) {
211
0
        rc_decrement(pcspace, "gs_cspace_new_scrgb");
212
0
        return NULL;
213
0
    }
214
0
    profile = pcspace->cmm_icc_profile_data;
215
216
    /* Compute the hash code of the profile. Everything in the
217
    ICC manager will have it's hash code precomputed */
218
0
    gsicc_get_icc_buff_hash(profile->buffer, &(profile->hashcode),
219
0
        profile->buffer_size);
220
0
    profile->hash_is_valid = true;
221
0
    profile->num_comps =
222
0
        gscms_get_input_channel_count(profile->profile_handle, profile->memory);
223
0
    profile->num_comps_out =
224
0
        gscms_get_output_channel_count(profile->profile_handle, profile->memory);
225
0
    profile->data_cs =
226
0
        gscms_get_profile_data_space(profile->profile_handle, profile->memory);
227
0
    gsicc_set_icc_range(&profile);
228
0
    return pcspace;
229
0
}
230
231
gs_color_space *
232
gs_cspace_new_ICC(gs_memory_t *pmem, gs_gstate * pgs, int components)
233
1.09M
{
234
1.09M
    gsicc_manager_t *icc_manage = pgs->icc_manager;
235
1.09M
    int code = 0;
236
1.09M
    gs_color_space *pcspace = gs_cspace_alloc(pmem, &gs_color_space_type_ICC);
237
238
1.09M
    if (pcspace == NULL)
239
0
        return pcspace;
240
241
1.09M
    switch (components) {
242
0
        case -1: /* alpha case */
243
0
            if (icc_manage->smask_profiles == NULL) {
244
0
                code = gsicc_initialize_iccsmask(icc_manage);
245
0
            }
246
0
            if (code == 0) {
247
0
                pcspace->cmm_icc_profile_data =
248
0
                    icc_manage->smask_profiles->smask_gray;
249
0
            } else {
250
0
                pcspace->cmm_icc_profile_data = icc_manage->default_gray;
251
0
            }
252
0
            break;
253
0
        case -3: /* alpha case.  needs linear RGB */
254
0
            if (icc_manage->smask_profiles == NULL) {
255
0
                code = gsicc_initialize_iccsmask(icc_manage);
256
0
            }
257
0
            if (code == 0) {
258
0
                pcspace->cmm_icc_profile_data =
259
0
                    icc_manage->smask_profiles->smask_rgb;
260
0
            } else {
261
0
                pcspace->cmm_icc_profile_data = icc_manage->default_rgb;
262
0
            }
263
0
            break;
264
1.09M
        case 1: pcspace->cmm_icc_profile_data = icc_manage->default_gray; break;
265
0
        case 3: pcspace->cmm_icc_profile_data = icc_manage->default_rgb; break;
266
0
        case 4: pcspace->cmm_icc_profile_data = icc_manage->default_cmyk; break;
267
0
        default: rc_decrement(pcspace,"gs_cspace_new_ICC"); return NULL;
268
1.09M
    }
269
1.09M
    gsicc_adjust_profile_rc(pcspace->cmm_icc_profile_data, 1, "gs_cspace_new_ICC");
270
1.09M
    return pcspace;
271
1.09M
}
272
273
/* ------ Accessors ------ */
274
275
/* Get the index of a color space. */
276
gs_color_space_index
277
gs_color_space_get_index(const gs_color_space * pcs)
278
23.3M
{
279
23.3M
    return pcs->type->index;
280
23.3M
}
281
282
/* See if the space is CIE based */
283
bool gs_color_space_is_CIE(const gs_color_space * pcs)
284
507k
{
285
507k
    switch(gs_color_space_get_index(pcs)){
286
0
        case gs_color_space_index_CIEDEFG:
287
0
        case gs_color_space_index_CIEDEF:
288
0
        case gs_color_space_index_CIEABC:
289
0
        case gs_color_space_index_CIEA:
290
507k
        case gs_color_space_index_ICC:
291
507k
            return true;
292
0
        break;
293
92
        default:
294
92
            return false;
295
507k
    }
296
507k
}
297
298
/* See if the space is Postscript CIE based */
299
bool gs_color_space_is_PSCIE(const gs_color_space * pcs)
300
17.8M
{
301
17.8M
    switch(gs_color_space_get_index(pcs)){
302
0
        case gs_color_space_index_CIEDEFG:
303
0
        case gs_color_space_index_CIEDEF:
304
0
        case gs_color_space_index_CIEABC:
305
0
        case gs_color_space_index_CIEA:
306
0
            return true;
307
0
        break;
308
17.8M
        default:
309
17.8M
            return false;
310
17.8M
}
311
17.8M
}
312
313
/* See if the space is ICC based */
314
bool gs_color_space_is_ICC(const gs_color_space * pcs)
315
1.13M
{
316
1.13M
    return(gs_color_space_get_index(pcs) == gs_color_space_index_ICC);
317
1.13M
}
318
319
/* Get the number of components in a color space. */
320
int
321
gs_color_space_num_components(const gs_color_space * pcs)
322
6.03M
{
323
6.03M
    return cs_num_components(pcs);
324
6.03M
}
325
326
/* Restrict a color to its legal range. */
327
void
328
gs_color_space_restrict_color(gs_client_color *pcc, const gs_color_space *pcs)
329
0
{
330
0
    cs_restrict_color(pcc, pcs);
331
0
}
332
333
/* Install a DeviceGray color space. */
334
static int
335
gx_install_DeviceGray(gs_color_space * pcs, gs_gstate * pgs)
336
3.84M
{
337
    /* If we already have profile data installed, nothing to do here. */
338
3.84M
    if (pcs->cmm_icc_profile_data != NULL)
339
0
        return 0;
340
341
    /* If we haven't initialised the iccmanager, do it now. */
342
3.84M
    if (pgs->icc_manager->default_gray == NULL) {
343
650k
        int code = gsicc_init_iccmanager(pgs);
344
650k
        if (code < 0)
345
7
            return code;
346
650k
    }
347
348
    /* pcs takes a reference to the default_gray profile data */
349
3.84M
    pcs->cmm_icc_profile_data = pgs->icc_manager->default_gray;
350
3.84M
    gsicc_adjust_profile_rc(pgs->icc_manager->default_gray, 1, "gx_install_DeviceGray");
351
3.84M
    pcs->type = &gs_color_space_type_ICC;
352
3.84M
    return 0;
353
3.84M
}
354
355
int
356
gx_num_components_1(const gs_color_space * pcs)
357
17.6M
{
358
17.6M
    return 1;
359
17.6M
}
360
int
361
gx_num_components_3(const gs_color_space * pcs)
362
901
{
363
901
    return 3;
364
901
}
365
int
366
gx_num_components_4(const gs_color_space * pcs)
367
0
{
368
0
    return 4;
369
0
}
370
371
gx_color_polarity_t
372
gx_polarity_subtractive(const gs_color_space * pcs)
373
0
{
374
0
    return GX_CINFO_POLARITY_SUBTRACTIVE;
375
0
}
376
377
gx_color_polarity_t
378
gx_polarity_additive(const gs_color_space * pcs)
379
0
{
380
0
    return GX_CINFO_POLARITY_ADDITIVE;
381
0
}
382
383
gx_color_polarity_t
384
gx_polarity_unknown(const gs_color_space * pcs)
385
0
{
386
0
    return GX_CINFO_POLARITY_UNKNOWN;
387
0
}
388
389
/*
390
 * For color spaces that have a base or alternative color space, return that
391
 * color space. Otherwise return null.
392
 */
393
const gs_color_space *
394
gs_cspace_base_space(const gs_color_space * pcspace)
395
91.0k
{
396
91.0k
    return pcspace->base_space;
397
91.0k
}
398
399
const gs_color_space *
400
gs_cspace_devn_process_space(const gs_color_space * pcspace)
401
0
{
402
0
    return pcspace->params.device_n.devn_process_space;
403
0
}
404
405
/* Abstract the reference counting for color spaces
406
   so that we can also increment the ICC profile
407
   if there is one associated with the color space */
408
409
void rc_increment_cs(gs_color_space *pcs)
410
5.70M
{
411
5.70M
    rc_increment(pcs);
412
5.70M
}
413
414
2.09M
void rc_decrement_cs(gs_color_space *pcs, const char *cname) {
415
416
2.09M
    if (pcs) {
417
2.09M
        rc_decrement(pcs, cname);
418
2.09M
    }
419
2.09M
}
420
421
void rc_decrement_only_cs(gs_color_space *pcs, const char *cname)
422
20.8M
{
423
20.8M
    if (pcs) {
424
10.5M
        rc_decrement_only(pcs, cname);
425
10.5M
    }
426
20.8M
}
427
428
void cs_adjust_counts_icc(gs_gstate *pgs, int delta)
429
36.3M
{
430
36.3M
    gs_color_space *pcs = gs_currentcolorspace_inline(pgs);
431
432
36.3M
    if (pcs) {
433
24.3M
        cs_adjust_color_count(pgs, delta);
434
24.3M
        rc_adjust_const(pcs, delta, "cs_adjust_counts_icc");
435
24.3M
    }
436
36.3M
}
437
438
void cs_adjust_swappedcounts_icc(gs_gstate *pgs, int delta)
439
36.3M
{
440
36.3M
    gs_color_space *pcs = gs_swappedcolorspace_inline(pgs);
441
442
36.3M
    if (pcs) {
443
24.3M
        cs_adjust_swappedcolor_count(pgs, delta);
444
24.3M
        rc_adjust_const(pcs, delta, "cs_adjust_swappedcounts_icc");
445
24.3M
    }
446
36.3M
}
447
448
/* ------ Other implementation procedures ------ */
449
450
/* Null color space installation procedure. */
451
int
452
gx_no_install_cspace(gs_color_space * pcs, gs_gstate * pgs)
453
0
{
454
0
    return 0;
455
0
}
456
457
/* Install a DeviceRGB color space. */
458
static int
459
gx_install_DeviceRGB(gs_color_space * pcs, gs_gstate * pgs)
460
300k
{
461
    /* If we already have profile_data, nothing to do here. */
462
300k
    if (pcs->cmm_icc_profile_data != NULL)
463
0
        return 0;
464
465
    /* If the icc manager hasn't been set up yet, then set it up. */
466
300k
    if (pgs->icc_manager->default_rgb == NULL)
467
0
        gsicc_init_iccmanager(pgs);
468
469
    /* pcs takes a reference to default_rgb */
470
300k
    pcs->cmm_icc_profile_data = pgs->icc_manager->default_rgb;
471
300k
    gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, 1, "gx_install_DeviceRGB");
472
300k
    pcs->type = &gs_color_space_type_ICC;
473
300k
    return 0;
474
300k
}
475
476
/* Install a DeviceCMYK color space. */
477
static int
478
gx_install_DeviceCMYK(gs_color_space * pcs, gs_gstate * pgs)
479
91.8k
{
480
    /* If we already have profile data, nothing to do here. */
481
91.8k
    if (pcs->cmm_icc_profile_data != NULL)
482
0
        return 0;
483
484
    /* If the icc manager hasn't been set up yet, then set it up. */
485
91.8k
    if (pgs->icc_manager->default_cmyk == NULL)
486
0
        gsicc_init_iccmanager(pgs);
487
488
    /* pcs takes a reference to default_cmyk */
489
91.8k
    pcs->cmm_icc_profile_data = pgs->icc_manager->default_cmyk;
490
91.8k
    gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, 1, "gx_install_DeviceCMYK");
491
91.8k
    pcs->type = &gs_color_space_type_ICC;
492
91.8k
    return 0;
493
91.8k
}
494
495
/*
496
 * Communicate to the overprint compositor that this particular
497
 * state overprint is not enabled.  This could be due to a
498
 * mismatched color space, or that overprint is false or the
499
 * device does not support it.
500
 */
501
int
502
gx_set_no_overprint(gs_gstate* pgs)
503
83.9k
{
504
83.9k
    gs_overprint_params_t   params = { 0 };
505
506
83.9k
    params.retain_any_comps = false;
507
83.9k
    params.op_state = OP_STATE_NONE;
508
83.9k
    params.is_fill_color = pgs->is_fill_color;
509
83.9k
    params.effective_opm = pgs->color[0].effective_opm = 0;
510
511
83.9k
    return gs_gstate_update_overprint(pgs, &params);
512
83.9k
}
513
514
/* Retain all the spot colorants and not the process
515
   colorants.  This occurs if we have a process color
516
   mismatch between the source and the destination but
517
   the output device supports spot colors */
518
int
519
gx_set_spot_only_overprint(gs_gstate* pgs)
520
633
{
521
633
    gs_overprint_params_t   params = { 0 };
522
633
    gx_device* dev = pgs->device;
523
633
    gx_color_index drawn_comps = dev == NULL ? 0 : gx_get_process_comps(dev);
524
525
633
    params.retain_any_comps = true;
526
633
    params.op_state = OP_STATE_NONE;
527
633
    params.is_fill_color = pgs->is_fill_color;
528
633
    params.effective_opm = pgs->color[0].effective_opm = 0;
529
633
    params.drawn_comps = drawn_comps;
530
531
633
    return gs_gstate_update_overprint(pgs, &params);
532
633
}
533
534
/*
535
 * Push an overprint compositor onto the current device indicating that,
536
 * at most, the spot color parameters are to be preserved.
537
 *
538
 * This routine should be used for all Device, CIEBased, and ICCBased
539
 * color spaces, except for DeviceCMKY.
540
 */
541
int
542
gx_spot_colors_set_overprint(const gs_color_space * pcs, gs_gstate * pgs)
543
0
{
544
0
    gs_overprint_params_t   params = {0};
545
0
    bool op = pgs->is_fill_color ? pgs->overprint : pgs->stroke_overprint;
546
547
0
    if (!op)
548
0
        params.retain_any_comps = false;
549
0
    else
550
0
        params.retain_any_comps = true;
551
552
0
    params.is_fill_color = pgs->is_fill_color;
553
0
    params.op_state = OP_STATE_NONE;
554
555
    /* Only DeviceCMYK case can have overprint mode set to true */
556
0
    params.effective_opm = pgs->color[0].effective_opm = 0;
557
0
    return gs_gstate_update_overprint(pgs, &params);
558
0
}
559
560
static bool
561
check_single_comp(int comp, frac targ_val, int ncomps, const frac * pval)
562
172
{
563
172
    int     i;
564
565
872
    for (i = 0; i < ncomps; i++) {
566
700
        if ( (i != comp && pval[i] != frac_0)  ||
567
700
             (i == comp && pval[i] != targ_val)  )
568
0
            return false;
569
700
    }
570
172
    return true;
571
172
}
572
573
/*
574
 * Determine if the current color model is a "DeviceCMYK" color model, and
575
 * if so what are its process color components. This information is required
576
 * when PLRM defines special rules for CMYK devices. This includes:
577
 * 1. DeviceGray to CMYK color conversion
578
 * 2. when overprint is true and overprint mode is set to 1.
579
 *
580
 * A color model is considered a "DeviceCMYK" color model if it supports the
581
 * cyan, magenta, yellow, and black color components, and maps the DeviceCMYK
582
 * color model components directly to these color components. Note that this
583
 * does not require any particular component order, allows for additional
584
 * spot color components, and does admit DeviceN color spaces if they have
585
 * the requisite behavior.
586
 *
587
 * If the color model is a "DeviceCMYK" color model, return the set of
588
 * process color components; otherwise return 0.
589
 */
590
gx_color_index
591
check_cmyk_color_model_comps(gx_device * dev)
592
3.58k
{
593
3.58k
    gx_device_color_info *          pcinfo = &dev->color_info;
594
3.58k
    uchar                           ncomps = pcinfo->num_components;
595
3.58k
    int                             cyan_c, magenta_c, yellow_c, black_c;
596
3.58k
    frac                            frac_14 = frac_1 / 4;
597
3.58k
    frac                            out[GX_DEVICE_COLOR_MAX_COMPONENTS];
598
3.58k
    gx_color_index                  process_comps;
599
3.58k
    const gx_cm_color_map_procs    *cmprocs;
600
3.58k
    const gx_device                *cmdev;
601
602
603
3.58k
    if (pcinfo->num_components < 4                     ||
604
3.58k
        pcinfo->polarity == GX_CINFO_POLARITY_ADDITIVE ||
605
3.58k
        pcinfo->gray_index == GX_CINFO_COMP_NO_INDEX) {
606
3.54k
        pcinfo->opmsupported = GX_CINFO_OPMSUPPORTED_NOT;
607
3.54k
        return 0;
608
3.54k
    }
609
610
    /* check for the appropriate components */
611
43
    if ( ncomps < 4                                       ||
612
43
         (cyan_c = dev_proc(dev, get_color_comp_index)(
613
43
                       dev,
614
43
                       "Cyan",
615
43
                       sizeof("Cyan") - 1,
616
43
                       NO_COMP_NAME_TYPE_OP)) < 0           ||
617
43
         cyan_c == GX_DEVICE_COLOR_MAX_COMPONENTS         ||
618
43
         (magenta_c = dev_proc(dev, get_color_comp_index)(
619
43
                          dev,
620
43
                          "Magenta",
621
43
                          sizeof("Magenta") - 1,
622
43
                          NO_COMP_NAME_TYPE_OP)) < 0        ||
623
43
         magenta_c == GX_DEVICE_COLOR_MAX_COMPONENTS      ||
624
43
         (yellow_c = dev_proc(dev, get_color_comp_index)(
625
43
                        dev,
626
43
                        "Yellow",
627
43
                        sizeof("Yellow") - 1,
628
43
                        NO_COMP_NAME_TYPE_OP)) < 0               ||
629
43
         yellow_c == GX_DEVICE_COLOR_MAX_COMPONENTS       ||
630
43
         (black_c = dev_proc(dev, get_color_comp_index)(
631
43
                        dev,
632
43
                        "Black",
633
43
                        sizeof("Black") - 1,
634
43
                        NO_COMP_NAME_TYPE_OP)) < 0                         ||
635
43
         black_c == GX_DEVICE_COLOR_MAX_COMPONENTS          )
636
0
        return 0;
637
638
    /* check the mapping */
639
43
    cmprocs = dev_proc(dev, get_color_mapping_procs)(dev, &cmdev);
640
641
43
    cmprocs->map_cmyk(cmdev, frac_14, frac_0, frac_0, frac_0, out);
642
43
    if (!check_single_comp(cyan_c, frac_14, ncomps, out)) {
643
0
        pcinfo->opmsupported = GX_CINFO_OPMSUPPORTED_NOT;
644
0
        return 0;
645
0
    }
646
43
    cmprocs->map_cmyk(cmdev, frac_0, frac_14, frac_0, frac_0, out);
647
43
    if (!check_single_comp(magenta_c, frac_14, ncomps, out)) {
648
0
        pcinfo->opmsupported = GX_CINFO_OPMSUPPORTED_NOT;
649
0
        return 0;
650
0
    }
651
43
    cmprocs->map_cmyk(cmdev, frac_0, frac_0, frac_14, frac_0, out);
652
43
    if (!check_single_comp(yellow_c, frac_14, ncomps, out)) {
653
0
        pcinfo->opmsupported = GX_CINFO_OPMSUPPORTED_NOT;
654
0
        return 0;
655
0
    }
656
43
    cmprocs->map_cmyk(cmdev, frac_0, frac_0, frac_0, frac_14, out);
657
43
    if (!check_single_comp(black_c, frac_14, ncomps, out)) {
658
0
        pcinfo->opmsupported = GX_CINFO_OPMSUPPORTED_NOT;
659
0
        return 0;
660
0
    }
661
662
43
    process_comps =  ((gx_color_index)1 << cyan_c)
663
43
                   | ((gx_color_index)1 << magenta_c)
664
43
                   | ((gx_color_index)1 << yellow_c)
665
43
                   | ((gx_color_index)1 << black_c);
666
43
    pcinfo->opmsupported = GX_CINFO_OPMSUPPORTED;
667
43
    pcinfo->process_comps = process_comps;
668
43
    pcinfo->black_component = black_c;
669
43
    return process_comps;
670
43
}
671
672
/*
673
 * This set_overprint method is unique. If overprint is true, overprint
674
 * mode is set to 1, the process color model has DeviceCMYK behavior (see
675
 * the comment ahead of gx_is_cmyk_color_model above), and the device
676
 * color is set, the device color needs to be considered in setting up
677
 * the set of drawn components.
678
 */
679
static int
680
gx_set_overprint_DeviceCMYK(const gs_color_space * pcs, gs_gstate * pgs)
681
0
{
682
0
    gx_device *             dev = pgs->device;
683
0
    gx_device_color_info *  pcinfo = (dev == 0 ? 0 : &dev->color_info);
684
685
    /* check if we require special handling */
686
0
    if ( !pgs->overprint                      ||
687
0
         pgs->overprint_mode != 1             ||
688
0
         pcinfo == 0                          ||
689
0
         pcinfo->opmsupported == GX_CINFO_OPMSUPPORTED_NOT)
690
0
        return gx_spot_colors_set_overprint(pcs, pgs);
691
    /* Share code with CMYK ICC case */
692
0
    return gx_set_overprint_cmyk(pcs, pgs);
693
0
}
694
695
/* A few comments about ICC profiles and overprint simulation.  In order
696
   to do proper overprint simulation, the source ICC profile and the
697
   destination ICC profile must be the same.  If they are not, then
698
   we end up mapping the source CMYK data to a different CMYK value.  In
699
   this case, the non-zero components, which with overprint mode = 1 specify
700
   which are to be overprinted will not be correct to produce the proper
701
   overprint simulation.  This is seen with AR when doing output preview,
702
   overprint simulation enabled of the file overprint_icc.pdf (see our
703
   test files) which has SWOP ICC based CMYK fills.  In AR, if we use a
704
   simulation ICC profile that is different than the source profile,
705
   overprinting is no longer previewed. We follow the same logic here.
706
   If the source and destination ICC profiles do not match, then there is
707
   effectively no overprinting enabled.  This is bug 692433.  However,
708
   even with the mismatch, if the device supports spot colorants, those
709
   colors should be maintained. This is bug 702725. */
710
int gx_set_overprint_cmyk(const gs_color_space * pcs, gs_gstate * pgs)
711
249
{
712
249
    gx_device *             dev = pgs->device;
713
249
    gx_color_index          drawn_comps = 0;
714
249
    gs_overprint_params_t   params = { 0 };
715
249
    gx_device_color        *pdc;
716
249
    cmm_dev_profile_t      *dev_profile;
717
249
    cmm_profile_t          *output_profile = 0;
718
249
    int                     code;
719
249
    bool                    profile_ok = false;
720
249
    gsicc_rendering_param_t        render_cond;
721
249
    bool                    eop;
722
723
249
    if_debug0m(gs_debug_flag_overprint, pgs->memory,
724
249
        "[overprint] gx_set_overprint_cmyk\n");
725
726
249
    if (dev) {
727
249
        code = dev_proc(dev, get_profile)(dev, &dev_profile);
728
249
        if (code < 0)
729
0
            return code;
730
731
249
        gsicc_extract_profile(dev->graphics_type_tag, dev_profile, &(output_profile),
732
249
                              &render_cond);
733
734
249
        drawn_comps = gx_get_process_comps(dev);
735
249
    }
736
737
249
    if_debug1m(gs_debug_flag_overprint, pgs->memory,
738
249
        "[overprint] gx_set_overprint_cmyk. drawn_comps = 0x%x\n", (uint)drawn_comps);
739
740
249
    if (drawn_comps == 0)
741
0
        return gx_spot_colors_set_overprint(pcs, pgs);
742
743
    /* correct for any zero'ed color components.  But only if profiles
744
       match AND pgs->overprint_mode is true */
745
249
    if (pcs->cmm_icc_profile_data != NULL && output_profile != NULL) {
746
249
        if (gsicc_profiles_equal(output_profile, pcs->cmm_icc_profile_data)) {
747
249
            profile_ok = true;
748
249
        }
749
249
    }
750
751
249
    eop = gs_currentcolor_eopm(pgs);
752
753
249
    if_debug3m(gs_debug_flag_overprint, pgs->memory,
754
249
        "[overprint] gx_set_overprint_cmyk. is_fill_color = %d, pgs->color[0].effective_opm = %d pgs->color[1].effective_opm = %d\n",
755
249
        pgs->is_fill_color, pgs->color[0].effective_opm, pgs->color[1].effective_opm);
756
757
249
    if (profile_ok && eop) {
758
93
        gx_color_index  nz_comps, one, temp;
759
93
        int             code;
760
93
        int             num_colorant[4], k;
761
93
        bool            colorant_ok;
762
93
        dev_color_proc_get_nonzero_comps((*procp));
763
764
93
        if_debug0m(gs_debug_flag_overprint, pgs->memory,
765
93
            "[overprint] gx_set_overprint_cmyk. color_is_set, profile_ok and eop\n");
766
767
93
        code = gx_set_dev_color(pgs);
768
93
        if (code < 0)
769
0
            return code;
770
93
        pdc = gs_currentdevicecolor_inline(pgs);
771
93
        procp = pdc->type->get_nonzero_comps;
772
93
        if (pdc->ccolor_valid) {
773
            /* If we have the source colors, then use those in making the
774
               decision as to which ones are non-zero.  Then we avoid
775
               accidently looking at small values that get quantized to zero
776
               Note that to get here in the code, the source color data color
777
               space has to be CMYK. Trick is that we do need to worry about
778
               the colorant order on the target device */
779
93
            num_colorant[0] = (dev_proc(dev, get_color_comp_index))\
780
93
                             (dev, "Cyan", strlen("Cyan"), NO_COMP_NAME_TYPE_OP);
781
93
            num_colorant[1] = (dev_proc(dev, get_color_comp_index))\
782
93
                             (dev, "Magenta", strlen("Magenta"), NO_COMP_NAME_TYPE_OP);
783
93
            num_colorant[2] = (dev_proc(dev, get_color_comp_index))\
784
93
                             (dev, "Yellow", strlen("Yellow"), NO_COMP_NAME_TYPE_OP);
785
93
            num_colorant[3] = (dev_proc(dev, get_color_comp_index))\
786
93
                             (dev, "Black", strlen("Black"), NO_COMP_NAME_TYPE_OP);
787
93
            nz_comps = 0;
788
93
            one = 1;
789
93
            colorant_ok = true;
790
465
            for (k = 0; k < 4; k++) {
791
                /* Note: AR assumes the value is zero if it
792
                   is less than 0.5 out of 255 */
793
372
                if (pdc->ccolor.paint.values[k] > (0.5 / 255.0)) {
794
93
                    if (num_colorant[k] == -1) {
795
0
                        colorant_ok = false;
796
93
                    } else {
797
93
                        temp = one << num_colorant[k];
798
93
                        nz_comps = nz_comps | temp;
799
93
                    }
800
93
                }
801
372
            }
802
            /* For some reason we don't have one of the standard colorants */
803
93
            if (!colorant_ok) {
804
0
                if ((code = procp(pdc, dev, &nz_comps)) < 0)
805
0
                    return code;
806
0
            }
807
93
        } else {
808
0
            if ((code = procp(pdc, dev, &nz_comps)) < 0)
809
0
                return code;
810
0
        }
811
93
        drawn_comps &= nz_comps;
812
93
    }
813
249
    params.is_fill_color = pgs->is_fill_color;
814
249
    params.retain_any_comps = true;
815
249
    params.drawn_comps = drawn_comps;
816
249
    params.op_state = OP_STATE_NONE;
817
818
249
    if_debug2m(gs_debug_flag_overprint, pgs->memory,
819
249
        "[overprint] gx_set_overprint_cmyk. retain_any_comps = %d, drawn_comps = 0x%x\n",
820
249
        params.retain_any_comps, (uint)(params.drawn_comps));
821
822
    /* We are in CMYK, the profiles match and overprint is true.  Set effective
823
       overprint mode to overprint mode but only if effective has not already
824
       been set to 0 */
825
249
    params.effective_opm = pgs->color[0].effective_opm =
826
249
        pgs->overprint_mode && gs_currentcolor_eopm(pgs);
827
249
    return gs_gstate_update_overprint(pgs, &params);
828
249
}
829
830
/* A stub for a color mapping linearity check, when it is inapplicable. */
831
int
832
gx_cspace_no_linear(const gs_color_space *cs, const gs_gstate * pgs,
833
                gx_device * dev,
834
                const gs_client_color *c0, const gs_client_color *c1,
835
                const gs_client_color *c2, const gs_client_color *c3,
836
                float smoothness, gsicc_link_t *icclink)
837
0
{
838
0
    return_error(gs_error_rangecheck);
839
0
}
840
841
static inline int
842
cc2dc(const gs_color_space *cs, const gs_gstate * pgs, gx_device *dev,
843
            gx_device_color *dc, const gs_client_color *cc)
844
91.8k
{
845
91.8k
    return cs->type->remap_color(cc, cs, dc, pgs, dev, gs_color_select_texture);
846
91.8k
}
847
848
static inline void
849
interpolate_cc(gs_client_color *c,
850
        const gs_client_color *c0, const gs_client_color *c1, double t, int n)
851
47.9k
{
852
47.9k
    int i;
853
854
96.1k
    for (i = 0; i < n; i++)
855
48.2k
        c->paint.values[i] = c0->paint.values[i] * t + c1->paint.values[i] * (1 - t);
856
47.9k
}
857
858
static inline bool
859
is_dc_nearly_linear(const gx_device *dev, const gx_device_color *c,
860
        const gx_device_color *c0, const gx_device_color *c1,
861
        double t, uchar n, float smoothness)
862
47.9k
{
863
47.9k
    uchar i;
864
865
47.9k
    if (c0->type == &gx_dc_type_data_pure) {
866
31.1k
        gx_color_index pure0 = c0->colors.pure;
867
31.1k
        gx_color_index pure1 = c1->colors.pure;
868
31.1k
        gx_color_index pure = c->colors.pure;
869
870
151k
        for (i = 0; i < n; i++) {
871
120k
            int shift = dev->color_info.comp_shift[i];
872
120k
            int mask = (1 << dev->color_info.comp_bits[i]) - 1;
873
120k
            int max_color = (i == dev->color_info.gray_index ? dev->color_info.max_gray
874
120k
                                                             : dev->color_info.max_color);
875
120k
            float max_diff = max(1, max_color * smoothness);
876
120k
            int b0 = (pure0 >> shift) & mask, b1 = (pure1 >> shift) & mask;
877
120k
            int b = (pure >> shift) & mask;
878
120k
            double bb = b0 * t + b1 * (1 - t);
879
880
120k
            if (any_abs(b - bb) > max_diff)
881
0
                return false;
882
120k
        }
883
31.1k
        return true;
884
31.1k
    } else if (c0->type == &gx_dc_type_data_devn) {
885
83.9k
        for (i = 0; i < n; i++) {
886
67.1k
            int max_color = (i == dev->color_info.gray_index ? dev->color_info.max_gray
887
67.1k
                : dev->color_info.max_color);
888
67.1k
            double max_diff = max(1, max_color * smoothness);
889
            /* Color values are 16 bit.  We are basing the smoothness on the
890
               device bit depth.  So make sure to adjust the above max diff
891
               based upon our device bit depth */
892
67.1k
            double ratio = (double)max_color / (double)gx_max_color_value;
893
67.1k
            double b0 = (c0->colors.devn.values[i]) * ratio;
894
67.1k
            double b1 = (c1->colors.devn.values[i]) * ratio;
895
67.1k
            double b = (c->colors.devn.values[i]) * ratio;
896
67.1k
            double bb = b0 * t + b1 * (1 - t);
897
67.1k
            if (any_abs(b - bb) > max_diff)
898
0
                return false;
899
67.1k
        }
900
16.7k
        return true;
901
16.7k
    } else {
902
        /* Halftones must not paint with fill_linear_color_*. */
903
0
        return false;
904
0
    }
905
47.9k
}
906
907
/* Default color mapping linearity check, a 2-points case. */
908
static int
909
gx_cspace_is_linear_in_line(const gs_color_space *cs, const gs_gstate * pgs,
910
                gx_device *dev,
911
                const gs_client_color *c0, const gs_client_color *c1,
912
                float smoothness)
913
16.0k
{
914
16.0k
    gs_client_color c01a, c01b;
915
16.0k
    gx_device_color d[2], d01a, d01b;
916
16.0k
    int n = cs->type->num_components(cs);
917
16.0k
    uchar ndev = dev->color_info.num_components;
918
16.0k
    int code;
919
920
16.0k
    code = cc2dc(cs, pgs, dev, &d[0], c0);
921
16.0k
    if (code < 0)
922
0
        return code;
923
16.0k
    code = cc2dc(cs, pgs, dev, &d[1], c1);
924
16.0k
    if (code < 0)
925
0
        return code;
926
16.0k
    interpolate_cc(&c01a, c0, c1, 0.3, n);
927
16.0k
    code = cc2dc(cs, pgs, dev, &d01a, &c01a);
928
16.0k
    if (code < 0)
929
0
        return code;
930
16.0k
    if (!is_dc_nearly_linear(dev, &d01a, &d[0], &d[1], 0.3, ndev, smoothness))
931
0
        return 0;
932
16.0k
    interpolate_cc(&c01b, c0, c1, 0.7, n);
933
16.0k
    code = cc2dc(cs, pgs, dev, &d01b, &c01b);
934
16.0k
    if (code < 0)
935
0
        return code;
936
16.0k
    if (!is_dc_nearly_linear(dev, &d01b, &d[0], &d[1], 0.7, ndev, smoothness))
937
0
        return 0;
938
16.0k
    return 1;
939
16.0k
}
940
941
/* Default color mapping linearity check, a triangle case. */
942
static int
943
gx_cspace_is_linear_in_triangle(const gs_color_space *cs, const gs_gstate * pgs,
944
                gx_device *dev,
945
                const gs_client_color *c0, const gs_client_color *c1,
946
                const gs_client_color *c2, float smoothness)
947
3.97k
{
948
    /* We check 4 points - the median center, and middle points of 3 sides.
949
       Hopely this is enough for reasonable color spaces and color renderings.
950
       Note it gives 7 points for a quadrangle. */
951
3.97k
    gs_client_color c01, c12, c20, c012;
952
3.97k
    gx_device_color d[3], d01, d12, d20, d012;
953
954
    /* Note that the device and the client color space
955
       can have a different number of components */
956
957
3.97k
    int n = cs->type->num_components(cs);
958
3.97k
    uchar ndev = dev->color_info.num_components;
959
960
3.97k
    int code;
961
962
3.97k
    code = cc2dc(cs, pgs, dev, &d[0], c0);
963
3.97k
    if (code < 0)
964
0
        return code;
965
3.97k
    code = cc2dc(cs, pgs, dev, &d[1], c1);
966
3.97k
    if (code < 0)
967
0
        return code;
968
3.97k
    code = cc2dc(cs, pgs, dev, &d[2], c2);
969
3.97k
    if (code < 0)
970
0
        return code;
971
972
3.97k
    interpolate_cc(&c01, c0, c1, 0.5, n);
973
3.97k
    code = cc2dc(cs, pgs, dev, &d01, &c01);
974
3.97k
    if (code < 0)
975
0
        return code;
976
3.97k
    if (!is_dc_nearly_linear(dev, &d01, &d[0], &d[1], 0.5, ndev, smoothness))
977
0
        return 0;
978
979
3.97k
    interpolate_cc(&c012, c2, &c01, 2.0 / 3, n);
980
3.97k
    code = cc2dc(cs, pgs, dev, &d012, &c012);
981
3.97k
    if (code < 0)
982
0
        return code;
983
3.97k
    if (!is_dc_nearly_linear(dev, &d012, &d[2], &d01, 2.0 / 3, ndev, smoothness))
984
0
        return 0;
985
986
3.97k
    interpolate_cc(&c12, c1, c2, 0.5, n);
987
3.97k
    code = cc2dc(cs, pgs, dev, &d12, &c12);
988
3.97k
    if (code < 0)
989
0
        return code;
990
3.97k
    if (!is_dc_nearly_linear(dev, &d12, &d[1], &d[2], 0.5, ndev, smoothness))
991
0
        return 0;
992
993
3.97k
    interpolate_cc(&c20, c2, c0, 0.5, n);
994
3.97k
    code = cc2dc(cs, pgs, dev, &d20, &c20);
995
3.97k
    if (code < 0)
996
0
        return code;
997
3.97k
    if (!is_dc_nearly_linear(dev, &d20, &d[2], &d[0], 0.5, ndev, smoothness))
998
0
        return 0;
999
3.97k
    return 1;
1000
3.97k
}
1001
1002
/* Default color mapping linearity check. */
1003
int
1004
gx_cspace_is_linear_default(const gs_color_space *cs, const gs_gstate * pgs,
1005
                gx_device *dev,
1006
                const gs_client_color *c0, const gs_client_color *c1,
1007
                const gs_client_color *c2, const gs_client_color *c3,
1008
                float smoothness, gsicc_link_t *icclink)
1009
19.9k
{
1010
    /* Assuming 2 <= nc <= 4. We don't need other cases. */
1011
    /* With nc == 4 assuming a convex plain quadrangle in the client color space. */
1012
19.9k
    int code;
1013
1014
19.9k
    if (!colors_are_separable_and_linear(&dev->color_info))
1015
0
        return_error(gs_error_rangecheck);
1016
19.9k
    if (c2 == NULL)
1017
16.0k
        return gx_cspace_is_linear_in_line(cs, pgs, dev, c0, c1, smoothness);
1018
3.97k
    code = gx_cspace_is_linear_in_triangle(cs, pgs, dev, c0, c1, c2, smoothness);
1019
3.97k
    if (code <= 0)
1020
0
        return code;
1021
3.97k
    if (c3 == NULL)
1022
3.97k
        return 1;
1023
0
    return gx_cspace_is_linear_in_triangle(cs, pgs, dev, c1, c2, c3, smoothness);
1024
3.97k
}
1025
1026
/* Serialization. */
1027
int
1028
gx_serialize_cspace_type(const gs_color_space * pcs, stream * s)
1029
40.7k
{
1030
40.7k
    const gs_color_space_type * type = pcs->type;
1031
40.7k
    uint n;
1032
40.7k
    return sputs(s, (const byte *)&type->index, sizeof(type->index), &n);
1033
40.7k
}
1034
1035
/* GC procedures */
1036
1037
static
1038
ENUM_PTRS_BEGIN_PROC(color_space_enum_ptrs)
1039
4.62M
{
1040
4.62M
    EV_CONST gs_color_space *pcs = vptr;
1041
1042
4.62M
    if (index == 0)
1043
924k
        return ENUM_OBJ(pcs->base_space);
1044
3.69M
    if (index == 1)
1045
924k
        return ENUM_OBJ(pcs->pclient_color_space_data);
1046
2.77M
    if (index == 2)
1047
924k
        return ENUM_OBJ(pcs->icc_equivalent);
1048
1.84M
    if (index == 3)
1049
924k
        return ENUM_OBJ(pcs->params.device_n.devn_process_space);
1050
924k
    return ENUM_USING(*pcs->type->stype, vptr, size, index - 4);
1051
1.84M
    ENUM_PTRS_END_PROC
1052
1.84M
}
1053
static
1054
924k
RELOC_PTRS_WITH(color_space_reloc_ptrs, gs_color_space *pcs)
1055
924k
{
1056
924k
    RELOC_VAR(pcs->base_space);
1057
924k
    RELOC_VAR(pcs->pclient_color_space_data);
1058
924k
    RELOC_VAR(pcs->icc_equivalent);
1059
924k
    RELOC_VAR(pcs->params.device_n.devn_process_space);
1060
924k
    RELOC_USING(*pcs->type->stype, vptr, size);
1061
924k
}
1062
924k
RELOC_PTRS_END