Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpdfc.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* Color space management and writing for pdfwrite driver */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gscspace.h"   /* for gscie.h */
22
#include "gscdevn.h"
23
#include "gscie.h"
24
#include "gscindex.h"
25
#include "gscsepr.h"
26
#include "stream.h"
27
#include "gsicc.h"
28
#include "gserrors.h"
29
#include "gsfunc.h"     /* required for colour space function evaluation */
30
#include "gsfunc3.h"    /* Required to create a replacement linear interpolation function */
31
#include "gsfunc0.h"    /* Required to create a sampled function for DeviceN alternate replacement */
32
#include "gdevpdfx.h"
33
#include "gdevpdfg.h"
34
#include "gdevpdfc.h"
35
#include "gdevpdfo.h"
36
#include "strimpl.h"
37
#include "sstring.h"
38
#include "gxcspace.h"
39
#include "gxcdevn.h"
40
#include "gscspace.h"
41
#include "gsicc_manage.h"
42
#include "gsicc_cache.h"
43
44
/*
45
 * PDF doesn't have general CIEBased color spaces.  However, it provides
46
 * two methods for handling general CIE spaces:
47
 *
48
 *  - For PDF 1.2 and above, we note that the transformation from L*a*b*
49
 *  space to XYZ space is invertible, so we can handle any PostScript
50
 *  CIEBased space by transforming color values in that space to XYZ,
51
 *  then inverse-transforming them to L*a*b* and using a PDF Lab space
52
 *  with the same WhitePoint and BlackPoint and appropriate ranges for
53
 *  a and b.  This approach has the drawback that Y values outside the
54
 *  range [0..1] can't be represented: we just clamp them.
55
 *
56
 *  - For PDF 1.3 and above, we can create an ICCBased space.  This is
57
 *  actually necessary, not just an option, because for shadings (also
58
 *  introduced in PDF 1.3), we want color interpolation to occur in the
59
 *  original space.
60
 *
61
 * The Lab approach is not currently implemented, because it requires
62
 * transforming all the sample values of images.  The ICCBased approach is
63
 * implemented for color spaces whose ranges lie within [0..1], which are
64
 * the only ranges supported by the ICC standard: we think that removing
65
 * this limitation would also require transforming image sample values.
66
 */
67
68
/* GC descriptors */
69
public_st_pdf_color_space();
70
71
/* ------ CIE space testing ------ */
72
73
/* Test whether a cached CIE procedure is the identity function. */
74
#define CIE_CACHE_IS_IDENTITY(pc)\
75
0
  ((pc)->floats.params.is_identity)
76
#define CIE_CACHE3_IS_IDENTITY(pca)\
77
0
  (CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\
78
0
   CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\
79
0
   CIE_CACHE_IS_IDENTITY(&(pca)[2]))
80
81
/*
82
 * Test whether a cached CIE procedure is an exponential.  A cached
83
 * procedure is exponential iff f(x) = k*(x^p).  We make a very cursory
84
 * check for this: we require that f(0) = 0, set k = f(1), set p =
85
 * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
86
 * two arbitrarily chosen values between 0 and 1.  Naturally all this is
87
 * done with some slop.
88
 */
89
0
#define CC_INDEX_A (gx_cie_cache_size / 3)
90
0
#define CC_INDEX_B (gx_cie_cache_size * 2 / 3)
91
0
#define CC_INDEX_1 (gx_cie_cache_size - 1)
92
0
#define CC_KEY(i) ((i) / (double)CC_INDEX_1)
93
0
#define CC_KEY_A CC_KEY(CC_INDEX_A)
94
0
#define CC_KEY_B CC_KEY(CC_INDEX_B)
95
96
static bool
97
cie_values_are_exponential(double v0, double va, double vb, double k,
98
                           float *pexpt)
99
0
{
100
0
    double p;
101
102
0
    if (fabs(v0) >= 0.001 || fabs(k) < 0.001)
103
0
        return false;
104
0
    if (va == 0 || (va > 0) != (k > 0))
105
0
        return false;
106
0
    p = log(va / k) / log(CC_KEY_A);
107
0
    if (fabs(vb - k * pow(CC_KEY_B, p)) >= 0.001)
108
0
        return false;
109
0
    *pexpt = p;
110
0
    return true;
111
0
}
112
113
static bool
114
cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt)
115
0
{
116
0
    return cie_values_are_exponential(pc->floats.values[0],
117
0
                                      pc->floats.values[CC_INDEX_A],
118
0
                                      pc->floats.values[CC_INDEX_B],
119
0
                                      pc->floats.values[CC_INDEX_1],
120
0
                                      pexpt);
121
0
}
122
#define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\
123
0
  (cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\
124
0
   cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\
125
0
   cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w))
126
127
static bool
128
cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt)
129
0
{
130
0
    return cie_values_are_exponential(pc->vecs.values[0].u,
131
0
                                      pc->vecs.values[CC_INDEX_A].u,
132
0
                                      pc->vecs.values[CC_INDEX_B].u,
133
0
                                      pc->vecs.values[CC_INDEX_1].u,
134
0
                                      pexpt);
135
0
}
136
#define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\
137
0
  (cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\
138
0
   cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\
139
0
   cie_vector_cache_is_exponential(&(pca)[2], &(expts).w))
140
141
#undef CC_INDEX_A
142
#undef CC_INDEX_B
143
#undef CC_KEY_A
144
#undef CC_KEY_B
145
146
/*
147
 * Test whether a cached CIEBasedABC space consists only of a single
148
 * Decode step followed by a single Matrix step.
149
 */
150
static cie_cache_one_step_t
151
cie_cached_abc_is_one_step(const gs_cie_abc *pcie, const gs_matrix3 **ppmat)
152
0
{
153
    /* The order of steps is, DecodeABC, MatrixABC, DecodeLMN, MatrixLMN. */
154
155
0
    if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN)) {
156
0
        if (pcie->MatrixABC.is_identity) {
157
0
            *ppmat = &pcie->common.MatrixLMN;
158
0
            return ONE_STEP_ABC;
159
0
        }
160
0
        if (pcie->common.MatrixLMN.is_identity) {
161
0
            *ppmat = &pcie->MatrixABC;
162
0
            return ONE_STEP_ABC;
163
0
        }
164
0
    }
165
0
    if (CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC.caches)) {
166
0
        if (pcie->MatrixABC.is_identity) {
167
0
            *ppmat = &pcie->common.MatrixLMN;
168
0
            return ONE_STEP_LMN;
169
0
        }
170
0
    }
171
0
    return ONE_STEP_NOT;
172
0
}
173
174
/*
175
 * Test whether a cached CIEBasedABC space is a L*a*b* space.
176
 */
177
static bool
178
cie_scalar_cache_is_lab_lmn(const gs_cie_abc *pcie, int i)
179
0
{
180
0
    double k = CC_KEY(i);
181
0
    double g = (k >= 6.0 / 29 ? k * k * k :
182
0
                (k - 4.0 / 29) * (108.0 / 841));
183
184
0
#define CC_V(j,i) (pcie->common.caches.DecodeLMN[j].floats.values[i])
185
0
#define CC_WP(uvw) (pcie->common.points.WhitePoint.uvw)
186
187
0
    return (fabs(CC_V(0, i) - g * CC_WP(u)) < 0.001 &&
188
0
            fabs(CC_V(1, i) - g * CC_WP(v)) < 0.001 &&
189
0
            fabs(CC_V(2, i) - g * CC_WP(w)) < 0.001
190
0
            );
191
192
0
#undef CC_V
193
0
#undef CC_WP
194
0
}
195
static bool
196
cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t *pvc, int i)
197
0
{
198
0
    const gx_cie_vector_cache *const pc3 = pvc->caches;
199
0
    double k = CC_KEY(i);
200
0
    double l0 = pc3[0].vecs.params.base,
201
0
        l = l0 + k * (pc3[0].vecs.params.limit - l0);
202
0
    double a0 = pc3[1].vecs.params.base,
203
0
        a = a0 + k * (pc3[1].vecs.params.limit - a0);
204
0
    double b0 = pc3[2].vecs.params.base,
205
0
        b = b0 + k * (pc3[2].vecs.params.limit - b0);
206
207
0
    return (fabs(cie_cached2float(pc3[0].vecs.values[i].u) -
208
0
                 (l + 16) / 116) < 0.001 &&
209
0
            fabs(cie_cached2float(pc3[1].vecs.values[i].u) -
210
0
                 a / 500) < 0.001 &&
211
0
            fabs(cie_cached2float(pc3[2].vecs.values[i].w) -
212
0
                 b / -200) < 0.001
213
0
            );
214
0
}
215
216
static bool
217
cie_is_lab(const gs_cie_abc *pcie)
218
0
{
219
0
    int i;
220
221
    /* Check MatrixABC and MatrixLMN. */
222
0
    if (!(pcie->MatrixABC.cu.u == 1 && pcie->MatrixABC.cu.v == 1 &&
223
0
          pcie->MatrixABC.cu.w == 1 &&
224
0
          pcie->MatrixABC.cv.u == 1 && pcie->MatrixABC.cv.v == 0 &&
225
0
          pcie->MatrixABC.cv.w == 0 &&
226
0
          pcie->MatrixABC.cw.u == 0 && pcie->MatrixABC.cw.v == 0 &&
227
0
          pcie->MatrixABC.cw.w == -1 &&
228
0
          pcie->common.MatrixLMN.is_identity
229
0
          ))
230
0
        return false;
231
232
    /* Check DecodeABC and DecodeLMN. */
233
0
    for (i = 0; i <= CC_INDEX_1; ++i)
234
0
        if (!(cie_vector_cache_is_lab_abc(&pcie->caches.DecodeABC, i) &&
235
0
              cie_scalar_cache_is_lab_lmn(pcie, i)
236
0
              ))
237
0
            return false;
238
239
0
    return true;
240
0
}
241
242
#undef CC_INDEX_1
243
#undef CC_KEY
244
245
/* Test whether one or more CIE-based ranges are [0..1]. */
246
static bool
247
cie_ranges_are_0_1(const gs_range *prange, int n)
248
0
{
249
0
    int i;
250
251
0
    for (i = 0; i < n; ++i)
252
0
        if (prange[i].rmin != 0 || prange[i].rmax != 1)
253
0
            return false;
254
0
    return true;
255
0
}
256
257
/* ------ Utilities ------ */
258
259
/* Add a 3-element vector to a Cos array or dictionary. */
260
static int
261
cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec)
262
0
{
263
0
    int code = cos_array_add_real(pca, pvec->u);
264
265
0
    if (code >= 0)
266
0
        code = cos_array_add_real(pca, pvec->v);
267
0
    if (code >= 0)
268
0
        code = cos_array_add_real(pca, pvec->w);
269
0
    return code;
270
0
}
271
static int
272
cos_dict_put_c_key_vector3(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key,
273
                           const gs_vector3 *pvec)
274
0
{
275
0
    cos_array_t *pca = cos_array_alloc(pdev, "cos_array_from_vector3");
276
0
    int code;
277
278
0
    if (pca == 0)
279
0
        return_error(gs_error_VMerror);
280
0
    code = cos_array_add_vector3(pca, pvec);
281
0
    if (code < 0) {
282
0
        COS_FREE(pca, "cos_array_from_vector3");
283
0
        return code;
284
0
    }
285
0
    return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
286
0
}
287
288
/*
289
 * Finish creating a CIE-based color space (Calxxx or Lab.)
290
 * This procedure is exported for gdevpdfk.c.
291
 */
292
int
293
pdf_finish_cie_space(gx_device_pdf *pdev, cos_array_t *pca, cos_dict_t *pcd,
294
                     const gs_cie_common *pciec)
295
0
{
296
0
    int code = cos_dict_put_c_key_vector3(pdev, pcd, "/WhitePoint",
297
0
                                          &pciec->points.WhitePoint);
298
299
0
    if (code < 0)
300
0
        return code;
301
0
    if (pciec->points.BlackPoint.u != 0 ||
302
0
        pciec->points.BlackPoint.v != 0 ||
303
0
        pciec->points.BlackPoint.w != 0
304
0
        ) {
305
0
        code = cos_dict_put_c_key_vector3(pdev, pcd, "/BlackPoint",
306
0
                                          &pciec->points.BlackPoint);
307
0
        if (code < 0)
308
0
            return code;
309
0
    }
310
0
    return cos_array_add_object(pca, COS_OBJECT(pcd));
311
0
}
312
313
/* ------ Color space writing ------ */
314
315
/* Define standard and short color space names. */
316
const pdf_color_space_names_t pdf_color_space_names = {
317
    PDF_COLOR_SPACE_NAMES
318
};
319
const pdf_color_space_names_t pdf_color_space_names_short = {
320
    PDF_COLOR_SPACE_NAMES_SHORT
321
};
322
323
/*
324
 * Create a local Device{Gray,RGB,CMYK} color space corresponding to the
325
 * given number of components.
326
 */
327
int
328
pdf_cspace_init_Device(gs_memory_t *mem, gs_color_space **ppcs,
329
                       int num_components)
330
8.48k
{
331
8.48k
    switch (num_components) {
332
0
    case 1: *ppcs = gs_cspace_new_DeviceGray(mem); break;
333
8.48k
    case 3: *ppcs = gs_cspace_new_DeviceRGB(mem); break;
334
0
    case 4: *ppcs = gs_cspace_new_DeviceCMYK(mem); break;
335
0
    default: return_error(gs_error_rangecheck);
336
8.48k
    }
337
338
8.48k
    if (*ppcs == NULL)
339
0
        return_error(gs_error_VMerror);
340
341
8.48k
    return 0;
342
8.48k
}
343
344
int pdf_delete_sampled_base_space_function(gx_device_pdf *pdev, gs_function_t *pfn)
345
0
{
346
0
    gs_function_Sd_params_t *params = (gs_function_Sd_params_t *)&pfn->params;
347
348
0
    gs_free_object(pdev->memory, (void *)params->Domain, "pdf_delete_function");
349
0
    gs_free_object(pdev->memory, (void *)params->Range, "pdf_delete_function");
350
0
    gs_free_string(pdev->memory, (void *)params->DataSource.data.str.data, params->DataSource.data.str.size, "pdf_dselete_function");
351
0
    gs_free_object(pdev->memory, (void *)pfn, "pdf_delete_function");
352
0
    return 0;
353
0
}
354
355
int pdf_delete_base_space_function(gx_device_pdf *pdev, gs_function_t *pfn)
356
0
{
357
0
    gs_function_ElIn_params_t *params = (gs_function_ElIn_params_t *)&pfn->params;
358
359
0
    gs_free_object(pdev->memory, (void *)params->Domain, "pdf_delete_function");
360
0
    gs_free_object(pdev->memory, (void *)params->Range, "pdf_delete_function");
361
0
    gs_free_object(pdev->memory, (void *)params->C0, "pdf_delete_function");
362
0
    gs_free_object(pdev->memory, (void *)params->C1, "pdf_delete_function");
363
0
    gs_free_object(pdev->memory, (void *)pfn, "pdf_delete_function");
364
0
    return 0;
365
0
}
366
367
int pdf_make_sampled_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn,
368
                                        int nSrcComp, int nDstComp, byte *data)
369
0
{
370
0
    gs_function_Sd_params_t params;
371
0
    void *ptr1, *ptr2;
372
0
    int i, code;
373
0
    gs_const_string str;
374
375
0
    str.size = nDstComp * (uint)pow(2, nSrcComp);
376
0
    str.data = gs_alloc_string(pdev->memory, str.size, "pdf_DeviceN");
377
0
    if (str.data == NULL)
378
0
        return_error(gs_error_VMerror);
379
0
    memcpy((void *)str.data, data, str.size);
380
381
0
    params.m = nSrcComp;
382
0
    params.n = nDstComp;
383
0
    params.Order = 1;
384
0
    params.BitsPerSample = 8;
385
386
0
    ptr1 = gs_alloc_byte_array(pdev->memory, nSrcComp, sizeof(int), "pdf_make_function(Domain)");
387
0
    if (ptr1 == NULL)
388
0
        return gs_note_error(gs_error_VMerror);
389
390
0
    for (i=0;i<nSrcComp;i++) {
391
0
        ((int *)ptr1)[i] = 2;
392
0
    }
393
0
    params.Size = (const int *)ptr1;
394
395
0
    ptr1 = (float *)
396
0
        gs_alloc_byte_array(pdev->memory, 2 * nSrcComp, sizeof(float), "pdf_make_function(Domain)");
397
0
    if (ptr1 == 0) {
398
0
        return gs_note_error(gs_error_VMerror);
399
0
    }
400
0
    ptr2 = (float *)
401
0
        gs_alloc_byte_array(pdev->memory, 2 * nDstComp, sizeof(float), "pdf_make_function(Range)");
402
0
    if (ptr2 == 0) {
403
0
        gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)");
404
0
        return gs_note_error(gs_error_VMerror);
405
0
    }
406
0
    for (i=0;i<nSrcComp;i++) {
407
0
        ((float *)ptr1)[i*2] = 0.0f;
408
0
        ((float *)ptr1)[(i*2) + 1] = 1.0f;
409
0
    }
410
0
    for (i=0;i<nDstComp;i++) {
411
0
        ((float *)ptr2)[i*2] = 0.0f;
412
0
        ((float *)ptr2)[(i*2) + 1] = 1.0f;
413
0
    }
414
0
    params.Domain = ptr1;
415
0
    params.Range = ptr2;
416
0
    params.Encode = params.Decode = NULL;
417
0
    data_source_init_string(&params.DataSource, str);
418
419
0
    code = gs_function_Sd_init(pfn, &params, pdev->memory);
420
0
    return code;
421
0
}
422
423
int pdf_make_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn,
424
                                        int ncomp, float *data_low, float *data_high)
425
0
{
426
0
    gs_function_ElIn_params_t params;
427
0
    float *ptr1, *ptr2;
428
0
    int i, code;
429
430
0
    ptr1 = (float *)
431
0
        gs_alloc_byte_array(pdev->memory, 2, sizeof(float), "pdf_make_function(Domain)");
432
0
    if (ptr1 == 0) {
433
0
        return gs_note_error(gs_error_VMerror);
434
0
    }
435
0
    ptr2 = (float *)
436
0
        gs_alloc_byte_array(pdev->memory, 2 * ncomp, sizeof(float), "pdf_make_function(Range)");
437
0
    if (ptr2 == 0) {
438
0
        gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)");
439
0
        return gs_note_error(gs_error_VMerror);
440
0
    }
441
0
    params.m = 1;
442
0
    params.n = ncomp;
443
0
    params.N = 1.0f;
444
0
    ptr1[0] = 0.0f;
445
0
    ptr1[1] = 1.0f;
446
0
    for (i=0;i<ncomp;i++) {
447
0
        ptr2[i*2] = 0.0f;
448
0
        ptr2[(i*2) + 1] = 1.0f;
449
0
    }
450
0
    params.Domain = ptr1;
451
0
    params.Range = ptr2;
452
453
0
    ptr1 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C0)");
454
0
    if (ptr1 == 0) {
455
0
        gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C0)");
456
0
        gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C0)");
457
0
        return gs_note_error(gs_error_VMerror);
458
0
    }
459
0
    ptr2 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C1)");
460
0
    if (ptr2 == 0) {
461
0
        gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C1)");
462
0
        gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C1)");
463
0
        gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(C1)");
464
0
        return gs_note_error(gs_error_VMerror);
465
0
    }
466
467
0
    for (i=0;i<ncomp;i++) {
468
0
        ptr1[i] = data_low[i];
469
0
        ptr2[i] = data_high[i];
470
0
    }
471
0
    params.C0 = ptr1;
472
0
    params.C1 = ptr2;
473
0
    code = gs_function_ElIn_init(pfn, &params, pdev->memory);
474
0
    if (code < 0) {
475
0
        gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function");
476
0
        gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function");
477
0
        gs_free_object(pdev->memory, (void *)params.C0, "pdf_make_function");
478
0
        gs_free_object(pdev->memory, (void *)params.C1, "pdf_make_function");
479
0
    }
480
0
    return code;
481
0
}
482
483
/* Create a Separation or DeviceN color space (internal). */
484
static int
485
pdf_separation_color_space(gx_device_pdf *pdev, const gs_gstate * pgs,
486
                           cos_array_t *pca, const char *csname,
487
                           const cos_value_t *snames,
488
                           const gs_color_space *alt_space,
489
                           const gs_function_t *pfn,
490
                           const pdf_color_space_names_t *pcsn,
491
                           const cos_value_t *v_attributes)
492
1.14k
{
493
1.14k
    cos_value_t v;
494
1.14k
    const gs_range_t *ranges;
495
1.14k
    int code, csi;
496
497
    /* We need to think about the alternate space. If we are producing
498
     * PDF/X or PDF/A we can't produce some device spaces, and the code in
499
     * pdf_color_space_named always allows device spaces. We could alter
500
     * that code, but by then we don't know its an Alternate space, and have
501
     * lost the tin transform procedure. So instead we check here.
502
     */
503
1.14k
    csi = gs_color_space_get_index(alt_space);
504
    /* Note that if csi is ICC, check to see if this was one of
505
       the default substitutes that we introduced for DeviceGray,
506
       DeviceRGB or DeviceCMYK.  If it is, then just write
507
       the default color.  Depending upon the flavor of PDF,
508
       or other options, we may want to actually have all
509
       the colors defined by ICC profiles and not do the following
510
       substituion of the Device space. */
511
1.14k
    if (csi == gs_color_space_index_ICC) {
512
1.14k
        csi = gsicc_get_default_type(alt_space->cmm_icc_profile_data);
513
1.14k
    }
514
1.14k
    if (csi == gs_color_space_index_DeviceRGB && ((pdev->PDFX > 0 && pdev->PDFX < 4) ||
515
149
        (pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceCMYK)))) {
516
517
        /*
518
         * We shouldn't get here. If someoone is using PDF/X or PDF/A then they should *also*
519
         * set ColorConversionStrategy, and any Separation or DeviceN space should have been
520
         * converted earlier. If we somehow do get here (eg user set PDFA but *ddin't* set
521
         * ColorConversionStrategy) then return a rangecheck error. Earlier code will then
522
         * fall back to writing a device space.
523
         */
524
0
        dmprintf(pdev->pdf_memory, "Attempting to write a DeviceN space with an inappropriate alternate,\nhave you set ColorConversionStrategy ?\n");
525
0
        return gs_error_rangecheck;
526
0
    }
527
1.14k
    if (csi == gs_color_space_index_DeviceCMYK &&
528
834
        (pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceRGB))) {
529
530
0
        dmprintf(pdev->pdf_memory, "Attempting to write a DeviceN space with an inappropriate alternate,\nhave you set ColorConversionStrategy ?\n");
531
0
        return gs_error_rangecheck;
532
0
    }
533
534
1.14k
    if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
535
1.14k
        (code = cos_array_add(pca, snames)) < 0 ||
536
1.14k
        (code = pdf_color_space_named(pdev, pgs, &v, &ranges, alt_space, pcsn, false, NULL, 0, false)) < 0 ||
537
1.14k
        (code = cos_array_add(pca, &v)) < 0 ||
538
1.14k
        (code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
539
1.14k
        (code = cos_array_add(pca, &v)) < 0 ||
540
1.14k
        (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
541
1.14k
        )
542
0
        return code;
543
1.14k
    return 0;
544
1.14k
}
545
546
/*
547
 * Create an Indexed color space.  This is a single-use procedure,
548
 * broken out only for readability.
549
 */
550
int
551
pdf_indexed_color_space(gx_device_pdf *pdev, const gs_gstate * pgs, cos_value_t *pvalue,
552
                        const gs_color_space *pcs, cos_array_t *pca, cos_value_t *cos_base)
553
886
{
554
886
    const gs_indexed_params *pip = &pcs->params.indexed;
555
886
    const gs_color_space *base_space = pcs->base_space;
556
886
    int num_entries = pip->hival + 1;
557
886
    int num_components = gs_color_space_num_components(base_space);
558
886
    uint table_size = num_entries * num_components;
559
    /* Guess at the extra space needed for PS string encoding. */
560
886
    uint string_size = 2 + table_size * 4;
561
886
    uint string_used;
562
886
    byte buf[100];    /* arbitrary */
563
886
    stream_AXE_state st;
564
886
    stream s, es;
565
886
    gs_memory_t *mem = pdev->pdf_memory;
566
886
    byte *table;
567
886
    byte *palette;
568
886
    cos_value_t v;
569
886
    int code;
570
571
    /* PDF doesn't support Indexed color spaces with more than 256 entries. */
572
886
    if (num_entries > 256)
573
0
        return_error(gs_error_rangecheck);
574
886
    if (pdev->CompatibilityLevel < 1.3 && !pdev->ForOPDFRead) {
575
0
        switch (gs_color_space_get_index(pcs)) {
576
0
            case gs_color_space_index_Pattern:
577
0
            case gs_color_space_index_Separation:
578
0
            case gs_color_space_index_Indexed:
579
0
            case gs_color_space_index_DeviceN:
580
0
                return_error(gs_error_rangecheck);
581
0
            default: DO_NOTHING;
582
0
        }
583
584
0
    }
585
886
    table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
586
886
    palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
587
886
    if (table == 0 || palette == 0) {
588
0
        gs_free_string(mem, palette, table_size,
589
0
                       "pdf_color_space(palette)");
590
0
        gs_free_string(mem, table, string_size,
591
0
                       "pdf_color_space(table)");
592
0
        return_error(gs_error_VMerror);
593
0
    }
594
886
    s_init(&s, mem);
595
886
    swrite_string(&s, table, string_size);
596
886
    s_init(&es, mem);
597
886
    s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
598
886
    s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
599
886
    sputc(&s, '(');
600
886
    if (pcs->params.indexed.use_proc) {
601
0
        gs_client_color cmin, cmax;
602
0
        byte *pnext = palette;
603
0
        int i, j;
604
605
        /* Find the legal range for the color components. */
606
0
        for (j = 0; j < num_components; ++j)
607
0
            cmin.paint.values[j] = (float)min_long,
608
0
                cmax.paint.values[j] = (float)max_long;
609
0
        gs_color_space_restrict_color(&cmin, base_space);
610
0
        gs_color_space_restrict_color(&cmax, base_space);
611
        /*
612
         * Compute the palette values, with the legal range for each
613
         * one mapped to [0 .. 255].
614
         */
615
0
        for (i = 0; i < num_entries; ++i) {
616
0
            gs_client_color cc;
617
618
0
            gs_cspace_indexed_lookup(pcs, i, &cc);
619
0
            for (j = 0; j < num_components; ++j) {
620
0
                float v = (cc.paint.values[j] - cmin.paint.values[j])
621
0
                    * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
622
623
0
                *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
624
0
            }
625
0
        }
626
0
    } else
627
886
        memcpy(palette, pip->lookup.table.data, table_size);
628
886
    if (gs_color_space_get_index(base_space) ==
629
886
        gs_color_space_index_DeviceRGB
630
886
        ) {
631
        /* Check for an all-gray palette3. */
632
0
        int i;
633
634
0
        for (i = table_size; (i -= 3) >= 0; )
635
0
            if (palette[i] != palette[i + 1] ||
636
0
                palette[i] != palette[i + 2]
637
0
                )
638
0
                break;
639
0
        if (i < 0) {
640
            /* Change the color space to DeviceGray. */
641
0
            for (i = 0; i < num_entries; ++i)
642
0
                palette[i] = palette[i * 3];
643
0
            table_size = num_entries;
644
0
            base_space = gs_cspace_new_DeviceGray(mem);
645
0
            if (base_space == NULL)
646
0
                return_error(gs_error_VMerror);
647
0
        }
648
0
    }
649
886
    stream_write(&es, palette, table_size);
650
886
    gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
651
    /* Another case where we use sclose() and not sclose_filters(), because the
652
     * buffer we supplied to s_init_filter is a heap based C object, so we
653
     * must not free it.
654
     */
655
886
    sclose(&es);
656
886
    sflush(&s);
657
886
    string_used = (uint)stell(&s);
658
886
    table = gs_resize_string(mem, table, string_size, string_used,
659
886
                             "pdf_color_space(table)");
660
    /*
661
     * Since the array is always referenced by name as a resource
662
     * rather than being written as a value, even for in-line images,
663
     * always use the full name for the color space.
664
     *
665
     * We don't have to worry about the range of the base space:
666
     * in PDF, unlike PostScript, the values from the lookup table are
667
     * scaled automatically.
668
     */
669
886
    if (cos_base == NULL) {
670
886
    if ((code = pdf_color_space_named(pdev, pgs, pvalue, NULL, base_space,
671
886
                                &pdf_color_space_names, false, NULL, 0, false)) < 0 ||
672
886
        (code = cos_array_add(pca,
673
886
                              cos_c_string_value(&v,
674
886
                                                 pdf_color_space_names.Indexed
675
886
                                                 /*pcsn->Indexed*/))) < 0 ||
676
886
        (code = cos_array_add(pca, pvalue)) < 0 ||
677
886
        (code = cos_array_add_int(pca, pip->hival)) < 0 ||
678
886
        (code = cos_array_add_no_copy(pca,
679
886
                                      cos_string_value(&v, table,
680
886
                                                       string_used))) < 0
681
886
        )
682
0
        return code;
683
886
    } else {
684
0
        code = cos_array_add(pca, cos_c_string_value(&v, pdf_color_space_names.Indexed));
685
0
        if (code < 0)
686
0
            return code;
687
0
        code = cos_array_add(pca, cos_base);
688
0
        if (code < 0)
689
0
            return code;
690
0
        code = cos_array_add_int(pca, pip->hival);
691
0
        if (code < 0)
692
0
            return code;
693
0
        code = cos_array_add_no_copy(pca, cos_string_value(&v, table, string_used));
694
0
        if (code < 0)
695
0
            return code;
696
0
    }
697
886
    return 0;
698
886
}
699
700
/*
701
 * Find a color space resource by seriialized data.
702
 */
703
static pdf_resource_t *
704
pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size)
705
20.5k
{
706
20.5k
    pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains;
707
20.5k
    pdf_resource_t *pres;
708
20.5k
    int i;
709
710
228k
    for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
711
243k
        for (pres = pchain[i]; pres != 0; pres = pres->next) {
712
35.2k
            const pdf_color_space_t *const ppcs =
713
35.2k
                (const pdf_color_space_t *)pres;
714
35.2k
            if (ppcs->serialized_size != serialized_size)
715
15.9k
                continue;
716
19.3k
            if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size))
717
15.4k
                return pres;
718
19.3k
        }
719
223k
    }
720
5.08k
    return NULL;
721
20.5k
}
722
723
int pdf_convert_ICC(gx_device_pdf *pdev,
724
                const gs_color_space *pcs, cos_value_t *pvalue,
725
                const pdf_color_space_names_t *pcsn)
726
0
{
727
0
    gs_color_space_index csi;
728
0
    int code;
729
730
0
    csi = gs_color_space_get_index(pcs);
731
0
    if (csi == gs_color_space_index_ICC) {
732
0
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
733
0
    }
734
0
    if (csi == gs_color_space_index_Indexed) {
735
0
        pcs = pcs->base_space;
736
0
        csi = gs_color_space_get_index(pcs);
737
0
    }
738
0
    if (csi == gs_color_space_index_ICC) {
739
0
        if (pcs->cmm_icc_profile_data == NULL ||
740
0
            pdev->CompatibilityLevel < 1.3
741
0
            ) {
742
0
            if (pcs->base_space != NULL) {
743
0
                return 0;
744
0
            } else {
745
0
                int num_des_comps;
746
0
                cmm_dev_profile_t *dev_profile;
747
748
                /* determine number of components in device space */
749
0
                code = dev_proc((gx_device *)pdev, get_profile)((gx_device *)pdev, &dev_profile);
750
0
                if (code < 0)
751
0
                    return code;
752
753
0
                num_des_comps = gsicc_get_device_profile_comps(dev_profile);
754
                /* Set image color space to be device space */
755
0
                switch( num_des_comps )  {
756
0
                    case 1:
757
0
                        cos_c_string_value(pvalue, pcsn->DeviceGray);
758
                        /* negative return means we do conversion */
759
0
                        return -1;
760
0
                    case 3:
761
0
                        cos_c_string_value(pvalue, pcsn->DeviceRGB);
762
0
                        return -1;
763
0
                    case 4:
764
0
                        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
765
0
                        return -1;
766
0
                    default:
767
0
                        break;
768
0
                }
769
0
            }
770
0
        }
771
0
    }
772
0
    return 0;
773
0
}
774
775
/*
776
 * Create a PDF color space corresponding to a PostScript color space.
777
 * For parameterless color spaces, set *pvalue to a (literal) string with
778
 * the color space name; for other color spaces, create a cos_array_t if
779
 * necessary and set *pvalue to refer to it.  In the latter case, if
780
 * by_name is true, return a string /Rxxxx rather than a reference to
781
 * the actual object.
782
 *
783
 * If ppranges is not NULL, then if  the domain of the color space had
784
 * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
785
 * to the ranges in *ppranges, otherwise set *ppranges to 0.
786
 */
787
int
788
pdf_color_space_named(gx_device_pdf *pdev, const gs_gstate * pgs,
789
                cos_value_t *pvalue,
790
                const gs_range_t **ppranges,
791
                const gs_color_space *pcs_in,
792
                const pdf_color_space_names_t *pcsn,
793
                bool by_name, const byte *res_name, int name_length, bool keepICC)
794
54.0k
{
795
54.0k
    const gs_color_space *pcs = pcs_in;
796
54.0k
    gs_color_space_index csi;
797
54.0k
    cos_array_t *pca;
798
54.0k
    cos_dict_t *pcd;
799
54.0k
    cos_value_t v;
800
54.0k
    const gs_cie_common *pciec;
801
54.0k
    gs_function_t *pfn;
802
54.0k
    const gs_range_t *ranges = 0;
803
54.0k
    uint serialized_size = 0;
804
54.0k
    byte *serialized = NULL, serialized0[100];
805
54.0k
    pdf_resource_t *pres = NULL;
806
54.0k
    int code, i;
807
54.0k
    bool is_lab = false;
808
809
54.0k
    csi = gs_color_space_get_index(pcs);
810
    /* Note that if csi is ICC, check to see if this was one of
811
       the default substitutes that we introduced for DeviceGray,
812
       DeviceRGB or DeviceCMYK.  If it is, then just write
813
       the default color.  Depending upon the flavor of PDF,
814
       or other options, we may want to actually have all
815
       the colors defined by ICC profiles and not do the following
816
       substituion of the Device space. */
817
54.0k
    if (csi == gs_color_space_index_ICC && !keepICC) {
818
26.1k
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
819
26.1k
    }
820
54.0k
    if (ppranges)
821
42.5k
        *ppranges = 0;   /* default */
822
54.0k
    switch (csi) {
823
4.07k
    case gs_color_space_index_DeviceGray:
824
4.07k
        cos_c_string_value(pvalue, pcsn->DeviceGray);
825
4.07k
        return 0;
826
19.8k
    case gs_color_space_index_DeviceRGB:
827
19.8k
        cos_c_string_value(pvalue, pcsn->DeviceRGB);
828
19.8k
        return 0;
829
2.35k
    case gs_color_space_index_DeviceCMYK:
830
2.35k
        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
831
2.35k
        return 0;
832
84
    case gs_color_space_index_Pattern:
833
84
        if (!pcs->params.pattern.has_base_space) {
834
0
            cos_c_string_value(pvalue, "/Pattern");
835
0
            return 0;
836
0
        }
837
84
        break;
838
12.4k
    case gs_color_space_index_ICC:
839
        /*
840
         * Take a special early exit for unrecognized ICCBased color spaces,
841
         * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
842
         */
843
844
12.4k
        if (pcs->cmm_icc_profile_data == NULL ||
845
12.4k
            pdev->CompatibilityLevel < 1.3
846
12.4k
            ) {
847
71
            if (res_name != NULL)
848
0
                return 0; /* Ignore .includecolorspace */
849
71
            if (pcs->base_space != NULL) {
850
0
            return pdf_color_space_named( pdev, pgs, pvalue, ppranges,
851
0
                                    pcs->base_space,
852
0
                                    pcsn, by_name, NULL, 0, keepICC);
853
71
            } else {
854
71
                switch( cs_num_components(pcs) )  {
855
0
                    case 1:
856
0
                        cos_c_string_value(pvalue, pcsn->DeviceGray);
857
0
                        return 0;
858
71
                    case 3:
859
71
                        cos_c_string_value(pvalue, pcsn->DeviceRGB);
860
71
                        return 0;
861
0
                    case 4:
862
0
                        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
863
0
                        return 0;
864
0
                    default:
865
0
                        break;
866
71
                }
867
71
            }
868
71
        }
869
870
12.3k
        break;
871
15.2k
    default:
872
15.2k
        break;
873
54.0k
    }
874
    /* Check whether we already have a PDF object for this color space. */
875
27.6k
    if (pcs->id != gs_no_id)
876
27.6k
        pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
877
27.6k
    if (pres == NULL) {
878
20.5k
        stream s;
879
880
20.5k
        s_init(&s, pdev->memory);
881
20.5k
        swrite_position_only(&s);
882
20.5k
        code = cs_serialize(pcs, &s);
883
20.5k
        if (code < 0)
884
0
            return_error(gs_error_unregistered); /* Must not happen. */
885
20.5k
        serialized_size = stell(&s);
886
        /* I think this is another case where we use sclose() and not sclose_filters().
887
         * It seems like we don't actually write anything, but it allows us to find the
888
         * length of the serialised data. No buffer hre, so we must no call
889
         * s_close_filters() as that will try to free it.
890
         */
891
20.5k
        sclose(&s);
892
20.5k
        if (serialized_size <= sizeof(serialized0))
893
0
            serialized = serialized0;
894
20.5k
        else {
895
20.5k
            serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
896
20.5k
            if (serialized == NULL)
897
0
                return_error(gs_error_VMerror);
898
20.5k
        }
899
20.5k
        swrite_string(&s, serialized, serialized_size);
900
20.5k
        code = cs_serialize(pcs, &s);
901
20.5k
        if (code < 0)
902
0
            return_error(gs_error_unregistered); /* Must not happen. */
903
20.5k
        if (stell(&s) != serialized_size)
904
0
            return_error(gs_error_unregistered); /* Must not happen. */
905
20.5k
        sclose(&s);
906
20.5k
        pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
907
20.5k
        if (pres != NULL) {
908
15.4k
            if (serialized != serialized0)
909
15.4k
                gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
910
15.4k
            serialized = NULL;
911
15.4k
        }
912
20.5k
    }
913
27.6k
    if (pres) {
914
22.5k
        const pdf_color_space_t *const ppcs =
915
22.5k
            (const pdf_color_space_t *)pres;
916
917
22.5k
        if (ppranges != 0 && ppcs->ranges != 0)
918
0
            *ppranges = ppcs->ranges;
919
22.5k
        pca = (cos_array_t *)pres->object;
920
22.5k
        goto ret;
921
22.5k
    }
922
923
    /* Space has parameters -- create an array. */
924
5.08k
    pca = cos_array_alloc(pdev, "pdf_color_space");
925
5.08k
    if (pca == 0)
926
0
        return_error(gs_error_VMerror);
927
928
5.08k
    switch (csi) {
929
930
2.99k
    case gs_color_space_index_ICC:
931
2.99k
        code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs, pca);
932
2.99k
        break;
933
934
0
    case gs_color_space_index_CIEA: {
935
        /* Check that we can represent this as a CalGray space. */
936
0
        const gs_cie_a *pcie = pcs->params.a;
937
0
        bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
938
0
        bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
939
0
                          pcie->MatrixA.w == 1);
940
0
        gs_vector3 expts;
941
942
0
        pciec = (const gs_cie_common *)pcie;
943
0
        if (!pcie->common.MatrixLMN.is_identity) {
944
0
            if (!pdev->ForOPDFRead) {
945
0
                if (pcs->icc_equivalent == 0) {
946
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
947
0
                    if (code < 0)
948
0
                        return code;
949
0
                }
950
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
951
0
                if (pcs->params.a->RangeA.rmin < 0.0 || pcs->params.a->RangeA.rmax > 1.0)
952
0
                        ranges = &pcs->params.a->RangeA;
953
0
            } else {
954
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
955
0
                                         &pcie->RangeA, ONE_STEP_NOT, NULL,
956
0
                                         &ranges);
957
0
            }
958
0
            break;
959
0
        }
960
0
        if (unitary && identityA &&
961
0
            CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
962
0
            CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
963
0
            expts.v == expts.u && expts.w == expts.u
964
0
            ) {
965
0
            DO_NOTHING;
966
0
        } else if (unitary && identityA &&
967
0
                   CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
968
0
                   cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
969
0
                   ) {
970
0
            DO_NOTHING;
971
0
        } else {
972
0
            if (!pdev->ForOPDFRead) {
973
0
                if (pcs->icc_equivalent == 0) {
974
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
975
0
                    if (code < 0)
976
0
                        return code;
977
0
                }
978
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
979
0
                if (pcs->params.a->RangeA.rmin < 0.0 || pcs->params.a->RangeA.rmax > 1.0)
980
0
                        ranges = &pcs->params.a->RangeA;
981
0
            } else {
982
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
983
0
                                         &pcie->RangeA, ONE_STEP_NOT, NULL,
984
0
                                         &ranges);
985
0
            }
986
0
            break;
987
0
        }
988
0
        code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
989
0
        if (code < 0)
990
0
            return code;
991
0
        pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
992
0
        if (pcd == 0)
993
0
            return_error(gs_error_VMerror);
994
0
        if (expts.u != 1) {
995
0
            code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
996
0
            if (code < 0)
997
0
                return code;
998
0
        }
999
0
    }
1000
0
    cal:
1001
    /* Finish handling a CIE-based color space (Calxxx or Lab). */
1002
0
    if (code < 0)
1003
0
        return code;
1004
0
    code = pdf_finish_cie_space(pdev, pca, pcd, pciec);
1005
0
    break;
1006
1007
0
    case gs_color_space_index_CIEABC: {
1008
        /* Check that we can represent this as a CalRGB space. */
1009
0
        const gs_cie_abc *pcie = pcs->params.abc;
1010
0
        bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
1011
0
        gs_vector3 expts;
1012
0
        const gs_matrix3 *pmat = NULL;
1013
0
        cie_cache_one_step_t one_step =
1014
0
            cie_cached_abc_is_one_step(pcie, &pmat);
1015
1016
0
        pciec = (const gs_cie_common *)pcie;
1017
0
        if (unitary) {
1018
0
            switch (one_step) {
1019
0
            case ONE_STEP_ABC:
1020
0
                if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
1021
0
                    goto calrgb;
1022
0
                break;
1023
0
            case ONE_STEP_LMN:
1024
0
                if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
1025
0
                    goto calrgb;
1026
0
            default:
1027
0
                break;
1028
0
            }
1029
0
        }
1030
0
        if (cie_is_lab(pcie)) {
1031
            /* Represent this as a Lab space. */
1032
0
            pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1033
0
            if (pcd == 0)
1034
0
                return_error(gs_error_VMerror);
1035
0
            code = pdf_put_lab_color_space(pdev, pca, pcd, pcie->RangeABC.ranges);
1036
0
            goto cal;
1037
0
        } else {
1038
0
            if (!pdev->ForOPDFRead) {
1039
0
                int i;
1040
1041
0
                if (pcs->icc_equivalent == 0) {
1042
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
1043
0
                    if (code < 0)
1044
0
                        return code;
1045
0
                }
1046
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
1047
0
                for (i = 0; i < 3; ++i) {
1048
0
                    double rmin = pcs->params.abc->RangeABC.ranges[i].rmin, rmax = pcs->params.abc->RangeABC.ranges[i].rmax;
1049
1050
0
                    if (rmin < 0.0 || rmax > 1.0)
1051
0
                        ranges = pcs->params.abc->RangeABC.ranges;
1052
0
                }
1053
0
            } else {
1054
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
1055
0
                                         pcie->RangeABC.ranges,
1056
0
                                         one_step, pmat, &ranges);
1057
0
            }
1058
0
            break;
1059
0
        }
1060
0
    calrgb:
1061
0
        code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
1062
0
        if (code < 0)
1063
0
            return code;
1064
0
        pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1065
0
        if (pcd == 0)
1066
0
            return_error(gs_error_VMerror);
1067
0
        if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
1068
0
            code = cos_dict_put_c_key_vector3(pdev, pcd, "/Gamma", &expts);
1069
0
            if (code < 0)
1070
0
                return code;
1071
0
        }
1072
0
        if (!pmat->is_identity) {
1073
0
            cos_array_t *pcma =
1074
0
                cos_array_alloc(pdev, "pdf_color_space(Matrix)");
1075
1076
0
            if (pcma == 0)
1077
0
                return_error(gs_error_VMerror);
1078
0
            if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
1079
0
                (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
1080
0
                (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
1081
0
                (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
1082
0
                                     COS_OBJECT_VALUE(&v, pcma))) < 0
1083
0
                )
1084
0
                return code;
1085
0
        }
1086
0
    }
1087
0
    goto cal;
1088
1089
0
    case gs_color_space_index_CIEDEF:
1090
0
            if (!pdev->ForOPDFRead) {
1091
0
                int i;
1092
0
                if (pcs->icc_equivalent == 0) {
1093
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
1094
0
                    if (code < 0)
1095
0
                        return code;
1096
0
                }
1097
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
1098
0
                for (i = 0; i < 3; ++i) {
1099
0
                    double rmin = pcs->params.def->RangeDEF.ranges[i].rmin, rmax = pcs->params.def->RangeDEF.ranges[i].rmax;
1100
1101
0
                    if (rmin < 0.0 || rmax > 1.0)
1102
0
                        ranges = pcs->params.def->RangeDEF.ranges;
1103
0
                }
1104
0
            } else {
1105
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
1106
0
                                     (const gs_cie_common *)pcs->params.def,
1107
0
                                     pcs->params.def->RangeDEF.ranges,
1108
0
                                     ONE_STEP_NOT, NULL, &ranges);
1109
0
            }
1110
0
        break;
1111
1112
0
    case gs_color_space_index_CIEDEFG:
1113
0
            if (!pdev->ForOPDFRead) {
1114
0
                int i;
1115
0
                if (pcs->icc_equivalent == 0) {
1116
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
1117
0
                    if (code < 0)
1118
0
                        return code;
1119
0
                }
1120
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
1121
0
                for (i = 0; i < 4; ++i) {
1122
0
                    double rmin = pcs->params.defg->RangeDEFG.ranges[i].rmin, rmax = pcs->params.defg->RangeDEFG.ranges[i].rmax;
1123
1124
0
                    if (rmin < 0.0 || rmax > 1.0)
1125
0
                        ranges = pcs->params.defg->RangeDEFG.ranges;
1126
0
                }
1127
0
            } else {
1128
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
1129
0
                                     (const gs_cie_common *)pcs->params.defg,
1130
0
                                     pcs->params.defg->RangeDEFG.ranges,
1131
0
                                     ONE_STEP_NOT, NULL, &ranges);
1132
0
            }
1133
0
        break;
1134
1135
886
    case gs_color_space_index_Indexed:
1136
886
        code = pdf_indexed_color_space(pdev, pgs, pvalue, pcs, pca, NULL);
1137
886
        break;
1138
1139
92
    case gs_color_space_index_DeviceN:
1140
92
        if (!pdev->PreserveDeviceN)
1141
0
            return_error(gs_error_rangecheck);
1142
92
        if (pdev->CompatibilityLevel < 1.3)
1143
48
            return_error(gs_error_rangecheck);
1144
44
        if (pdev->PDFA != 0) {
1145
0
            for (i = 0; i < pcs->params.device_n.num_components; ++i) {
1146
0
                if (utf8_check((unsigned char *)pcs->params.device_n.names[i]) != NULL) {
1147
0
                    switch(pdev->PDFACompatibilityPolicy) {
1148
0
                        case 0:
1149
0
                            emprintf(pdev->memory,
1150
0
                                 "Ink name in Separation space not valid UTF-8, reverting to normal PDF output.\n");
1151
0
                            pdev->AbortPDFAX = true;
1152
0
                            pdev->PDFA = 0;
1153
0
                            break;
1154
0
                        case 1:
1155
0
                            emprintf(pdev->memory,
1156
0
                                 "Ink name in Separation space not valid UTF-8, reverting to normal PDF output.\n");
1157
0
                            pdev->AbortPDFAX = true;
1158
0
                            pdev->PDFA = 0;
1159
0
                            break;
1160
0
                        default:
1161
0
                        case 2:
1162
0
                            emprintf(pdev->memory,
1163
0
                                 "Ink name in Separation space not valid UTF-8, aborting.\n");
1164
0
                            return_error(gs_error_limitcheck);
1165
0
                            break;
1166
0
                    }
1167
0
                    break;
1168
0
                }
1169
0
            }
1170
0
        }
1171
44
        pfn = gs_cspace_get_devn_function(pcs);
1172
        /****** CURRENTLY WE ONLY HANDLE Functions ******/
1173
44
        if (pfn == 0)
1174
0
            return_error(gs_error_rangecheck);
1175
44
        {
1176
44
            cos_array_t *psna =
1177
44
                cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
1178
44
            int i;
1179
44
            byte *name_string;
1180
44
            uint name_string_length;
1181
44
            cos_value_t v_attributes, *va = NULL;
1182
44
            pdf_resource_t *pres_attributes = NULL;
1183
1184
44
            if (psna == 0)
1185
0
                return_error(gs_error_VMerror);
1186
150
            for (i = 0; i < pcs->params.device_n.num_components; ++i) {
1187
106
                name_string = (byte *)pcs->params.device_n.names[i];
1188
106
                name_string_length = strlen(pcs->params.device_n.names[i]);
1189
1190
106
                code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v);
1191
106
                if (code < 0)
1192
0
                    return code;
1193
106
                code = cos_array_add(psna, &v);
1194
106
                cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(DeviceN component)");
1195
106
                if (code < 0)
1196
0
                    return code;
1197
106
            }
1198
44
            COS_OBJECT_VALUE(&v, psna);
1199
1200
            /* If we have either /Process or /Colorants (or both) then we need to create an
1201
             * attributes dictionary.
1202
             */
1203
44
            if (pcs->params.device_n.devn_process_space != NULL || pcs->params.device_n.colorants != NULL) {
1204
31
                cos_value_t v_Subtype_name;
1205
1206
31
                code = pdf_alloc_resource(pdev, resourceOther, 0, &pres_attributes, -1);
1207
31
                if (code < 0)
1208
0
                    return code;
1209
31
                cos_become(pres_attributes->object, cos_type_dict);
1210
1211
31
                if (pcs->params.device_n.subtype == gs_devicen_DeviceN) {
1212
0
                    code = pdf_string_to_cos_name(pdev, (const byte *)"DeviceN", 7, &v_Subtype_name);
1213
0
                    if (code < 0)
1214
0
                        return code;
1215
31
                } else {
1216
31
                    if (pcs->params.device_n.subtype == gs_devicen_NChannel) {
1217
31
                        code = pdf_string_to_cos_name(pdev, (const byte *)"NChannel", 8, &v_Subtype_name);
1218
31
                        if (code < 0)
1219
0
                            return code;
1220
31
                    } else
1221
0
                        return gs_note_error(gs_error_typecheck);
1222
31
                }
1223
31
                code = cos_dict_put((cos_dict_t *)pres_attributes->object, (const byte *)"/Subtype", 8, &v_Subtype_name);
1224
31
                cos_value_free((const cos_value_t *)&v_Subtype_name, pdev->pdf_memory, "pdf_color_space(Subtype)");
1225
31
                if (code < 0)
1226
0
                    return code;
1227
31
            }
1228
44
            if (pcs->params.device_n.devn_process_space != NULL) {
1229
31
                cos_dict_t *process;
1230
31
                cos_array_t *components;
1231
31
                cos_value_t v_process, v_components, v_process_space, v_process_name;
1232
31
                int m;
1233
1234
31
                process = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
1235
31
                if (process == NULL)
1236
0
                    return_error(gs_error_VMerror);
1237
1238
31
                COS_OBJECT_VALUE(&v_process, process);
1239
31
                code = cos_dict_put((cos_dict_t *)pres_attributes->object,
1240
31
                    (const byte *)"/Process", 8, &v_process);
1241
31
                if (code < 0)
1242
0
                    return code;
1243
1244
31
                code = pdf_color_space_named(pdev, pgs, &v_process_space, NULL, pcs->params.device_n.devn_process_space, pcsn, false, NULL, 0, keepICC);
1245
31
                 if (code < 0)
1246
0
                     return code;
1247
31
                code = pdf_string_to_cos_name(pdev, (const byte *)"ColorSpace", 10, &v_process_name);
1248
31
                if (code < 0)
1249
0
                    return code;
1250
31
                code = cos_dict_put(process, v_process_name.contents.chars.data,
1251
31
                                    v_process_name.contents.chars.size, &v_process_space);
1252
31
                cos_value_free((const cos_value_t *)&v_process_name, pdev->pdf_memory, "pdf_color_space(ColorSpace)");
1253
31
                if (code < 0)
1254
0
                    return code;
1255
1256
31
                components = cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
1257
31
                if (components == NULL) {
1258
0
                    return_error(gs_error_VMerror);
1259
0
                }
1260
31
                COS_OBJECT_VALUE(&v_components, components);
1261
31
                code = cos_dict_put((cos_dict_t *)process,
1262
31
                    (const byte *)"/Components", 11, &v_components);
1263
31
                if (code < 0)
1264
0
                    return code;
1265
155
                for (m=0;m < pcs->params.device_n.num_process_names;m++) {
1266
124
                    code = pdf_string_to_cos_name(pdev, (const byte *)pcs->params.device_n.process_names[m], strlen(pcs->params.device_n.process_names[m]), &v_process_name);
1267
124
                    if (code < 0)
1268
0
                        return code;
1269
124
                    code = cos_array_put(components, m, &v_process_name);
1270
124
                    cos_value_free((const cos_value_t *)&v_process_name, pdev->pdf_memory, "pdf_color_space(process_name)");
1271
124
                    if (code < 0)
1272
0
                        return code;
1273
124
                }
1274
1275
31
            }
1276
44
            if (pcs->params.device_n.colorants != NULL) {
1277
0
                cos_dict_t *colorants  = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
1278
0
                cos_value_t v_colorants, v_separation, v_colorant_name;
1279
0
                const gs_device_n_colorant *csa;
1280
1281
0
                if (colorants == NULL)
1282
0
                    return_error(gs_error_VMerror);
1283
1284
0
                COS_OBJECT_VALUE(&v_colorants, colorants);
1285
0
                code = cos_dict_put((cos_dict_t *)pres_attributes->object,
1286
0
                    (const byte *)"/Colorants", 10, &v_colorants);
1287
0
                if (code < 0)
1288
0
                    return code;
1289
0
                for (csa = pcs->params.device_n.colorants; csa != NULL; csa = csa->next) {
1290
0
                    name_string = (byte *)csa->colorant_name;
1291
0
                    name_string_length = strlen((const char *)name_string);
1292
0
                    code = pdf_color_space_named(pdev, pgs, &v_separation, NULL, csa->cspace, pcsn, false, NULL, 0, keepICC);
1293
0
                    if (code < 0)
1294
0
                        return code;
1295
0
                    code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v_colorant_name);
1296
0
                    if (code < 0)
1297
0
                        return code;
1298
0
                    code = cos_dict_put(colorants, v_colorant_name.contents.chars.data,
1299
0
                                        v_colorant_name.contents.chars.size, &v_separation);
1300
0
                    cos_value_free((const cos_value_t *)&v_colorant_name, pdev->pdf_memory, "pdf_color_space(Subtype)");
1301
0
                    if (code < 0)
1302
0
                        return code;
1303
0
                }
1304
0
            }
1305
44
            if (pres_attributes != NULL) {
1306
31
                code = pdf_substitute_resource(pdev, &pres_attributes, resourceOther, NULL, true);
1307
31
                if (code < 0)
1308
0
                    return code;
1309
31
                pres_attributes->where_used |= pdev->used_mask;
1310
31
                va = &v_attributes;
1311
31
                COS_OBJECT_VALUE(va, pres_attributes->object);
1312
31
            }
1313
44
            code = pdf_separation_color_space(pdev, pgs, pca, "/DeviceN", &v,
1314
44
                                                   pcs->base_space,
1315
44
                                        pfn, &pdf_color_space_names, va);
1316
44
            if (v.value_type == COS_VALUE_SCALAR)
1317
0
                cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(Devicen)");
1318
44
            if (va != NULL && va->value_type == COS_VALUE_SCALAR)
1319
0
                cos_value_free((const cos_value_t *)&va, pdev->pdf_memory, "pdf_color_space(Devicen)");
1320
44
            if (code < 0)
1321
0
                return code;
1322
44
        }
1323
44
        break;
1324
1325
1.10k
    case gs_color_space_index_Separation:
1326
1.10k
        if (!pdev->PreserveSeparation)
1327
0
            return_error(gs_error_rangecheck);
1328
1.10k
        if (pdev->PDFA != 0 && utf8_check((unsigned char *)pcs->params.separation.sep_name) != NULL) {
1329
0
            switch(pdev->PDFACompatibilityPolicy) {
1330
0
                case 0:
1331
0
                    emprintf(pdev->memory,
1332
0
                         "Ink name in Separation space not valid UTF-8, reverting to normal PDF output.\n");
1333
0
                    pdev->AbortPDFAX = true;
1334
0
                    pdev->PDFA = 0;
1335
0
                    break;
1336
0
                case 1:
1337
0
                    emprintf(pdev->memory,
1338
0
                         "Ink name in Separation space not valid UTF-8, reverting to normal PDF output.\n");
1339
0
                    pdev->AbortPDFAX = true;
1340
0
                    pdev->PDFA = 0;
1341
0
                    break;
1342
0
                default:
1343
0
                case 2:
1344
0
                    emprintf(pdev->memory,
1345
0
                         "Ink name in Separation space not valid UTF-8, aborting.\n");
1346
0
                    return_error(gs_error_limitcheck);
1347
0
                    break;
1348
0
            }
1349
0
        }
1350
1.10k
        pfn = gs_cspace_get_sepr_function(pcs);
1351
        /****** CURRENTLY WE ONLY HANDLE Functions ******/
1352
1.10k
        if (pfn == 0)
1353
0
            return_error(gs_error_rangecheck);
1354
1.10k
        {
1355
1.10k
            code = pdf_string_to_cos_name(pdev, (const byte *)pcs->params.separation.sep_name,
1356
1.10k
                                      strlen(pcs->params.separation.sep_name), &v);
1357
1.10k
            if (code < 0)
1358
0
                return code;
1359
1360
1.10k
            code = pdf_separation_color_space(pdev, pgs, pca, "/Separation", &v,
1361
1.10k
                                            pcs->base_space,
1362
1.10k
                                            pfn, &pdf_color_space_names, NULL);
1363
1.10k
            if (v.value_type == COS_VALUE_SCALAR)
1364
1.10k
                cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(Separation name)");
1365
1.10k
            if (code < 0)
1366
0
                return code;
1367
1.10k
        }
1368
1.10k
        break;
1369
1370
1.10k
    case gs_color_space_index_Pattern:
1371
14
        if ((code = pdf_color_space_named(pdev, pgs, pvalue, ppranges,
1372
14
                                    pcs->base_space,
1373
14
                                    &pdf_color_space_names, false, NULL, 0, false)) < 0 ||
1374
14
            (code = cos_array_add(pca,
1375
14
                                  cos_c_string_value(&v, "/Pattern"))) < 0 ||
1376
14
            (code = cos_array_add(pca, pvalue)) < 0
1377
14
            )
1378
0
            return code;
1379
14
        break;
1380
1381
14
    default:
1382
0
        return_error(gs_error_rangecheck);
1383
5.08k
    }
1384
1385
    /*
1386
     * Register the color space as a resource, since it must be referenced
1387
     * by name rather than directly.
1388
     */
1389
5.03k
    {
1390
5.03k
        pdf_color_space_t *ppcs;
1391
1392
5.03k
        if (code < 0 ||
1393
5.03k
            (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
1394
5.03k
                                       &pres, -1)) < 0
1395
5.03k
            ) {
1396
0
            COS_FREE(pca, "pdf_color_space");
1397
0
            return code;
1398
0
        }
1399
5.03k
        pdf_reserve_object_id(pdev, pres, 0);
1400
5.03k
        if (res_name != NULL) {
1401
0
            int l = min(name_length, sizeof(pres->rname) - 1);
1402
1403
0
            memcpy(pres->rname, res_name, l);
1404
0
            pres->rname[l] = 0;
1405
0
        }
1406
5.03k
        ppcs = (pdf_color_space_t *)pres;
1407
5.03k
        if (serialized == serialized0) {
1408
0
            serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
1409
0
            if (serialized == NULL)
1410
0
                return_error(gs_error_VMerror);
1411
0
            memcpy(serialized, serialized0, serialized_size);
1412
0
        }
1413
5.03k
        ppcs->serialized = serialized;
1414
5.03k
        ppcs->serialized_size = serialized_size;
1415
5.03k
        if (ranges) {
1416
0
            int num_comp = gs_color_space_num_components(pcs);
1417
0
            gs_range_t *copy_ranges = (gs_range_t *)
1418
0
                gs_alloc_byte_array(pdev->pdf_memory, num_comp,
1419
0
                                    sizeof(gs_range_t), "pdf_color_space");
1420
1421
0
            if (copy_ranges == 0) {
1422
0
                COS_FREE(pca, "pdf_color_space");
1423
0
                return_error(gs_error_VMerror);
1424
0
            }
1425
0
            memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
1426
0
            ppcs->ranges = copy_ranges;
1427
0
            if (ppranges)
1428
0
                *ppranges = copy_ranges;
1429
0
        } else
1430
5.03k
            ppcs->ranges = 0;
1431
5.03k
        pca->id = pres->object->id;
1432
5.03k
        COS_FREE(pres->object, "pdf_color_space");
1433
5.03k
        pres->object = (cos_object_t *)pca;
1434
5.03k
        cos_write_object(COS_OBJECT(pca), pdev, resourceColorSpace);
1435
5.03k
    }
1436
27.6k
 ret:
1437
27.6k
    if (by_name) {
1438
        /* Return a resource name rather than an object reference. */
1439
22.4k
        discard(COS_RESOURCE_VALUE(pvalue, pca));
1440
22.4k
    } else
1441
27.6k
        discard(COS_OBJECT_VALUE(pvalue, pca));
1442
27.6k
    if (pres != NULL) {
1443
27.6k
        pres->where_used |= pdev->used_mask;
1444
27.6k
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
1445
27.6k
        if (code < 0)
1446
0
            return code;
1447
27.6k
    }
1448
27.6k
    return 0;
1449
27.6k
}
1450
1451
int free_color_space(gx_device_pdf *pdev, pdf_resource_t *pres)
1452
5.57k
{
1453
5.57k
    pdf_color_space_t *ppcs = (pdf_color_space_t *)pres;
1454
1455
5.57k
    if (ppcs->serialized)
1456
5.03k
        gs_free_object(pdev->pdf_memory, ppcs->serialized, "free serialized colour space");
1457
5.57k
    if (pres->object) {
1458
5.57k
        cos_release(pres->object, "release ColorSpace object");
1459
5.57k
        gs_free_object(pdev->pdf_memory, pres->object, "free ColorSpace object");
1460
5.57k
        pres->object = 0;
1461
5.57k
    }
1462
5.57k
    return 0;
1463
5.57k
}
1464
1465
/* ---------------- Miscellaneous ---------------- */
1466
1467
/* Create colored and uncolored Pattern color spaces. */
1468
static int
1469
pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
1470
                  pdf_resource_t **ppres, const char *cs_name)
1471
9.89k
{
1472
9.89k
    int code;
1473
1474
9.89k
    if (!*ppres) {
1475
539
        int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
1476
539
                                           ppres);
1477
1478
539
        if (code < 0)
1479
0
            return code;
1480
539
        pprints1(pdev->strm, "%s\n", cs_name);
1481
539
        pdf_end_resource(pdev, resourceColorSpace);
1482
539
        (*ppres)->object->written = true; /* don't write at end */
1483
539
        ((pdf_color_space_t *)*ppres)->ranges = 0;
1484
539
        ((pdf_color_space_t *)*ppres)->serialized = 0;
1485
539
    }
1486
9.89k
    code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres);
1487
9.89k
    if (code < 0)
1488
0
        return code;
1489
9.89k
    cos_resource_value(pvalue, (*ppres)->object);
1490
9.89k
    return 0;
1491
9.89k
}
1492
int
1493
pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
1494
9.89k
{
1495
9.89k
    return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
1496
9.89k
                             "[/Pattern]");
1497
9.89k
}
1498
int
1499
pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
1500
0
{
1501
    /* Only for process colors. */
1502
0
    int ncomp = pdev->color_info.num_components;
1503
0
    static const char *const pcs_names[5] = {
1504
0
        0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
1505
0
        "[/Pattern /DeviceCMYK]"
1506
0
    };
1507
1508
0
    return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
1509
0
                             pcs_names[ncomp]);
1510
0
}
1511
int
1512
pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev,
1513
                const gs_color_space *pcs, cos_value_t *pvalue, const gs_gstate * pgs)
1514
84
{
1515
    /* Only for high level colors. */
1516
84
    return pdf_color_space_named(pdev, pgs, pvalue, NULL, pcs, &pdf_color_space_names, true, NULL, 0, false);
1517
84
}
1518
1519
/* Set the ProcSets bits corresponding to an image color space. */
1520
void
1521
pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
1522
25.0k
{
1523
25.0k
    const gs_color_space *pbcs = pcs;
1524
1525
27.0k
 csw:
1526
27.0k
    switch (gs_color_space_get_index(pbcs)) {
1527
0
    case gs_color_space_index_DeviceGray:
1528
0
    case gs_color_space_index_CIEA:
1529
        /* We only handle CIEBasedA spaces that map to CalGray. */
1530
0
        pdev->procsets |= ImageB;
1531
0
        break;
1532
1.98k
    case gs_color_space_index_Indexed:
1533
1.98k
        pdev->procsets |= ImageI;
1534
1.98k
        pbcs = pcs->base_space;
1535
1.98k
        goto csw;
1536
25.0k
    default:
1537
25.0k
        pdev->procsets |= ImageC;
1538
25.0k
        break;
1539
27.0k
    }
1540
27.0k
}