Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gscsepr.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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
/* Separation color space and operation definition */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gsfunc.h"
22
#include "gsrefct.h"
23
#include "gsmatrix.h"   /* for gscolor2.h */
24
#include "gscsepr.h"
25
#include "gxcspace.h"
26
#include "gxfixed.h"    /* for gxcolor2.h */
27
#include "gxcolor2.h"   /* for gs_indexed_map */
28
#include "gzstate.h"    /* for pgs->overprint */
29
#include "gscdevn.h"    /* for alloc_device_n_map */
30
#include "gxcdevn.h"    /* for gs_device_n_map_s */
31
#include "gxcmap.h"
32
#include "gxdevcli.h"
33
#include "gsovrc.h"
34
#include "stream.h"
35
#include "gsicc_cache.h"
36
#include "gxdevice.h"
37
#include "gxcie.h"
38
#include "gxdevsop.h"
39
40
/* ---------------- Color space ---------------- */
41
42
gs_private_st_composite(st_color_space_Separation, gs_color_space,
43
                        "gs_color_space_Separation",
44
                        cs_Separation_enum_ptrs, cs_Separation_reloc_ptrs);
45
46
/* Define the Separation color space type. */
47
static cs_proc_init_color(gx_init_Separation);
48
static cs_proc_concrete_space(gx_concrete_space_Separation);
49
static cs_proc_concretize_color(gx_concretize_Separation);
50
static cs_proc_remap_concrete_color(gx_remap_concrete_Separation);
51
static cs_proc_remap_color(gx_remap_Separation);
52
static cs_proc_install_cspace(gx_install_Separation);
53
static cs_proc_set_overprint(gx_set_overprint_Separation);
54
static cs_proc_final(gx_final_Separation);
55
static cs_proc_serialize(gx_serialize_Separation);
56
const gs_color_space_type gs_color_space_type_Separation = {
57
    gs_color_space_index_Separation, true, false,
58
    &st_color_space_Separation, gx_num_components_1,
59
    gx_init_Separation, gx_restrict01_paint_1,
60
    gx_concrete_space_Separation,
61
    gx_concretize_Separation, gx_remap_concrete_Separation,
62
    gx_remap_Separation, gx_install_Separation,
63
    gx_set_overprint_Separation,
64
    gx_final_Separation, gx_no_adjust_color_count,
65
    gx_serialize_Separation,
66
    gx_cspace_is_linear_default, gx_polarity_subtractive
67
};
68
69
/* GC procedures */
70
71
static
72
312
ENUM_PTRS_BEGIN(cs_Separation_enum_ptrs) return 0;
73
312
    ENUM_PTR(0, gs_color_space, params.separation.map);
74
312
ENUM_PTRS_END
75
156
static RELOC_PTRS_BEGIN(cs_Separation_reloc_ptrs)
76
156
{
77
156
    RELOC_PTR(gs_color_space, params.separation.map);
78
156
}
79
156
RELOC_PTRS_END
80
81
/* Get the concrete space for a Separation space. */
82
static const gs_color_space *
83
gx_concrete_space_Separation(const gs_color_space * pcs,
84
                             const gs_gstate * pgs)
85
89.9k
{
86
89.9k
    bool is_lab = false;
87
#ifdef DEBUG
88
    /*
89
     * Verify that the color space and gs_gstate info match.
90
     */
91
    if (pcs->id != pgs->color_component_map.cspace_id)
92
        dmprintf(pgs->memory, "gx_concretze_space_Separation: color space id mismatch");
93
#endif
94
95
    /*
96
     * Check if we are using the alternate color space.
97
     */
98
89.9k
    if (pgs->color_component_map.use_alt_cspace) {
99
        /* Need to handle PS CIE space */
100
85.3k
        if (gs_color_space_is_PSCIE(pcs->base_space)) {
101
0
            if (pcs->base_space->icc_equivalent == NULL) {
102
0
                (void)gs_colorspace_set_icc_equivalent(pcs->base_space,
103
0
                                                    &is_lab, pgs->memory);
104
0
            }
105
0
            return (pcs->base_space->icc_equivalent);
106
0
        }
107
85.3k
        return cs_concrete_space(pcs->base_space, pgs);
108
85.3k
    }
109
    /*
110
     * Separation color spaces are concrete (when not using alt. color space).
111
     */
112
4.56k
    return pcs;
113
89.9k
}
114
115
static int
116
check_Separation_component_name(const gs_color_space * pcs, gs_gstate * pgs);
117
118
/* Check if the colorant is a process colorant */
119
static separation_colors
120
gx_check_process_names_Separation(gs_color_space * pcs, gs_gstate * pgs)
121
14.0k
{
122
14.0k
    byte *pname = (byte *)pcs->params.separation.sep_name;
123
14.0k
    uint name_size = strlen(pcs->params.separation.sep_name);
124
125
    /* Classify */
126
14.0k
    if (strncmp((char *)pname, "None", name_size) == 0 ||
127
14.0k
        strncmp((char *)pname, "All", name_size) == 0) {
128
1
        return SEP_ENUM;
129
14.0k
    } else {
130
14.0k
        if (strncmp((char *)pname, "Cyan", name_size) == 0 ||
131
14.0k
            strncmp((char *)pname, "Magenta", name_size) == 0 ||
132
14.0k
            strncmp((char *)pname, "Yellow", name_size) == 0 ||
133
14.0k
            strncmp((char *)pname, "Black", name_size) == 0) {
134
7.97k
            return SEP_PURE_CMYK;
135
7.97k
        } else if (strncmp((char *)pname, "Red", name_size) == 0 ||
136
6.05k
            strncmp((char *)pname, "Green", name_size) == 0 ||
137
6.05k
            strncmp((char *)pname, "Blue", name_size) == 0) {
138
0
            return SEP_PURE_RGB;
139
6.05k
        } else {
140
6.05k
            return SEP_MIX;
141
6.05k
        }
142
14.0k
    }
143
14.0k
}
144
145
/* Install a Separation color space. */
146
static int
147
gx_install_Separation(gs_color_space * pcs, gs_gstate * pgs)
148
14.0k
{
149
14.0k
    int code;
150
151
14.0k
    code = check_Separation_component_name(pcs, pgs);
152
14.0k
    if (code < 0)
153
0
       return code;
154
155
14.0k
    if (pgs->icc_manager->device_named != NULL) {
156
0
        pcs->params.separation.named_color_supported =
157
0
            gsicc_support_named_color(pcs, pgs);
158
0
    }
159
160
14.0k
    pcs->params.separation.color_type =
161
14.0k
        gx_check_process_names_Separation(pcs, pgs);
162
163
14.0k
    gs_currentcolorspace_inline(pgs)->params.separation.use_alt_cspace =
164
14.0k
        using_alt_color_space(pgs);
165
14.0k
    if (gs_currentcolorspace_inline(pgs)->params.separation.use_alt_cspace) {
166
11.0k
        code = (pcs->base_space->type->install_cspace)
167
11.0k
            (pcs->base_space, pgs);
168
11.0k
    } else {
169
        /*
170
         * Give the device an opportunity to capture equivalent colors for any
171
         * spot colors which might be present in the color space.
172
         */
173
2.95k
        if (dev_proc(pgs->device, update_spot_equivalent_colors))
174
2.95k
           code = dev_proc(pgs->device, update_spot_equivalent_colors)
175
2.95k
                                                        (pgs->device, pgs, pcs);
176
2.95k
    }
177
14.0k
    return code;
178
14.0k
}
179
180
/* Set the overprint information appropriate to a separation color space */
181
static int
182
gx_set_overprint_Separation(const gs_color_space * pcs, gs_gstate * pgs)
183
16.7k
{
184
16.7k
    gs_devicen_color_map *  pcmap = &pgs->color_component_map;
185
186
16.7k
    if (pcmap->use_alt_cspace)
187
110
        return gx_set_no_overprint(pgs);
188
16.6k
    else {
189
16.6k
        gs_overprint_params_t params = { 0 };
190
191
16.6k
        params.retain_any_comps = (((pgs->overprint && pgs->is_fill_color) ||
192
16.6k
                                   (pgs->stroke_overprint && !pgs->is_fill_color)) &&
193
16.6k
                                   (pcs->params.separation.sep_type != SEP_ALL));
194
16.6k
        params.is_fill_color = pgs->is_fill_color;
195
16.6k
        params.drawn_comps = 0;
196
16.6k
        params.op_state = OP_STATE_NONE;
197
16.6k
        if (params.retain_any_comps) {
198
40
            if (pcs->params.separation.sep_type != SEP_NONE) {
199
40
                int mcomp = pcmap->color_map[0];
200
201
40
                if (mcomp >= 0)
202
40
                    gs_overprint_set_drawn_comp( params.drawn_comps, mcomp);
203
40
            }
204
40
        }
205
        /* Only DeviceCMYK can use overprint mode */
206
16.6k
        params.effective_opm = pgs->color[0].effective_opm = 0;
207
16.6k
        return gs_gstate_update_overprint(pgs, &params);
208
16.6k
    }
209
16.7k
}
210
211
/* Finalize contents of a Separation color space. */
212
static void
213
gx_final_Separation(gs_color_space * pcs)
214
13.9k
{
215
13.9k
    rc_adjust_const(pcs->params.separation.map, -1,
216
13.9k
                    "gx_adjust_Separation");
217
13.9k
    pcs->params.separation.map = NULL;
218
13.9k
    gs_free_object(pcs->params.separation.mem, pcs->params.separation.sep_name, "gx_final_Separation");
219
13.9k
    pcs->params.separation.sep_name = NULL;
220
13.9k
}
221
222
/* ------ Constructors/accessors ------ */
223
224
/*
225
 * Construct a new separation color space.
226
 */
227
int
228
gs_cspace_new_Separation(
229
    gs_color_space **ppcs,
230
    gs_color_space * palt_cspace,
231
    gs_memory_t * pmem
232
)
233
13.9k
{
234
13.9k
    gs_color_space *pcs;
235
13.9k
    int code;
236
237
13.9k
    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
238
0
        return_error(gs_error_rangecheck);
239
240
13.9k
    pcs = gs_cspace_alloc(pmem, &gs_color_space_type_Separation);
241
13.9k
    if (pcs == NULL)
242
0
        return_error(gs_error_VMerror);
243
13.9k
    pcs->params.separation.map = NULL;
244
13.9k
    pcs->params.separation.named_color_supported = false;
245
246
13.9k
    code = alloc_device_n_map(&pcs->params.separation.map, pmem,
247
13.9k
                              "gs_cspace_build_Separation");
248
13.9k
    if (code < 0) {
249
0
        gs_free_object(pmem, pcs, "gs_cspace_build_Separation");
250
0
        return_error(code);
251
0
    }
252
13.9k
    pcs->base_space = palt_cspace;
253
13.9k
    rc_increment_cs(palt_cspace);
254
13.9k
    *ppcs = pcs;
255
13.9k
    return 0;
256
13.9k
}
257
258
#if 0 /* Unused; Unsupported by gx_serialize_device_n_map. */
259
/*
260
 * Set the tint transformation procedure used by a Separation color space.
261
 */
262
int
263
gs_cspace_set_sepr_proc(gs_color_space * pcspace,
264
                        int (*proc)(const float *,
265
                                    float *,
266
                                    const gs_gstate *,
267
                                    void *
268
                                    ),
269
                        void *proc_data
270
                        )
271
{
272
    gs_device_n_map *pimap;
273
274
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation)
275
        return_error(gs_error_rangecheck);
276
    pimap = pcspace->params.separation.map;
277
    pimap->tint_transform = proc;
278
    pimap->tint_transform_data = proc_data;
279
    pimap->cache_valid = false;
280
281
    return 0;
282
}
283
#endif
284
285
/*
286
 * Set the Separation tint transformation procedure to a Function.
287
 */
288
int
289
gs_cspace_set_sepr_function(const gs_color_space *pcspace, gs_function_t *pfn)
290
13.9k
{
291
13.9k
    gs_device_n_map *pimap;
292
293
13.9k
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation ||
294
13.9k
        pfn->params.m != 1 || pfn->params.n !=
295
13.9k
          gs_color_space_num_components(pcspace->base_space)
296
13.9k
        )
297
0
        return_error(gs_error_rangecheck);
298
13.9k
    pimap = pcspace->params.separation.map;
299
13.9k
    pimap->tint_transform = map_devn_using_function;
300
13.9k
    pimap->tint_transform_data = pfn;
301
13.9k
    pimap->cache_valid = false;
302
13.9k
    return 0;
303
13.9k
}
304
305
/*
306
 * If the Separation tint transformation procedure is a Function,
307
 * return the function object, otherwise return 0.
308
 */
309
gs_function_t *
310
gs_cspace_get_sepr_function(const gs_color_space *pcspace)
311
12.9k
{
312
12.9k
    if (gs_color_space_get_index(pcspace) == gs_color_space_index_Separation &&
313
12.9k
        pcspace->params.separation.map->tint_transform ==
314
12.9k
          map_devn_using_function)
315
12.9k
        return pcspace->params.separation.map->tint_transform_data;
316
0
    return 0;
317
12.9k
}
318
319
/* ------ Internal procedures ------ */
320
321
/* Initialize a Separation color. */
322
static void
323
gx_init_Separation(gs_client_color * pcc, const gs_color_space * pcs)
324
16.8k
{
325
16.8k
    pcc->paint.values[0] = 1.0;
326
16.8k
}
327
328
/* Remap a Separation color. */
329
330
static int
331
gx_remap_Separation(const gs_client_color * pcc, const gs_color_space * pcs,
332
        gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
333
                       gs_color_select_t select)
334
90.1k
{
335
90.1k
    int code = 0;
336
90.1k
    bool mapped = false;
337
338
90.1k
    if (pcs->params.separation.sep_type != SEP_NONE) {
339
        /* First see if we want to do a direct remap with a named color table.
340
           Note that this call occurs regardless of the alt color space boolean
341
           value.  A decision can be made in gsicc_transform_named_color to
342
           return false if you don't want those named colors to be mapped */
343
90.1k
        if (pcs->params.separation.sep_type == SEP_OTHER &&
344
90.1k
            pgs->icc_manager->device_named != NULL) {
345
            /* Try to apply the direct replacement */
346
0
            mapped = gx_remap_named_color(pcc, pcs, pdc, pgs, dev, select);
347
0
        }
348
90.1k
        if (!mapped)
349
90.1k
            code = gx_default_remap_color(pcc, pcs, pdc, pgs, dev, select);
350
90.1k
    } else {
351
0
        color_set_null(pdc);
352
0
    }
353
    /* Save original color space and color info into dev color */
354
90.1k
    pdc->ccolor.paint.values[0] = pcc->paint.values[0];
355
90.1k
    pdc->ccolor_valid = true;
356
90.1k
    return code;
357
90.1k
}
358
359
static int
360
gx_concretize_Separation(const gs_client_color *pc, const gs_color_space *pcs,
361
                         frac *pconc, const gs_gstate *pgs, gx_device *dev)
362
90.1k
{
363
90.1k
    int code;
364
90.1k
    gs_client_color cc;
365
90.1k
    gs_color_space *pacs = pcs->base_space;
366
90.1k
    bool is_lab;
367
368
90.1k
    if (pcs->params.separation.sep_type == SEP_OTHER &&
369
90.1k
        pcs->params.separation.use_alt_cspace) {
370
85.5k
        gs_device_n_map *map = pcs->params.separation.map;
371
        /* Check the 1-element cache first. */
372
85.5k
        if (map->cache_valid && map->tint[0] == pc->paint.values[0]) {
373
0
            int i, num_out = gs_color_space_num_components(pacs);
374
375
0
            for (i = 0; i < num_out; ++i)
376
0
                pconc[i] = map->conc[i];
377
0
            return 0;
378
0
        }
379
85.5k
        code = (*pcs->params.separation.map->tint_transform)
380
85.5k
            (pc->paint.values, &cc.paint.values[0],
381
85.5k
             pgs, pcs->params.separation.map->tint_transform_data);
382
85.5k
        if (code < 0)
383
14
            return code;
384
85.5k
        (*pacs->type->restrict_color)(&cc, pacs);
385
        /* First check if this was PS based. */
386
85.5k
        if (gs_color_space_is_PSCIE(pacs)) {
387
            /* We may have to rescale data to 0 to 1 range */
388
0
            rescale_cie_colors(pacs, &cc);
389
            /* If we have not yet created the profile do that now */
390
0
            if (pacs->icc_equivalent == NULL) {
391
0
                code = gs_colorspace_set_icc_equivalent(pacs, &(is_lab), pgs->memory);
392
0
                if (code < 0)
393
0
                   return code;
394
0
            }
395
            /* Use the ICC equivalent color space */
396
0
            pacs = pacs->icc_equivalent;
397
0
        }
398
85.5k
        if (pacs->cmm_icc_profile_data &&
399
85.5k
            (pacs->cmm_icc_profile_data->data_cs == gsCIELAB ||
400
85.5k
            pacs->cmm_icc_profile_data->islab)) {
401
            /* Get the data in a form that is concrete for the CMM */
402
0
            cc.paint.values[0] /= 100.0;
403
0
            cc.paint.values[1] = (cc.paint.values[1]+128)/255.0;
404
0
            cc.paint.values[2] = (cc.paint.values[2]+128)/255.0;
405
0
        }
406
85.5k
        return cs_concretize_color(&cc, pacs, pconc, pgs, dev);
407
85.5k
    } else {
408
4.56k
        pconc[0] = gx_unit_frac(pc->paint.values[0]);
409
4.56k
    }
410
4.56k
    return 0;
411
90.1k
}
412
413
static int
414
gx_remap_concrete_Separation(const gs_color_space * pcs, const frac * pconc,
415
        gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
416
                             gs_color_select_t select, const cmm_dev_profile_t *dev_profile)
417
4.56k
{
418
#ifdef DEBUG
419
    /*
420
     * Verify that the color space and gs_gstate info match.
421
     */
422
    if (pcs->id != pgs->color_component_map.cspace_id)
423
        dmprintf(pgs->memory, "gx_remap_concrete_Separation: color space id mismatch");
424
#endif
425
426
4.56k
    if (pgs->color_component_map.use_alt_cspace) {
427
0
        const gs_color_space *pacs = pcs->base_space;
428
429
0
        return (*pacs->type->remap_concrete_color)
430
0
                                (pacs, pconc, pdc, pgs, dev, select, dev_profile);
431
4.56k
    } else {
432
        /* We need to determine if we did a direct color replacement */
433
4.56k
        gx_remap_concrete_separation(pconc[0], pdc, pgs, dev, select, pcs);
434
4.56k
        return 0;
435
4.56k
    }
436
4.56k
}
437
438
/*
439
 * Check that the color component name for a Separation color space
440
 * matches the device colorant names.  Also build a gs_devicen_color_map
441
 * structure.
442
 */
443
static int
444
check_Separation_component_name(const gs_color_space * pcs, gs_gstate * pgs)
445
14.0k
{
446
14.0k
    int colorant_number;
447
14.0k
    byte *pname;
448
14.0k
    uint name_size;
449
14.0k
    gs_devicen_color_map * pcolor_component_map
450
14.0k
        = &pgs->color_component_map;
451
14.0k
    gx_device * dev = pgs->device;
452
453
14.0k
    pcolor_component_map->num_components = 1;
454
14.0k
    pcolor_component_map->cspace_id = pcs->id;
455
14.0k
    pcolor_component_map->num_colorants = dev->color_info.num_components;
456
14.0k
    pcolor_component_map->sep_type = pcs->params.separation.sep_type;
457
    /*
458
     * If this is a None or All separation then we do not need to
459
     * use the alternate color space.  Also if the named color
460
     * profile supports the component, don't use the alternate
461
     * tint transform. */
462
14.0k
    if (pcs->params.separation.sep_type != SEP_OTHER ||
463
14.0k
        gsicc_support_named_color(pcs, pgs)) {
464
0
        pcolor_component_map->use_alt_cspace = false;
465
0
        return 0;
466
0
    }
467
    /*
468
     * Always use the alternate color space if the current device is
469
     * using an additive color model.  Separations are only for use
470
     * with a subtractive color model.  The exception is if we have a separation
471
     * device and we are doing transparency blending in an additive color
472
     * space.  In that case, the spots are kept separated and blended
473
     * individually per the PDF specification.   Note however, if the spot is
474
     * a CMYK process color and we are doing the blend in an additive color space
475
     * the alternate color space is used.  This matches AR.
476
     */
477
478
14.0k
    if (!(dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0) &&
479
14.0k
        dev_proc(dev, dev_spec_op)(dev, gxdso_is_pdf14_device, NULL, 0)) &&
480
14.0k
        dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
481
10.4k
        pcolor_component_map->use_alt_cspace = true;
482
10.4k
        return 0;
483
10.4k
    }
484
    /*
485
     * Get the character string and length for the component name.
486
     */
487
3.55k
    pname = (byte *)pcs->params.separation.sep_name;
488
3.55k
    name_size = strlen(pcs->params.separation.sep_name);
489
    /*
490
     * Compare the colorant name to the device's.  If the device's
491
     * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
492
     * colorant is in the SeparationNames list but not in the
493
     * SeparationOrder list.
494
     */
495
3.55k
    colorant_number = (*dev_proc(dev, get_color_comp_index))
496
3.55k
                (dev, (const char *)pname, name_size, SEPARATION_NAME);
497
3.55k
    if (colorant_number >= 0 && colorant_number < dev->color_info.max_components) {   /* If valid colorant name */
498
2.95k
        pcolor_component_map->color_map[0] =
499
2.95k
                    (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
500
2.95k
                                                           : colorant_number;
501
2.95k
        pcolor_component_map->use_alt_cspace = false;
502
2.95k
    }
503
597
    else
504
597
        pcolor_component_map->use_alt_cspace = true;
505
3.55k
    return 0;
506
14.0k
}
507
508
/* ---------------- Notes on real Separation colors ---------------- */
509
510
typedef ulong gs_separation;  /* BOGUS */
511
512
#define gs_no_separation ((gs_separation)(-1L))
513
514
#define dev_proc_lookup_separation(proc)\
515
  gs_separation proc(gx_device *dev, const byte *sname, uint len,\
516
    gx_color_value *num_levels)
517
518
#define dev_proc_map_tint_color(proc)\
519
  gx_color_index proc(gx_device *dev, gs_separation sepr, bool overprint,\
520
    gx_color_value tint)
521
522
/*
523
 * This next comment is outdated since the Separation color space no longer
524
 * has the multi element cache (lookup table) however the remainder is
525
 * still appropriate.
526
 *
527
 * In principle, setting a Separation color space, or setting the device
528
 * when the current color space is a Separation space, calls the
529
 * lookup_separation device procedure to obtain the separation ID and
530
 * the number of achievable levels.  Currently, the only hooks for doing
531
 * this are unsuitable: gx_set_cmap_procs isn't called when the color
532
 * space changes, and doing it in gx_remap_Separation is inefficient.
533
 * Probably the best approach is to call gx_set_cmap_procs whenever the
534
 * color space changes.  In fact, if we do this, we can probably short-cut
535
 * two levels of procedure call in color remapping (gx_remap_color, by
536
 * turning it into a macro, and gx_remap_DeviceXXX, by calling the
537
 * cmap_proc procedure directly).  Some care will be required for the
538
 * implicit temporary resetting of the color space in [color]image.
539
 */
540
541
/* ---------------- Serialization. -------------------------------- */
542
543
static int
544
gx_serialize_Separation(const gs_color_space * pcs, stream * s)
545
14.7k
{
546
14.7k
    const gs_separation_params * p = &pcs->params.separation;
547
14.7k
    uint n;
548
14.7k
    int code = gx_serialize_cspace_type(pcs, s);
549
550
14.7k
    if (code < 0)
551
0
        return code;
552
14.7k
    code = sputs(s, (const byte *)p->sep_name, strlen(p->sep_name) + 1, &n);
553
14.7k
    if (code < 0)
554
0
        return code;
555
14.7k
    code = cs_serialize(pcs->base_space, s);
556
14.7k
    if (code < 0)
557
0
        return code;
558
14.7k
    code = gx_serialize_device_n_map(pcs, p->map, s);
559
14.7k
    if (code < 0)
560
0
        return code;
561
14.7k
    return sputs(s, (const byte *)&p->sep_type, sizeof(p->sep_type), &n);
562
    /* p->use_alt_cspace isn't a property of the space. */
563
14.7k
}