Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevpdfc.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Color space 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
508
{
331
508
    switch (num_components) {
332
0
    case 1: *ppcs = gs_cspace_new_DeviceGray(mem); break;
333
508
    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
508
    }
337
338
508
    if (*ppcs == NULL)
339
0
        return_error(gs_error_VMerror);
340
341
508
    return 0;
342
508
}
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
    memcpy((void *)str.data, data, str.size);
378
379
0
    params.m = nSrcComp;
380
0
    params.n = nDstComp;
381
0
    params.Order = 1;
382
0
    params.BitsPerSample = 8;
383
384
0
    ptr1 = gs_alloc_byte_array(pdev->memory, nSrcComp, sizeof(int), "pdf_make_function(Domain)");
385
0
    for (i=0;i<nSrcComp;i++) {
386
0
        ((int *)ptr1)[i] = 2;
387
0
    }
388
0
    params.Size = (const int *)ptr1;
389
390
0
    ptr1 = (float *)
391
0
        gs_alloc_byte_array(pdev->memory, 2 * nSrcComp, sizeof(float), "pdf_make_function(Domain)");
392
0
    if (ptr1 == 0) {
393
0
        return gs_note_error(gs_error_VMerror);
394
0
    }
395
0
    ptr2 = (float *)
396
0
        gs_alloc_byte_array(pdev->memory, 2 * nDstComp, sizeof(float), "pdf_make_function(Range)");
397
0
    if (ptr2 == 0) {
398
0
        gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)");
399
0
        return gs_note_error(gs_error_VMerror);
400
0
    }
401
0
    for (i=0;i<nSrcComp;i++) {
402
0
        ((float *)ptr1)[i*2] = 0.0f;
403
0
        ((float *)ptr1)[(i*2) + 1] = 1.0f;
404
0
    }
405
0
    for (i=0;i<nDstComp;i++) {
406
0
        ((float *)ptr2)[i*2] = 0.0f;
407
0
        ((float *)ptr2)[(i*2) + 1] = 1.0f;
408
0
    }
409
0
    params.Domain = ptr1;
410
0
    params.Range = ptr2;
411
0
    params.Encode = params.Decode = NULL;
412
0
    data_source_init_string(&params.DataSource, str);
413
414
0
    code = gs_function_Sd_init(pfn, &params, pdev->memory);
415
0
    return code;
416
0
}
417
418
int pdf_make_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn,
419
                                        int ncomp, float *data_low, float *data_high)
420
0
{
421
0
    gs_function_ElIn_params_t params;
422
0
    float *ptr1, *ptr2;
423
0
    int i, code;
424
425
0
    ptr1 = (float *)
426
0
        gs_alloc_byte_array(pdev->memory, 2, sizeof(float), "pdf_make_function(Domain)");
427
0
    if (ptr1 == 0) {
428
0
        return gs_note_error(gs_error_VMerror);
429
0
    }
430
0
    ptr2 = (float *)
431
0
        gs_alloc_byte_array(pdev->memory, 2 * ncomp, sizeof(float), "pdf_make_function(Range)");
432
0
    if (ptr2 == 0) {
433
0
        gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)");
434
0
        return gs_note_error(gs_error_VMerror);
435
0
    }
436
0
    params.m = 1;
437
0
    params.n = ncomp;
438
0
    params.N = 1.0f;
439
0
    ptr1[0] = 0.0f;
440
0
    ptr1[1] = 1.0f;
441
0
    for (i=0;i<ncomp;i++) {
442
0
        ptr2[i*2] = 0.0f;
443
0
        ptr2[(i*2) + 1] = 1.0f;
444
0
    }
445
0
    params.Domain = ptr1;
446
0
    params.Range = ptr2;
447
448
0
    ptr1 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C0)");
449
0
    if (ptr1 == 0) {
450
0
        gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C0)");
451
0
        gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C0)");
452
0
        return gs_note_error(gs_error_VMerror);
453
0
    }
454
0
    ptr2 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C1)");
455
0
    if (ptr2 == 0) {
456
0
        gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C1)");
457
0
        gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C1)");
458
0
        gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(C1)");
459
0
        return gs_note_error(gs_error_VMerror);
460
0
    }
461
462
0
    for (i=0;i<ncomp;i++) {
463
0
        ptr1[i] = data_low[i];
464
0
        ptr2[i] = data_high[i];
465
0
    }
466
0
    params.C0 = ptr1;
467
0
    params.C1 = ptr2;
468
0
    code = gs_function_ElIn_init(pfn, &params, pdev->memory);
469
0
    if (code < 0) {
470
0
        gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function");
471
0
        gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function");
472
0
        gs_free_object(pdev->memory, (void *)params.C0, "pdf_make_function");
473
0
        gs_free_object(pdev->memory, (void *)params.C1, "pdf_make_function");
474
0
    }
475
0
    return code;
476
0
}
477
478
/* Create a Separation or DeviceN color space (internal). */
479
static int
480
pdf_separation_color_space(gx_device_pdf *pdev, const gs_gstate * pgs,
481
                           cos_array_t *pca, const char *csname,
482
                           const cos_value_t *snames,
483
                           const gs_color_space *alt_space,
484
                           const gs_function_t *pfn,
485
                           const pdf_color_space_names_t *pcsn,
486
                           const cos_value_t *v_attributes)
487
221
{
488
221
    cos_value_t v;
489
221
    const gs_range_t *ranges;
490
221
    int code, csi;
491
492
    /* We need to think about the alternate space. If we are producing
493
     * PDF/X or PDF/A we can't produce some device spaces, and the code in
494
     * pdf_color_space_named always allows device spaces. We could alter
495
     * that code, but by then we don't know its an Alternate space, and have
496
     * lost the tin transform procedure. So instead we check here.
497
     */
498
221
    csi = gs_color_space_get_index(alt_space);
499
    /* Note that if csi is ICC, check to see if this was one of
500
       the default substitutes that we introduced for DeviceGray,
501
       DeviceRGB or DeviceCMYK.  If it is, then just write
502
       the default color.  Depending upon the flavor of PDF,
503
       or other options, we may want to actually have all
504
       the colors defined by ICC profiles and not do the following
505
       substituion of the Device space. */
506
221
    if (csi == gs_color_space_index_ICC) {
507
221
        csi = gsicc_get_default_type(alt_space->cmm_icc_profile_data);
508
221
    }
509
221
    if (csi == gs_color_space_index_DeviceRGB && (pdev->PDFX ||
510
10
        (pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceCMYK)))) {
511
512
        /*
513
         * We shouldn't get here. If someoone is using PDF/X or PDF/A then they should *also*
514
         * set ColorConversionStrategy, and any Separation or DeviceN space should have been
515
         * converted earlier. If we somehow do get here (eg user set PDFA but *ddin't* set
516
         * ColorConversionStrategy) then return a rangecheck error. Earlier code will then
517
         * fall back to writing a device space.
518
         */
519
0
        dmprintf(pdev->pdf_memory, "Attempting to write a DeviceN space with an inappropriate alternate,\nhave you set ColorConversionStrategy ?\n");
520
0
        return gs_error_rangecheck;
521
0
    }
522
221
    if (csi == gs_color_space_index_DeviceCMYK &&
523
221
        (pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceRGB))) {
524
525
0
        dmprintf(pdev->pdf_memory, "Attempting to write a DeviceN space with an inappropriate alternate,\nhave you set ColorConversionStrategy ?\n");
526
0
        return gs_error_rangecheck;
527
0
    }
528
529
221
    if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
530
221
        (code = cos_array_add(pca, snames)) < 0 ||
531
221
        (code = pdf_color_space_named(pdev, pgs, &v, &ranges, alt_space, pcsn, false, NULL, 0, false)) < 0 ||
532
221
        (code = cos_array_add(pca, &v)) < 0 ||
533
221
        (code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
534
221
        (code = cos_array_add(pca, &v)) < 0 ||
535
221
        (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
536
221
        )
537
0
        return code;
538
221
    return 0;
539
221
}
540
541
/*
542
 * Create an Indexed color space.  This is a single-use procedure,
543
 * broken out only for readability.
544
 */
545
int
546
pdf_indexed_color_space(gx_device_pdf *pdev, const gs_gstate * pgs, cos_value_t *pvalue,
547
                        const gs_color_space *pcs, cos_array_t *pca, cos_value_t *cos_base)
548
122
{
549
122
    const gs_indexed_params *pip = &pcs->params.indexed;
550
122
    const gs_color_space *base_space = pcs->base_space;
551
122
    int num_entries = pip->hival + 1;
552
122
    int num_components = gs_color_space_num_components(base_space);
553
122
    uint table_size = num_entries * num_components;
554
    /* Guess at the extra space needed for PS string encoding. */
555
122
    uint string_size = 2 + table_size * 4;
556
122
    uint string_used;
557
122
    byte buf[100];    /* arbitrary */
558
122
    stream_AXE_state st;
559
122
    stream s, es;
560
122
    gs_memory_t *mem = pdev->pdf_memory;
561
122
    byte *table;
562
122
    byte *palette;
563
122
    cos_value_t v;
564
122
    int code;
565
566
    /* PDF doesn't support Indexed color spaces with more than 256 entries. */
567
122
    if (num_entries > 256)
568
0
        return_error(gs_error_rangecheck);
569
122
    if (pdev->CompatibilityLevel < 1.3 && !pdev->ForOPDFRead) {
570
0
        switch (gs_color_space_get_index(pcs)) {
571
0
            case gs_color_space_index_Pattern:
572
0
            case gs_color_space_index_Separation:
573
0
            case gs_color_space_index_Indexed:
574
0
            case gs_color_space_index_DeviceN:
575
0
                return_error(gs_error_rangecheck);
576
0
            default: DO_NOTHING;
577
0
        }
578
579
0
    }
580
122
    table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
581
122
    palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
582
122
    if (table == 0 || palette == 0) {
583
0
        gs_free_string(mem, palette, table_size,
584
0
                       "pdf_color_space(palette)");
585
0
        gs_free_string(mem, table, string_size,
586
0
                       "pdf_color_space(table)");
587
0
        return_error(gs_error_VMerror);
588
0
    }
589
122
    s_init(&s, mem);
590
122
    swrite_string(&s, table, string_size);
591
122
    s_init(&es, mem);
592
122
    s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
593
122
    s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
594
122
    sputc(&s, '(');
595
122
    if (pcs->params.indexed.use_proc) {
596
0
        gs_client_color cmin, cmax;
597
0
        byte *pnext = palette;
598
0
        int i, j;
599
600
        /* Find the legal range for the color components. */
601
0
        for (j = 0; j < num_components; ++j)
602
0
            cmin.paint.values[j] = (float)min_long,
603
0
                cmax.paint.values[j] = (float)max_long;
604
0
        gs_color_space_restrict_color(&cmin, base_space);
605
0
        gs_color_space_restrict_color(&cmax, base_space);
606
        /*
607
         * Compute the palette values, with the legal range for each
608
         * one mapped to [0 .. 255].
609
         */
610
0
        for (i = 0; i < num_entries; ++i) {
611
0
            gs_client_color cc;
612
613
0
            gs_cspace_indexed_lookup(pcs, i, &cc);
614
0
            for (j = 0; j < num_components; ++j) {
615
0
                float v = (cc.paint.values[j] - cmin.paint.values[j])
616
0
                    * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
617
618
0
                *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
619
0
            }
620
0
        }
621
0
    } else
622
122
        memcpy(palette, pip->lookup.table.data, table_size);
623
122
    if (gs_color_space_get_index(base_space) ==
624
122
        gs_color_space_index_DeviceRGB
625
122
        ) {
626
        /* Check for an all-gray palette3. */
627
0
        int i;
628
629
0
        for (i = table_size; (i -= 3) >= 0; )
630
0
            if (palette[i] != palette[i + 1] ||
631
0
                palette[i] != palette[i + 2]
632
0
                )
633
0
                break;
634
0
        if (i < 0) {
635
            /* Change the color space to DeviceGray. */
636
0
            for (i = 0; i < num_entries; ++i)
637
0
                palette[i] = palette[i * 3];
638
0
            table_size = num_entries;
639
0
            base_space = gs_cspace_new_DeviceGray(mem);
640
0
            if (base_space == NULL)
641
0
                return_error(gs_error_VMerror);
642
0
        }
643
0
    }
644
122
    stream_write(&es, palette, table_size);
645
122
    gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
646
    /* Another case where we use sclose() and not sclose_filters(), because the
647
     * buffer we supplied to s_init_filter is a heap based C object, so we
648
     * must not free it.
649
     */
650
122
    sclose(&es);
651
122
    sflush(&s);
652
122
    string_used = (uint)stell(&s);
653
122
    table = gs_resize_string(mem, table, string_size, string_used,
654
122
                             "pdf_color_space(table)");
655
    /*
656
     * Since the array is always referenced by name as a resource
657
     * rather than being written as a value, even for in-line images,
658
     * always use the full name for the color space.
659
     *
660
     * We don't have to worry about the range of the base space:
661
     * in PDF, unlike PostScript, the values from the lookup table are
662
     * scaled automatically.
663
     */
664
122
    if (cos_base == NULL) {
665
122
    if ((code = pdf_color_space_named(pdev, pgs, pvalue, NULL, base_space,
666
122
                                &pdf_color_space_names, false, NULL, 0, false)) < 0 ||
667
122
        (code = cos_array_add(pca,
668
122
                              cos_c_string_value(&v,
669
122
                                                 pdf_color_space_names.Indexed
670
122
                                                 /*pcsn->Indexed*/))) < 0 ||
671
122
        (code = cos_array_add(pca, pvalue)) < 0 ||
672
122
        (code = cos_array_add_int(pca, pip->hival)) < 0 ||
673
122
        (code = cos_array_add_no_copy(pca,
674
122
                                      cos_string_value(&v, table,
675
122
                                                       string_used))) < 0
676
122
        )
677
0
        return code;
678
122
    } else {
679
0
        code = cos_array_add(pca, cos_c_string_value(&v, pdf_color_space_names.Indexed));
680
0
        if (code < 0)
681
0
            return code;
682
0
        code = cos_array_add(pca, cos_base);
683
0
        if (code < 0)
684
0
            return code;
685
0
        code = cos_array_add_int(pca, pip->hival);
686
0
        if (code < 0)
687
0
            return code;
688
0
        code = cos_array_add_no_copy(pca, cos_string_value(&v, table, string_used));
689
0
        if (code < 0)
690
0
            return code;
691
0
    }
692
122
    return 0;
693
122
}
694
695
/*
696
 * Find a color space resource by seriialized data.
697
 */
698
static pdf_resource_t *
699
pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size)
700
12.3k
{
701
12.3k
    pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains;
702
12.3k
    pdf_resource_t *pres;
703
12.3k
    int i;
704
705
143k
    for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
706
150k
        for (pres = pchain[i]; pres != 0; pres = pres->next) {
707
19.6k
            const pdf_color_space_t *const ppcs =
708
19.6k
                (const pdf_color_space_t *)pres;
709
19.6k
            if (ppcs->serialized_size != serialized_size)
710
7.95k
                continue;
711
11.7k
            if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size))
712
8.73k
                return pres;
713
11.7k
        }
714
139k
    }
715
3.59k
    return NULL;
716
12.3k
}
717
718
int pdf_convert_ICC(gx_device_pdf *pdev,
719
                const gs_color_space *pcs, cos_value_t *pvalue,
720
                const pdf_color_space_names_t *pcsn)
721
0
{
722
0
    gs_color_space_index csi;
723
0
    int code;
724
725
0
    csi = gs_color_space_get_index(pcs);
726
0
    if (csi == gs_color_space_index_ICC) {
727
0
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
728
0
    }
729
0
    if (csi == gs_color_space_index_Indexed) {
730
0
        pcs = pcs->base_space;
731
0
        csi = gs_color_space_get_index(pcs);
732
0
    }
733
0
    if (csi == gs_color_space_index_ICC) {
734
0
        if (pcs->cmm_icc_profile_data == NULL ||
735
0
            pdev->CompatibilityLevel < 1.3
736
0
            ) {
737
0
            if (pcs->base_space != NULL) {
738
0
                return 0;
739
0
            } else {
740
0
                int num_des_comps;
741
0
                cmm_dev_profile_t *dev_profile;
742
743
                /* determine number of components in device space */
744
0
                code = dev_proc((gx_device *)pdev, get_profile)((gx_device *)pdev, &dev_profile);
745
0
                if (code < 0)
746
0
                    return code;
747
748
0
                num_des_comps = gsicc_get_device_profile_comps(dev_profile);
749
                /* Set image color space to be device space */
750
0
                switch( num_des_comps )  {
751
0
                    case 1:
752
0
                        cos_c_string_value(pvalue, pcsn->DeviceGray);
753
                        /* negative return means we do conversion */
754
0
                        return -1;
755
0
                    case 3:
756
0
                        cos_c_string_value(pvalue, pcsn->DeviceRGB);
757
0
                        return -1;
758
0
                    case 4:
759
0
                        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
760
0
                        return -1;
761
0
                    default:
762
0
                        break;
763
0
                }
764
0
            }
765
0
        }
766
0
    }
767
0
    return 0;
768
0
}
769
770
/*
771
 * Create a PDF color space corresponding to a PostScript color space.
772
 * For parameterless color spaces, set *pvalue to a (literal) string with
773
 * the color space name; for other color spaces, create a cos_array_t if
774
 * necessary and set *pvalue to refer to it.  In the latter case, if
775
 * by_name is true, return a string /Rxxxx rather than a reference to
776
 * the actual object.
777
 *
778
 * If ppranges is not NULL, then if  the domain of the color space had
779
 * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
780
 * to the ranges in *ppranges, otherwise set *ppranges to 0.
781
 */
782
int
783
pdf_color_space_named(gx_device_pdf *pdev, const gs_gstate * pgs,
784
                cos_value_t *pvalue,
785
                const gs_range_t **ppranges,
786
                const gs_color_space *pcs_in,
787
                const pdf_color_space_names_t *pcsn,
788
                bool by_name, const byte *res_name, int name_length, bool keepICC)
789
19.7k
{
790
19.7k
    const gs_color_space *pcs = pcs_in;
791
19.7k
    gs_color_space_index csi;
792
19.7k
    cos_array_t *pca;
793
19.7k
    cos_dict_t *pcd;
794
19.7k
    cos_value_t v;
795
19.7k
    const gs_cie_common *pciec;
796
19.7k
    gs_function_t *pfn;
797
19.7k
    const gs_range_t *ranges = 0;
798
19.7k
    uint serialized_size = 0;
799
19.7k
    byte *serialized = NULL, serialized0[100];
800
19.7k
    pdf_resource_t *pres = NULL;
801
19.7k
    int code;
802
19.7k
    bool is_lab = false;
803
804
19.7k
    csi = gs_color_space_get_index(pcs);
805
    /* Note that if csi is ICC, check to see if this was one of
806
       the default substitutes that we introduced for DeviceGray,
807
       DeviceRGB or DeviceCMYK.  If it is, then just write
808
       the default color.  Depending upon the flavor of PDF,
809
       or other options, we may want to actually have all
810
       the colors defined by ICC profiles and not do the following
811
       substituion of the Device space. */
812
19.7k
    if (csi == gs_color_space_index_ICC && !keepICC) {
813
10.3k
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
814
10.3k
    }
815
19.7k
    if (ppranges)
816
18.9k
        *ppranges = 0;   /* default */
817
19.7k
    switch (csi) {
818
781
    case gs_color_space_index_DeviceGray:
819
781
        cos_c_string_value(pvalue, pcsn->DeviceGray);
820
781
        return 0;
821
2.60k
    case gs_color_space_index_DeviceRGB:
822
2.60k
        cos_c_string_value(pvalue, pcsn->DeviceRGB);
823
2.60k
        return 0;
824
513
    case gs_color_space_index_DeviceCMYK:
825
513
        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
826
513
        return 0;
827
6
    case gs_color_space_index_Pattern:
828
6
        if (!pcs->params.pattern.has_base_space) {
829
0
            cos_c_string_value(pvalue, "/Pattern");
830
0
            return 0;
831
0
        }
832
6
        break;
833
7.77k
    case gs_color_space_index_ICC:
834
        /*
835
         * Take a special early exit for unrecognized ICCBased color spaces,
836
         * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
837
         */
838
839
7.77k
        if (pcs->cmm_icc_profile_data == NULL ||
840
7.77k
            pdev->CompatibilityLevel < 1.3
841
7.77k
            ) {
842
20
            if (res_name != NULL)
843
0
                return 0; /* Ignore .includecolorspace */
844
20
            if (pcs->base_space != NULL) {
845
0
            return pdf_color_space_named( pdev, pgs, pvalue, ppranges,
846
0
                                    pcs->base_space,
847
0
                                    pcsn, by_name, NULL, 0, keepICC);
848
20
            } else {
849
20
                switch( cs_num_components(pcs) )  {
850
0
                    case 1:
851
0
                        cos_c_string_value(pvalue, pcsn->DeviceGray);
852
0
                        return 0;
853
20
                    case 3:
854
20
                        cos_c_string_value(pvalue, pcsn->DeviceRGB);
855
20
                        return 0;
856
0
                    case 4:
857
0
                        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
858
0
                        return 0;
859
0
                    default:
860
0
                        break;
861
20
                }
862
20
            }
863
20
        }
864
865
7.75k
        break;
866
8.10k
    default:
867
8.10k
        break;
868
19.7k
    }
869
    /* Check whether we already have a PDF object for this color space. */
870
15.8k
    if (pcs->id != gs_no_id)
871
15.8k
        pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
872
15.8k
    if (pres == NULL) {
873
12.3k
        stream s;
874
875
12.3k
        s_init(&s, pdev->memory);
876
12.3k
        swrite_position_only(&s);
877
12.3k
        code = cs_serialize(pcs, &s);
878
12.3k
        if (code < 0)
879
0
            return_error(gs_error_unregistered); /* Must not happen. */
880
12.3k
        serialized_size = stell(&s);
881
        /* I think this is another case where we use sclose() and not sclose_filters().
882
         * It seems like we don't actually write anything, but it allows us to find the
883
         * length of the serialised data. No buffer hre, so we must no call
884
         * s_close_filters() as that will try to free it.
885
         */
886
12.3k
        sclose(&s);
887
12.3k
        if (serialized_size <= sizeof(serialized0))
888
0
            serialized = serialized0;
889
12.3k
        else {
890
12.3k
            serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
891
12.3k
            if (serialized == NULL)
892
0
                return_error(gs_error_VMerror);
893
12.3k
        }
894
12.3k
        swrite_string(&s, serialized, serialized_size);
895
12.3k
        code = cs_serialize(pcs, &s);
896
12.3k
        if (code < 0)
897
0
            return_error(gs_error_unregistered); /* Must not happen. */
898
12.3k
        if (stell(&s) != serialized_size)
899
0
            return_error(gs_error_unregistered); /* Must not happen. */
900
12.3k
        sclose(&s);
901
12.3k
        pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
902
12.3k
        if (pres != NULL) {
903
8.73k
            if (serialized != serialized0)
904
8.73k
                gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
905
8.73k
            serialized = NULL;
906
8.73k
        }
907
12.3k
    }
908
15.8k
    if (pres) {
909
12.2k
        const pdf_color_space_t *const ppcs =
910
12.2k
            (const pdf_color_space_t *)pres;
911
912
12.2k
        if (ppranges != 0 && ppcs->ranges != 0)
913
0
            *ppranges = ppcs->ranges;
914
12.2k
        pca = (cos_array_t *)pres->object;
915
12.2k
        goto ret;
916
12.2k
    }
917
918
    /* Space has parameters -- create an array. */
919
3.59k
    pca = cos_array_alloc(pdev, "pdf_color_space");
920
3.59k
    if (pca == 0)
921
0
        return_error(gs_error_VMerror);
922
923
3.59k
    switch (csi) {
924
925
3.25k
    case gs_color_space_index_ICC:
926
3.25k
        code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs, pca);
927
3.25k
        break;
928
929
0
    case gs_color_space_index_CIEA: {
930
        /* Check that we can represent this as a CalGray space. */
931
0
        const gs_cie_a *pcie = pcs->params.a;
932
0
        bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
933
0
        bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
934
0
                          pcie->MatrixA.w == 1);
935
0
        gs_vector3 expts;
936
937
0
        pciec = (const gs_cie_common *)pcie;
938
0
        if (!pcie->common.MatrixLMN.is_identity) {
939
0
            if (!pdev->ForOPDFRead) {
940
0
                if (pcs->icc_equivalent == 0) {
941
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
942
0
                    if (code < 0)
943
0
                        return code;
944
0
                }
945
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
946
0
                if (pcs->params.a->RangeA.rmin < 0.0 || pcs->params.a->RangeA.rmax > 1.0)
947
0
                        ranges = &pcs->params.a->RangeA;
948
0
            } else {
949
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
950
0
                                         &pcie->RangeA, ONE_STEP_NOT, NULL,
951
0
                                         &ranges);
952
0
            }
953
0
            break;
954
0
        }
955
0
        if (unitary && identityA &&
956
0
            CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
957
0
            CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
958
0
            expts.v == expts.u && expts.w == expts.u
959
0
            ) {
960
0
            DO_NOTHING;
961
0
        } else if (unitary && identityA &&
962
0
                   CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
963
0
                   cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
964
0
                   ) {
965
0
            DO_NOTHING;
966
0
        } else {
967
0
            if (!pdev->ForOPDFRead) {
968
0
                if (pcs->icc_equivalent == 0) {
969
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
970
0
                    if (code < 0)
971
0
                        return code;
972
0
                }
973
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
974
0
                if (pcs->params.a->RangeA.rmin < 0.0 || pcs->params.a->RangeA.rmax > 1.0)
975
0
                        ranges = &pcs->params.a->RangeA;
976
0
            } else {
977
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
978
0
                                         &pcie->RangeA, ONE_STEP_NOT, NULL,
979
0
                                         &ranges);
980
0
            }
981
0
            break;
982
0
        }
983
0
        code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
984
0
        if (code < 0)
985
0
            return code;
986
0
        pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
987
0
        if (pcd == 0)
988
0
            return_error(gs_error_VMerror);
989
0
        if (expts.u != 1) {
990
0
            code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
991
0
            if (code < 0)
992
0
                return code;
993
0
        }
994
0
    }
995
0
    cal:
996
    /* Finish handling a CIE-based color space (Calxxx or Lab). */
997
0
    if (code < 0)
998
0
        return code;
999
0
    code = pdf_finish_cie_space(pdev, pca, pcd, pciec);
1000
0
    break;
1001
1002
0
    case gs_color_space_index_CIEABC: {
1003
        /* Check that we can represent this as a CalRGB space. */
1004
0
        const gs_cie_abc *pcie = pcs->params.abc;
1005
0
        bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
1006
0
        gs_vector3 expts;
1007
0
        const gs_matrix3 *pmat = NULL;
1008
0
        cie_cache_one_step_t one_step =
1009
0
            cie_cached_abc_is_one_step(pcie, &pmat);
1010
1011
0
        pciec = (const gs_cie_common *)pcie;
1012
0
        if (unitary) {
1013
0
            switch (one_step) {
1014
0
            case ONE_STEP_ABC:
1015
0
                if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
1016
0
                    goto calrgb;
1017
0
                break;
1018
0
            case ONE_STEP_LMN:
1019
0
                if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
1020
0
                    goto calrgb;
1021
0
            default:
1022
0
                break;
1023
0
            }
1024
0
        }
1025
0
        if (cie_is_lab(pcie)) {
1026
            /* Represent this as a Lab space. */
1027
0
            pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1028
0
            if (pcd == 0)
1029
0
                return_error(gs_error_VMerror);
1030
0
            code = pdf_put_lab_color_space(pdev, pca, pcd, pcie->RangeABC.ranges);
1031
0
            goto cal;
1032
0
        } else {
1033
0
            if (!pdev->ForOPDFRead) {
1034
0
                int i;
1035
1036
0
                if (pcs->icc_equivalent == 0) {
1037
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
1038
0
                    if (code < 0)
1039
0
                        return code;
1040
0
                }
1041
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
1042
0
                for (i = 0; i < 3; ++i) {
1043
0
                    double rmin = pcs->params.abc->RangeABC.ranges[i].rmin, rmax = pcs->params.abc->RangeABC.ranges[i].rmax;
1044
1045
0
                    if (rmin < 0.0 || rmax > 1.0)
1046
0
                        ranges = pcs->params.abc->RangeABC.ranges;
1047
0
                }
1048
0
            } else {
1049
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
1050
0
                                         pcie->RangeABC.ranges,
1051
0
                                         one_step, pmat, &ranges);
1052
0
            }
1053
0
            break;
1054
0
        }
1055
0
    calrgb:
1056
0
        code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
1057
0
        if (code < 0)
1058
0
            return code;
1059
0
        pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1060
0
        if (pcd == 0)
1061
0
            return_error(gs_error_VMerror);
1062
0
        if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
1063
0
            code = cos_dict_put_c_key_vector3(pdev, pcd, "/Gamma", &expts);
1064
0
            if (code < 0)
1065
0
                return code;
1066
0
        }
1067
0
        if (!pmat->is_identity) {
1068
0
            cos_array_t *pcma =
1069
0
                cos_array_alloc(pdev, "pdf_color_space(Matrix)");
1070
1071
0
            if (pcma == 0)
1072
0
                return_error(gs_error_VMerror);
1073
0
            if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
1074
0
                (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
1075
0
                (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
1076
0
                (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
1077
0
                                     COS_OBJECT_VALUE(&v, pcma))) < 0
1078
0
                )
1079
0
                return code;
1080
0
        }
1081
0
    }
1082
0
    goto cal;
1083
1084
0
    case gs_color_space_index_CIEDEF:
1085
0
            if (!pdev->ForOPDFRead) {
1086
0
                int i;
1087
0
                if (pcs->icc_equivalent == 0) {
1088
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
1089
0
                    if (code < 0)
1090
0
                        return code;
1091
0
                }
1092
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
1093
0
                for (i = 0; i < 3; ++i) {
1094
0
                    double rmin = pcs->params.def->RangeDEF.ranges[i].rmin, rmax = pcs->params.def->RangeDEF.ranges[i].rmax;
1095
1096
0
                    if (rmin < 0.0 || rmax > 1.0)
1097
0
                        ranges = pcs->params.def->RangeDEF.ranges;
1098
0
                }
1099
0
            } else {
1100
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
1101
0
                                     (const gs_cie_common *)pcs->params.def,
1102
0
                                     pcs->params.def->RangeDEF.ranges,
1103
0
                                     ONE_STEP_NOT, NULL, &ranges);
1104
0
            }
1105
0
        break;
1106
1107
0
    case gs_color_space_index_CIEDEFG:
1108
0
            if (!pdev->ForOPDFRead) {
1109
0
                int i;
1110
0
                if (pcs->icc_equivalent == 0) {
1111
0
                    code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory);
1112
0
                    if (code < 0)
1113
0
                        return code;
1114
0
                }
1115
0
                code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca);
1116
0
                for (i = 0; i < 4; ++i) {
1117
0
                    double rmin = pcs->params.defg->RangeDEFG.ranges[i].rmin, rmax = pcs->params.defg->RangeDEFG.ranges[i].rmax;
1118
1119
0
                    if (rmin < 0.0 || rmax > 1.0)
1120
0
                        ranges = pcs->params.defg->RangeDEFG.ranges;
1121
0
                }
1122
0
            } else {
1123
0
                code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
1124
0
                                     (const gs_cie_common *)pcs->params.defg,
1125
0
                                     pcs->params.defg->RangeDEFG.ranges,
1126
0
                                     ONE_STEP_NOT, NULL, &ranges);
1127
0
            }
1128
0
        break;
1129
1130
122
    case gs_color_space_index_Indexed:
1131
122
        code = pdf_indexed_color_space(pdev, pgs, pvalue, pcs, pca, NULL);
1132
122
        break;
1133
1134
13
    case gs_color_space_index_DeviceN:
1135
13
        if (!pdev->PreserveDeviceN)
1136
0
            return_error(gs_error_rangecheck);
1137
13
        if (pdev->CompatibilityLevel < 1.3)
1138
0
            return_error(gs_error_rangecheck);
1139
13
        pfn = gs_cspace_get_devn_function(pcs);
1140
        /****** CURRENTLY WE ONLY HANDLE Functions ******/
1141
13
        if (pfn == 0)
1142
0
            return_error(gs_error_rangecheck);
1143
13
        {
1144
13
            cos_array_t *psna =
1145
13
                cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
1146
13
            int i;
1147
13
            byte *name_string;
1148
13
            uint name_string_length;
1149
13
            cos_value_t v_attributes, *va = NULL;
1150
13
            pdf_resource_t *pres_attributes = NULL;
1151
1152
13
            if (psna == 0)
1153
0
                return_error(gs_error_VMerror);
1154
45
            for (i = 0; i < pcs->params.device_n.num_components; ++i) {
1155
32
                name_string = (byte *)pcs->params.device_n.names[i];
1156
32
                name_string_length = strlen(pcs->params.device_n.names[i]);
1157
1158
32
                code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v);
1159
32
                if (code < 0)
1160
0
                    return code;
1161
32
                code = cos_array_add(psna, &v);
1162
32
                cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(DeviceN component)");
1163
32
                if (code < 0)
1164
0
                    return code;
1165
32
            }
1166
13
            COS_OBJECT_VALUE(&v, psna);
1167
1168
            /* If we have either /Process or /Colorants (or both) then we need to create an
1169
             * attributes dictionary.
1170
             */
1171
13
            if (pcs->params.device_n.devn_process_space != NULL || pcs->params.device_n.colorants != NULL) {
1172
9
                cos_value_t v_Subtype_name;
1173
1174
9
                code = pdf_alloc_resource(pdev, resourceOther, 0, &pres_attributes, -1);
1175
9
                if (code < 0)
1176
0
                    return code;
1177
9
                cos_become(pres_attributes->object, cos_type_dict);
1178
1179
9
                if (pcs->params.device_n.subtype == gs_devicen_DeviceN) {
1180
0
                    code = pdf_string_to_cos_name(pdev, (const byte *)"DeviceN", 7, &v_Subtype_name);
1181
0
                    if (code < 0)
1182
0
                        return code;
1183
9
                } else {
1184
9
                    if (pcs->params.device_n.subtype == gs_devicen_NChannel) {
1185
9
                        code = pdf_string_to_cos_name(pdev, (const byte *)"NChannel", 8, &v_Subtype_name);
1186
9
                        if (code < 0)
1187
0
                            return code;
1188
9
                    } else
1189
0
                        return gs_note_error(gs_error_typecheck);
1190
9
                }
1191
9
                code = cos_dict_put((cos_dict_t *)pres_attributes->object, (const byte *)"/Subtype", 8, &v_Subtype_name);
1192
9
                cos_value_free((const cos_value_t *)&v_Subtype_name, pdev->pdf_memory, "pdf_color_space(Subtype)");
1193
9
                if (code < 0)
1194
0
                    return code;
1195
9
            }
1196
13
            if (pcs->params.device_n.devn_process_space != NULL) {
1197
9
                cos_dict_t *process;
1198
9
                cos_array_t *components;
1199
9
                cos_value_t v_process, v_components, v_process_space, v_process_name;
1200
9
                int m;
1201
1202
9
                process = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
1203
9
                if (process == NULL)
1204
0
                    return_error(gs_error_VMerror);
1205
1206
9
                COS_OBJECT_VALUE(&v_process, process);
1207
9
                code = cos_dict_put((cos_dict_t *)pres_attributes->object,
1208
9
                    (const byte *)"/Process", 8, &v_process);
1209
9
                if (code < 0)
1210
0
                    return code;
1211
1212
9
                code = pdf_color_space_named(pdev, pgs, &v_process_space, NULL, pcs->params.device_n.devn_process_space, pcsn, false, NULL, 0, keepICC);
1213
9
                 if (code < 0)
1214
0
                     return code;
1215
9
                code = pdf_string_to_cos_name(pdev, (const byte *)"ColorSpace", 10, &v_process_name);
1216
9
                if (code < 0)
1217
0
                    return code;
1218
9
                code = cos_dict_put(process, v_process_name.contents.chars.data,
1219
9
                                    v_process_name.contents.chars.size, &v_process_space);
1220
9
                cos_value_free((const cos_value_t *)&v_process_name, pdev->pdf_memory, "pdf_color_space(ColorSpace)");
1221
9
                if (code < 0)
1222
0
                    return code;
1223
1224
9
                components = cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
1225
9
                if (components == NULL) {
1226
0
                    return_error(gs_error_VMerror);
1227
0
                }
1228
9
                COS_OBJECT_VALUE(&v_components, components);
1229
9
                code = cos_dict_put((cos_dict_t *)process,
1230
9
                    (const byte *)"/Components", 11, &v_components);
1231
9
                if (code < 0)
1232
0
                    return code;
1233
45
                for (m=0;m < pcs->params.device_n.num_process_names;m++) {
1234
36
                    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);
1235
36
                    if (code < 0)
1236
0
                        return code;
1237
36
                    code = cos_array_put(components, m, &v_process_name);
1238
36
                    cos_value_free((const cos_value_t *)&v_process_name, pdev->pdf_memory, "pdf_color_space(process_name)");
1239
36
                    if (code < 0)
1240
0
                        return code;
1241
36
                }
1242
1243
9
            }
1244
13
            if (pcs->params.device_n.colorants != NULL) {
1245
0
                cos_dict_t *colorants  = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
1246
0
                cos_value_t v_colorants, v_separation, v_colorant_name;
1247
0
                const gs_device_n_colorant *csa;
1248
1249
0
                if (colorants == NULL)
1250
0
                    return_error(gs_error_VMerror);
1251
1252
0
                COS_OBJECT_VALUE(&v_colorants, colorants);
1253
0
                code = cos_dict_put((cos_dict_t *)pres_attributes->object,
1254
0
                    (const byte *)"/Colorants", 10, &v_colorants);
1255
0
                if (code < 0)
1256
0
                    return code;
1257
0
                for (csa = pcs->params.device_n.colorants; csa != NULL; csa = csa->next) {
1258
0
                    name_string = (byte *)csa->colorant_name;
1259
0
                    name_string_length = strlen((const char *)name_string);
1260
0
                    code = pdf_color_space_named(pdev, pgs, &v_separation, NULL, csa->cspace, pcsn, false, NULL, 0, keepICC);
1261
0
                    if (code < 0)
1262
0
                        return code;
1263
0
                    code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v_colorant_name);
1264
0
                    if (code < 0)
1265
0
                        return code;
1266
0
                    code = cos_dict_put(colorants, v_colorant_name.contents.chars.data,
1267
0
                                        v_colorant_name.contents.chars.size, &v_separation);
1268
0
                    cos_value_free((const cos_value_t *)&v_colorant_name, pdev->pdf_memory, "pdf_color_space(Subtype)");
1269
0
                    if (code < 0)
1270
0
                        return code;
1271
0
                }
1272
0
            }
1273
13
            if (pres_attributes != NULL) {
1274
9
                code = pdf_substitute_resource(pdev, &pres_attributes, resourceOther, NULL, true);
1275
9
                if (code < 0)
1276
0
                    return code;
1277
9
                pres_attributes->where_used |= pdev->used_mask;
1278
9
                va = &v_attributes;
1279
9
                COS_OBJECT_VALUE(va, pres_attributes->object);
1280
9
            }
1281
13
            code = pdf_separation_color_space(pdev, pgs, pca, "/DeviceN", &v,
1282
13
                                                   pcs->base_space,
1283
13
                                        pfn, &pdf_color_space_names, va);
1284
13
            if (v.value_type == COS_VALUE_SCALAR)
1285
0
                cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(Devicen)");
1286
13
            if (va != NULL && va->value_type == COS_VALUE_SCALAR)
1287
0
                cos_value_free((const cos_value_t *)&va, pdev->pdf_memory, "pdf_color_space(Devicen)");
1288
13
            if (code < 0)
1289
0
                return code;
1290
13
        }
1291
13
        break;
1292
1293
208
    case gs_color_space_index_Separation:
1294
208
        if (!pdev->PreserveSeparation)
1295
0
            return_error(gs_error_rangecheck);
1296
208
        pfn = gs_cspace_get_sepr_function(pcs);
1297
        /****** CURRENTLY WE ONLY HANDLE Functions ******/
1298
208
        if (pfn == 0)
1299
0
            return_error(gs_error_rangecheck);
1300
208
        {
1301
208
            code = pdf_string_to_cos_name(pdev, (const byte *)pcs->params.separation.sep_name,
1302
208
                                      strlen(pcs->params.separation.sep_name), &v);
1303
208
            if (code < 0)
1304
0
                return code;
1305
1306
208
            code = pdf_separation_color_space(pdev, pgs, pca, "/Separation", &v,
1307
208
                                            pcs->base_space,
1308
208
                                            pfn, &pdf_color_space_names, NULL);
1309
208
            if (v.value_type == COS_VALUE_SCALAR)
1310
208
                cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(Separation name)");
1311
208
            if (code < 0)
1312
0
                return code;
1313
208
        }
1314
208
        break;
1315
1316
208
    case gs_color_space_index_Pattern:
1317
2
        if ((code = pdf_color_space_named(pdev, pgs, pvalue, ppranges,
1318
2
                                    pcs->base_space,
1319
2
                                    &pdf_color_space_names, false, NULL, 0, false)) < 0 ||
1320
2
            (code = cos_array_add(pca,
1321
2
                                  cos_c_string_value(&v, "/Pattern"))) < 0 ||
1322
2
            (code = cos_array_add(pca, pvalue)) < 0
1323
2
            )
1324
0
            return code;
1325
2
        break;
1326
1327
2
    default:
1328
0
        return_error(gs_error_rangecheck);
1329
3.59k
    }
1330
1331
    /*
1332
     * Register the color space as a resource, since it must be referenced
1333
     * by name rather than directly.
1334
     */
1335
3.59k
    {
1336
3.59k
        pdf_color_space_t *ppcs;
1337
1338
3.59k
        if (code < 0 ||
1339
3.59k
            (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
1340
3.59k
                                       &pres, -1)) < 0
1341
3.59k
            ) {
1342
0
            COS_FREE(pca, "pdf_color_space");
1343
0
            return code;
1344
0
        }
1345
3.59k
        pdf_reserve_object_id(pdev, pres, 0);
1346
3.59k
        if (res_name != NULL) {
1347
0
            int l = min(name_length, sizeof(pres->rname) - 1);
1348
1349
0
            memcpy(pres->rname, res_name, l);
1350
0
            pres->rname[l] = 0;
1351
0
        }
1352
3.59k
        ppcs = (pdf_color_space_t *)pres;
1353
3.59k
        if (serialized == serialized0) {
1354
0
            serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
1355
0
            if (serialized == NULL)
1356
0
                return_error(gs_error_VMerror);
1357
0
            memcpy(serialized, serialized0, serialized_size);
1358
0
        }
1359
3.59k
        ppcs->serialized = serialized;
1360
3.59k
        ppcs->serialized_size = serialized_size;
1361
3.59k
        if (ranges) {
1362
0
            int num_comp = gs_color_space_num_components(pcs);
1363
0
            gs_range_t *copy_ranges = (gs_range_t *)
1364
0
                gs_alloc_byte_array(pdev->pdf_memory, num_comp,
1365
0
                                    sizeof(gs_range_t), "pdf_color_space");
1366
1367
0
            if (copy_ranges == 0) {
1368
0
                COS_FREE(pca, "pdf_color_space");
1369
0
                return_error(gs_error_VMerror);
1370
0
            }
1371
0
            memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
1372
0
            ppcs->ranges = copy_ranges;
1373
0
            if (ppranges)
1374
0
                *ppranges = copy_ranges;
1375
0
        } else
1376
3.59k
            ppcs->ranges = 0;
1377
3.59k
        pca->id = pres->object->id;
1378
3.59k
        COS_FREE(pres->object, "pdf_color_space");
1379
3.59k
        pres->object = (cos_object_t *)pca;
1380
3.59k
        cos_write_object(COS_OBJECT(pca), pdev, resourceColorSpace);
1381
3.59k
    }
1382
15.8k
 ret:
1383
15.8k
    if (by_name) {
1384
        /* Return a resource name rather than an object reference. */
1385
13.1k
        discard(COS_RESOURCE_VALUE(pvalue, pca));
1386
13.1k
    } else
1387
15.8k
        discard(COS_OBJECT_VALUE(pvalue, pca));
1388
15.8k
    if (pres != NULL) {
1389
15.8k
        pres->where_used |= pdev->used_mask;
1390
15.8k
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
1391
15.8k
        if (code < 0)
1392
0
            return code;
1393
15.8k
    }
1394
15.8k
    return 0;
1395
15.8k
}
1396
1397
int free_color_space(gx_device_pdf *pdev, pdf_resource_t *pres)
1398
3.69k
{
1399
3.69k
    pdf_color_space_t *ppcs = (pdf_color_space_t *)pres;
1400
1401
3.69k
    if (ppcs->serialized)
1402
3.59k
        gs_free_object(pdev->pdf_memory, ppcs->serialized, "free serialized colour space");
1403
3.69k
    if (pres->object) {
1404
3.69k
        cos_release(pres->object, "release ColorSpace object");
1405
3.69k
        gs_free_object(pdev->pdf_memory, pres->object, "free ColorSpace object");
1406
3.69k
        pres->object = 0;
1407
3.69k
    }
1408
3.69k
    return 0;
1409
3.69k
}
1410
1411
/* ---------------- Miscellaneous ---------------- */
1412
1413
/* Create colored and uncolored Pattern color spaces. */
1414
static int
1415
pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
1416
                  pdf_resource_t **ppres, const char *cs_name)
1417
3.00k
{
1418
3.00k
    int code;
1419
1420
3.00k
    if (!*ppres) {
1421
98
        int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
1422
98
                                           ppres);
1423
1424
98
        if (code < 0)
1425
0
            return code;
1426
98
        pprints1(pdev->strm, "%s\n", cs_name);
1427
98
        pdf_end_resource(pdev, resourceColorSpace);
1428
98
        (*ppres)->object->written = true; /* don't write at end */
1429
98
        ((pdf_color_space_t *)*ppres)->ranges = 0;
1430
98
        ((pdf_color_space_t *)*ppres)->serialized = 0;
1431
98
    }
1432
3.00k
    code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres);
1433
3.00k
    if (code < 0)
1434
0
        return code;
1435
3.00k
    cos_resource_value(pvalue, (*ppres)->object);
1436
3.00k
    return 0;
1437
3.00k
}
1438
int
1439
pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
1440
3.00k
{
1441
3.00k
    return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
1442
3.00k
                             "[/Pattern]");
1443
3.00k
}
1444
int
1445
pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
1446
0
{
1447
    /* Only for process colors. */
1448
0
    int ncomp = pdev->color_info.num_components;
1449
0
    static const char *const pcs_names[5] = {
1450
0
        0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
1451
0
        "[/Pattern /DeviceCMYK]"
1452
0
    };
1453
1454
0
    return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
1455
0
                             pcs_names[ncomp]);
1456
0
}
1457
int
1458
pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev,
1459
                const gs_color_space *pcs, cos_value_t *pvalue, const gs_gstate * pgs)
1460
6
{
1461
    /* Only for high level colors. */
1462
6
    return pdf_color_space_named(pdev, pgs, pvalue, NULL, pcs, &pdf_color_space_names, true, NULL, 0, false);
1463
6
}
1464
1465
/* Set the ProcSets bits corresponding to an image color space. */
1466
void
1467
pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
1468
4.82k
{
1469
4.82k
    const gs_color_space *pbcs = pcs;
1470
1471
5.23k
 csw:
1472
5.23k
    switch (gs_color_space_get_index(pbcs)) {
1473
0
    case gs_color_space_index_DeviceGray:
1474
0
    case gs_color_space_index_CIEA:
1475
        /* We only handle CIEBasedA spaces that map to CalGray. */
1476
0
        pdev->procsets |= ImageB;
1477
0
        break;
1478
417
    case gs_color_space_index_Indexed:
1479
417
        pdev->procsets |= ImageI;
1480
417
        pbcs = pcs->base_space;
1481
417
        goto csw;
1482
4.82k
    default:
1483
4.82k
        pdev->procsets |= ImageC;
1484
4.82k
        break;
1485
5.23k
    }
1486
5.23k
}