1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
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.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
17
/* Color space management and writing for pdfwrite driver */
21
#include "gscspace.h" /* for gscie.h */
29
#include "gsfunc.h" /* required for colour space function evaluation */
30
#include "gsfunc3.h" /* Required to create a replacement lineat interpolation function */
40
#include "gsicc_manage.h"
41
#include "gsicc_cache.h"
44
* PDF doesn't have general CIEBased color spaces. However, it provides
45
* two methods for handling general CIE spaces:
47
* - For PDF 1.2 and above, we note that the transformation from L*a*b*
48
* space to XYZ space is invertible, so we can handle any PostScript
49
* CIEBased space by transforming color values in that space to XYZ,
50
* then inverse-transforming them to L*a*b* and using a PDF Lab space
51
* with the same WhitePoint and BlackPoint and appropriate ranges for
52
* a and b. This approach has the drawback that Y values outside the
53
* range [0..1] can't be represented: we just clamp them.
55
* - For PDF 1.3 and above, we can create an ICCBased space. This is
56
* actually necessary, not just an option, because for shadings (also
57
* introduced in PDF 1.3), we want color interpolation to occur in the
60
* The Lab approach is not currently implemented, because it requires
61
* transforming all the sample values of images. The ICCBased approach is
62
* implemented for color spaces whose ranges lie within [0..1], which are
63
* the only ranges supported by the ICC standard: we think that removing
64
* this limitation would also require transforming image sample values.
68
public_st_pdf_color_space();
70
/* ------ CIE space testing ------ */
72
/* Test whether a cached CIE procedure is the identity function. */
73
#define CIE_CACHE_IS_IDENTITY(pc)\
74
((pc)->floats.params.is_identity)
75
#define CIE_CACHE3_IS_IDENTITY(pca)\
76
(CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\
77
CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\
78
CIE_CACHE_IS_IDENTITY(&(pca)[2]))
81
* Test whether a cached CIE procedure is an exponential. A cached
82
* procedure is exponential iff f(x) = k*(x^p). We make a very cursory
83
* check for this: we require that f(0) = 0, set k = f(1), set p =
84
* log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
85
* two arbitrarily chosen values between 0 and 1. Naturally all this is
86
* done with some slop.
88
#define CC_INDEX_A (gx_cie_cache_size / 3)
89
#define CC_INDEX_B (gx_cie_cache_size * 2 / 3)
90
#define CC_INDEX_1 (gx_cie_cache_size - 1)
91
#define CC_KEY(i) ((i) / (double)CC_INDEX_1)
92
#define CC_KEY_A CC_KEY(CC_INDEX_A)
93
#define CC_KEY_B CC_KEY(CC_INDEX_B)
96
cie_values_are_exponential(floatp v0, floatp va, floatp vb, floatp k,
101
if (fabs(v0) >= 0.001 || fabs(k) < 0.001)
103
if (va == 0 || (va > 0) != (k > 0))
105
p = log(va / k) / log(CC_KEY_A);
106
if (fabs(vb - k * pow(CC_KEY_B, p)) >= 0.001)
113
cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt)
115
return cie_values_are_exponential(pc->floats.values[0],
116
pc->floats.values[CC_INDEX_A],
117
pc->floats.values[CC_INDEX_B],
118
pc->floats.values[CC_INDEX_1],
121
#define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\
122
(cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\
123
cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\
124
cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w))
127
cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt)
129
return cie_values_are_exponential(pc->vecs.values[0].u,
130
pc->vecs.values[CC_INDEX_A].u,
131
pc->vecs.values[CC_INDEX_B].u,
132
pc->vecs.values[CC_INDEX_1].u,
135
#define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\
136
(cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\
137
cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\
138
cie_vector_cache_is_exponential(&(pca)[2], &(expts).w))
146
* Test whether a cached CIEBasedABC space consists only of a single
147
* Decode step followed by a single Matrix step.
149
static cie_cache_one_step_t
150
cie_cached_abc_is_one_step(const gs_cie_abc *pcie, const gs_matrix3 **ppmat)
152
/* The order of steps is, DecodeABC, MatrixABC, DecodeLMN, MatrixLMN. */
154
if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN)) {
155
if (pcie->MatrixABC.is_identity) {
156
*ppmat = &pcie->common.MatrixLMN;
159
if (pcie->common.MatrixLMN.is_identity) {
160
*ppmat = &pcie->MatrixABC;
164
if (CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC.caches)) {
165
if (pcie->MatrixABC.is_identity) {
166
*ppmat = &pcie->common.MatrixLMN;
174
* Test whether a cached CIEBasedABC space is a L*a*b* space.
177
cie_scalar_cache_is_lab_lmn(const gs_cie_abc *pcie, int i)
179
double k = CC_KEY(i);
180
double g = (k >= 6.0 / 29 ? k * k * k :
181
(k - 4.0 / 29) * (108.0 / 841));
183
#define CC_V(j,i) (pcie->common.caches.DecodeLMN[j].floats.values[i])
184
#define CC_WP(uvw) (pcie->common.points.WhitePoint.uvw)
186
return (fabs(CC_V(0, i) - g * CC_WP(u)) < 0.001 &&
187
fabs(CC_V(1, i) - g * CC_WP(v)) < 0.001 &&
188
fabs(CC_V(2, i) - g * CC_WP(w)) < 0.001
195
cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t *pvc, int i)
197
const gx_cie_vector_cache *const pc3 = pvc->caches;
198
double k = CC_KEY(i);
199
double l0 = pc3[0].vecs.params.base,
200
l = l0 + k * (pc3[0].vecs.params.limit - l0);
201
double a0 = pc3[1].vecs.params.base,
202
a = a0 + k * (pc3[1].vecs.params.limit - a0);
203
double b0 = pc3[2].vecs.params.base,
204
b = b0 + k * (pc3[2].vecs.params.limit - b0);
206
return (fabs(cie_cached2float(pc3[0].vecs.values[i].u) -
207
(l + 16) / 116) < 0.001 &&
208
fabs(cie_cached2float(pc3[1].vecs.values[i].u) -
210
fabs(cie_cached2float(pc3[2].vecs.values[i].w) -
216
cie_is_lab(const gs_cie_abc *pcie)
220
/* Check MatrixABC and MatrixLMN. */
221
if (!(pcie->MatrixABC.cu.u == 1 && pcie->MatrixABC.cu.v == 1 &&
222
pcie->MatrixABC.cu.w == 1 &&
223
pcie->MatrixABC.cv.u == 1 && pcie->MatrixABC.cv.v == 0 &&
224
pcie->MatrixABC.cv.w == 0 &&
225
pcie->MatrixABC.cw.u == 0 && pcie->MatrixABC.cw.v == 0 &&
226
pcie->MatrixABC.cw.w == -1 &&
227
pcie->common.MatrixLMN.is_identity
231
/* Check DecodeABC and DecodeLMN. */
232
for (i = 0; i <= CC_INDEX_1; ++i)
233
if (!(cie_vector_cache_is_lab_abc(&pcie->caches.DecodeABC, i) &&
234
cie_scalar_cache_is_lab_lmn(pcie, i)
244
/* Test whether one or more CIE-based ranges are [0..1]. */
246
cie_ranges_are_0_1(const gs_range *prange, int n)
250
for (i = 0; i < n; ++i)
251
if (prange[i].rmin != 0 || prange[i].rmax != 1)
256
/* ------ Utilities ------ */
258
/* Add a 3-element vector to a Cos array or dictionary. */
260
cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec)
262
int code = cos_array_add_real(pca, pvec->u);
265
code = cos_array_add_real(pca, pvec->v);
267
code = cos_array_add_real(pca, pvec->w);
271
cos_dict_put_c_key_vector3(cos_dict_t *pcd, const char *key,
272
const gs_vector3 *pvec)
274
cos_array_t *pca = cos_array_alloc(pcd->pdev, "cos_array_from_vector3");
278
return_error(gs_error_VMerror);
279
code = cos_array_add_vector3(pca, pvec);
281
COS_FREE(pca, "cos_array_from_vector3");
284
return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
288
* Finish creating a CIE-based color space (Calxxx or Lab.)
289
* This procedure is exported for gdevpdfk.c.
292
pdf_finish_cie_space(cos_array_t *pca, cos_dict_t *pcd,
293
const gs_cie_common *pciec)
295
int code = cos_dict_put_c_key_vector3(pcd, "/WhitePoint",
296
&pciec->points.WhitePoint);
300
if (pciec->points.BlackPoint.u != 0 ||
301
pciec->points.BlackPoint.v != 0 ||
302
pciec->points.BlackPoint.w != 0
304
code = cos_dict_put_c_key_vector3(pcd, "/BlackPoint",
305
&pciec->points.BlackPoint);
309
return cos_array_add_object(pca, COS_OBJECT(pcd));
312
/* ------ Color space writing ------ */
314
/* Define standard and short color space names. */
315
const pdf_color_space_names_t pdf_color_space_names = {
316
PDF_COLOR_SPACE_NAMES
318
const pdf_color_space_names_t pdf_color_space_names_short = {
319
PDF_COLOR_SPACE_NAMES_SHORT
323
* Create a local Device{Gray,RGB,CMYK} color space corresponding to the
324
* given number of components.
327
pdf_cspace_init_Device(gs_memory_t *mem, gs_color_space **ppcs,
330
switch (num_components) {
331
case 1: *ppcs = gs_cspace_new_DeviceGray(mem); break;
332
case 3: *ppcs = gs_cspace_new_DeviceRGB(mem); break;
333
case 4: *ppcs = gs_cspace_new_DeviceCMYK(mem); break;
334
default: return_error(gs_error_rangecheck);
339
static int pdf_delete_base_space_function(gx_device_pdf *pdev, gs_function_t *pfn)
341
gs_function_ElIn_params_t *params = (gs_function_ElIn_params_t *)&pfn->params;
343
gs_free_object(pdev->memory, (void *)params->Domain, "pdf_delete_function");
344
gs_free_object(pdev->memory, (void *)params->Range, "pdf_delete_function");
345
gs_free_object(pdev->memory, (void *)params->C0, "pdf_delete_function");
346
gs_free_object(pdev->memory, (void *)params->C1, "pdf_delete_function");
347
gs_free_object(pdev->memory, (void *)pfn, "pdf_delete_function");
351
static int pdf_make_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn,
352
int ncomp, float *data_low, float *data_high)
354
gs_function_ElIn_params_t params;
359
gs_alloc_byte_array(pdev->memory, 2, sizeof(float), "pdf_make_function(Domain)");
361
return gs_note_error(gs_error_VMerror);
364
gs_alloc_byte_array(pdev->memory, 2 * ncomp, sizeof(float), "pdf_make_function(Range)");
366
gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)");
367
return gs_note_error(gs_error_VMerror);
374
for (i=0;i<ncomp;i++) {
376
ptr2[(i*2) + 1] = 1.0f;
378
params.Domain = ptr1;
381
ptr1 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C0)");
383
gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C0)");
384
gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C0)");
385
return gs_note_error(gs_error_VMerror);
387
ptr2 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C1)");
389
gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C1)");
390
gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C1)");
391
gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(C1)");
392
return gs_note_error(gs_error_VMerror);
395
for (i=0;i<ncomp;i++) {
396
ptr1[i] = data_low[i];
397
ptr2[i] = data_high[i];
401
code = gs_function_ElIn_init(pfn, ¶ms, pdev->memory);
403
gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function");
404
gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function");
405
gs_free_object(pdev->memory, (void *)params.C0, "pdf_make_function");
406
gs_free_object(pdev->memory, (void *)params.C1, "pdf_make_function");
411
static void pdf_SepRGB_ConvertToCMYK (float *in, float *out)
416
if (in[0] <= in[1] && in[0] <= in[2]) {
417
CMYK[3] = 1.0 - in[0];
419
if (in[1]<= in[0] && in[1] <= in[2]) {
420
CMYK[3] = 1.0 - in[1];
422
CMYK[3] = 1.0 - in[2];
425
CMYK[0] = 1.0 - in[0] - CMYK[3];
426
CMYK[1] = 1.0 - in[1] - CMYK[3];
427
CMYK[2] = 1.0 - in[2] - CMYK[3];
432
static void pdf_SepCMYK_ConvertToRGB (float *in, float *out)
436
RGB[0] = in[0] + in[3];
437
RGB[1] = in[1] + in[3];
438
RGB[2] = in[2] + in[3];
454
/* Create a Separation or DeviceN color space (internal). */
456
pdf_separation_color_space(gx_device_pdf *pdev,
457
cos_array_t *pca, const char *csname,
458
const cos_value_t *snames,
459
const gs_color_space *alt_space,
460
const gs_function_t *pfn,
461
const pdf_color_space_names_t *pcsn,
462
const cos_value_t *v_attributes)
465
const gs_range_t *ranges;
468
/* We need to think about the alternate space. If we are producing
469
* PDF/X or PDF/A we can't produce some device spaces, and the code in
470
* pdf_color_space_named always allows device spaces. We could alter
471
* that code, but by then we don't know its an Alternate space, and have
472
* lost the tin transform procedure. So instead we check here.
474
csi = gs_color_space_get_index(alt_space);
475
/* Note that if csi is ICC, check to see if this was one of
476
the default substitutes that we introduced for DeviceGray,
477
DeviceRGB or DeviceCMYK. If it is, then just write
478
the default color. Depending upon the flavor of PDF,
479
or other options, we may want to actually have all
480
the colors defined by ICC profiles and not do the following
481
substituion of the Device space. */
482
if (csi == gs_color_space_index_ICC) {
483
csi = gsicc_get_default_type(alt_space->cmm_icc_profile_data);
485
if (csi == gs_color_space_index_DeviceRGB && (pdev->PDFX ||
486
(pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceCMYK)))) {
488
/* We have a DeviceRGB alternate, but are producing either PDF/X or
489
* PDF/A with a DeviceCMYK process color model. So we need to convert
490
* the alternate space into CMYK. We do this by evaluating the function
491
* at each end of the Separation space (0 and 1), convert the resulting
492
* RGB colours into CMYK and create a new function which linearly
493
* interpolates between these points.
495
gs_function_t *new_pfn = 0;
496
float in[1] = {0.0f};
500
code = gs_function_evaluate(pfn, in, out_low);
503
pdf_SepRGB_ConvertToCMYK((float *)&out_low, (float *)&out_low);
506
code = gs_function_evaluate(pfn, in, out_high);
509
pdf_SepRGB_ConvertToCMYK((float *)&out_high, (float *)&out_high);
511
code = pdf_make_base_space_function(pdev, &new_pfn, 4, out_low, out_high);
515
code = cos_array_add(pca, cos_c_string_value(&v, csname));
517
code = cos_array_add_no_copy(pca, snames);
519
cos_c_string_value(&v, (const char *)pcsn->DeviceCMYK);
520
code = cos_array_add(pca, &v);
522
code = pdf_function_scaled(pdev, new_pfn, 0x00, &v);
524
code = cos_array_add(pca, &v);
525
if (code >= 0 && v_attributes != NULL)
526
code = cos_array_add(pca, v_attributes);
531
pdf_delete_base_space_function(pdev, new_pfn);
534
if (csi == gs_color_space_index_DeviceCMYK &&
535
(pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceRGB))) {
536
/* We have a DeviceCMYK alternate, but are producingPDF/A with a
537
* DeviceRGB process color model. See comment above re DviceRGB.
539
gs_function_t *new_pfn = 0;
540
float in[1] = {0.0f};
544
code = gs_function_evaluate(pfn, in, out_low);
547
pdf_SepCMYK_ConvertToRGB((float *)&out_low, (float *)&out_low);
550
code = gs_function_evaluate(pfn, in, out_high);
553
pdf_SepCMYK_ConvertToRGB((float *)&out_high, (float *)&out_high);
555
code = pdf_make_base_space_function(pdev, &new_pfn, 3, out_low, out_high);
559
code = cos_array_add(pca, cos_c_string_value(&v, csname));
561
code = cos_array_add_no_copy(pca, snames);
563
cos_c_string_value(&v, pcsn->DeviceRGB);
564
code = cos_array_add(pca, &v);
566
code = pdf_function_scaled(pdev, new_pfn, 0x00, &v);
568
code = cos_array_add(pca, &v);
569
if (code >= 0 && v_attributes != NULL)
570
code = cos_array_add(pca, v_attributes);
575
pdf_delete_base_space_function(pdev, new_pfn);
579
if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
580
(code = cos_array_add_no_copy(pca, snames)) < 0 ||
581
(code = pdf_color_space_named(pdev, &v, &ranges, alt_space, pcsn, false, NULL, 0)) < 0 ||
582
(code = cos_array_add(pca, &v)) < 0 ||
583
(code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
584
(code = cos_array_add(pca, &v)) < 0 ||
585
(v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
592
* Create an Indexed color space. This is a single-use procedure,
593
* broken out only for readability.
596
pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
597
const gs_color_space *pcs, cos_array_t *pca)
599
const gs_indexed_params *pip = &pcs->params.indexed;
600
const gs_color_space *base_space = pcs->base_space;
601
int num_entries = pip->hival + 1;
602
int num_components = gs_color_space_num_components(base_space);
603
uint table_size = num_entries * num_components;
604
/* Guess at the extra space needed for PS string encoding. */
605
uint string_size = 2 + table_size * 4;
607
byte buf[100]; /* arbitrary */
610
gs_memory_t *mem = pdev->pdf_memory;
616
/* PDF doesn't support Indexed color spaces with more than 256 entries. */
617
if (num_entries > 256)
618
return_error(gs_error_rangecheck);
619
if (pdev->CompatibilityLevel < 1.3 && !pdev->ForOPDFRead) {
620
switch (gs_color_space_get_index(pcs)) {
621
case gs_color_space_index_Pattern:
622
case gs_color_space_index_Separation:
623
case gs_color_space_index_Indexed:
624
case gs_color_space_index_DeviceN:
625
return_error(gs_error_rangecheck);
630
table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
631
palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
632
if (table == 0 || palette == 0) {
633
gs_free_string(mem, palette, table_size,
634
"pdf_color_space(palette)");
635
gs_free_string(mem, table, string_size,
636
"pdf_color_space(table)");
637
return_error(gs_error_VMerror);
640
swrite_string(&s, table, string_size);
642
s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
643
s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
645
if (pcs->params.indexed.use_proc) {
646
gs_client_color cmin, cmax;
647
byte *pnext = palette;
650
/* Find the legal range for the color components. */
651
for (j = 0; j < num_components; ++j)
652
cmin.paint.values[j] = (float)min_long,
653
cmax.paint.values[j] = (float)max_long;
654
gs_color_space_restrict_color(&cmin, base_space);
655
gs_color_space_restrict_color(&cmax, base_space);
657
* Compute the palette values, with the legal range for each
658
* one mapped to [0 .. 255].
660
for (i = 0; i < num_entries; ++i) {
663
gs_cspace_indexed_lookup(pcs, i, &cc);
664
for (j = 0; j < num_components; ++j) {
665
float v = (cc.paint.values[j] - cmin.paint.values[j])
666
* 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
668
*pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
672
memcpy(palette, pip->lookup.table.data, table_size);
673
if (gs_color_space_get_index(base_space) ==
674
gs_color_space_index_DeviceRGB
676
/* Check for an all-gray palette3. */
679
for (i = table_size; (i -= 3) >= 0; )
680
if (palette[i] != palette[i + 1] ||
681
palette[i] != palette[i + 2]
685
/* Change the color space to DeviceGray. */
686
for (i = 0; i < num_entries; ++i)
687
palette[i] = palette[i * 3];
688
table_size = num_entries;
689
base_space = gs_cspace_new_DeviceGray(mem);
692
stream_write(&es, palette, table_size);
693
gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
696
string_used = (uint)stell(&s);
697
table = gs_resize_string(mem, table, string_size, string_used,
698
"pdf_color_space(table)");
700
* Since the array is always referenced by name as a resource
701
* rather than being written as a value, even for in-line images,
702
* always use the full name for the color space.
704
* We don't have to worry about the range of the base space:
705
* in PDF, unlike PostScript, the values from the lookup table are
706
* scaled automatically.
708
if ((code = pdf_color_space_named(pdev, pvalue, NULL, base_space,
709
&pdf_color_space_names, false, NULL, 0)) < 0 ||
710
(code = cos_array_add(pca,
711
cos_c_string_value(&v,
712
pdf_color_space_names.Indexed
713
/*pcsn->Indexed*/))) < 0 ||
714
(code = cos_array_add(pca, pvalue)) < 0 ||
715
(code = cos_array_add_int(pca, pip->hival)) < 0 ||
716
(code = cos_array_add_no_copy(pca,
717
cos_string_value(&v, table,
725
* Find a color space resource by seriialized data.
727
static pdf_resource_t *
728
pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size)
730
pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains;
731
pdf_resource_t *pres;
734
for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
735
for (pres = pchain[i]; pres != 0; pres = pres->next) {
736
const pdf_color_space_t *const ppcs =
737
(const pdf_color_space_t *)pres;
738
if (ppcs->serialized_size != serialized_size)
740
if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size))
747
int pdf_convert_ICC(gx_device_pdf *pdev,
748
const gs_color_space *pcs, cos_value_t *pvalue,
749
const pdf_color_space_names_t *pcsn)
751
gs_color_space_index csi;
754
csi = gs_color_space_get_index(pcs);
755
if (csi == gs_color_space_index_ICC) {
756
csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
758
if (csi == gs_color_space_index_Indexed) {
759
pcs = pcs->base_space;
760
csi = gs_color_space_get_index(pcs);
762
if (csi == gs_color_space_index_ICC) {
763
if (pcs->cmm_icc_profile_data == NULL ||
764
pdev->CompatibilityLevel < 1.3
766
if (pcs->base_space != NULL) {
770
cmm_dev_profile_t *dev_profile;
772
/* determine number of components in device space */
773
code = dev_proc((gx_device *)pdev, get_profile)((gx_device *)pdev, &dev_profile);
777
num_des_comps = gsicc_get_device_profile_comps(dev_profile);
778
/* Set image color space to be device space */
779
switch( num_des_comps ) {
781
cos_c_string_value(pvalue, pcsn->DeviceGray);
782
/* negative return means we do conversion */
785
cos_c_string_value(pvalue, pcsn->DeviceRGB);
788
cos_c_string_value(pvalue, pcsn->DeviceCMYK);
800
* Create a PDF color space corresponding to a PostScript color space.
801
* For parameterless color spaces, set *pvalue to a (literal) string with
802
* the color space name; for other color spaces, create a cos_array_t if
803
* necessary and set *pvalue to refer to it. In the latter case, if
804
* by_name is true, return a string /Rxxxx rather than a reference to
807
* If ppranges is not NULL, then if the domain of the color space had
808
* to be scaled (to convert a CIEBased space to ICCBased), store a pointer
809
* to the ranges in *ppranges, otherwise set *ppranges to 0.
812
pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue,
813
const gs_range_t **ppranges,
814
const gs_color_space *pcs_in,
815
const pdf_color_space_names_t *pcsn,
816
bool by_name, const byte *res_name, int name_length)
818
const gs_color_space *pcs;
819
gs_color_space_index csi;
823
const gs_cie_common *pciec;
825
const gs_range_t *ranges = 0;
826
uint serialized_size;
827
byte *serialized = NULL, serialized0[100];
828
pdf_resource_t *pres = NULL;
830
#ifdef DEPRECATED_906
834
/* If color space is CIE based and we have compatibility then go ahead and use the ICC alternative */
835
if ((pdev->CompatibilityLevel < 1.3) || !gs_color_space_is_PSCIE(pcs_in) ) {
839
/* The snippet below creates an ICC equivalent profile for the PS
840
color space. This is disabled until I add the capability to
841
specify the profile version to ensure compatability with
843
#ifdef DEPRECATED_906
844
if (pcs_in->icc_equivalent != NULL) {
845
pcs = pcs_in->icc_equivalent;
847
/* Need to create the equivalent object */
848
gs_colorspace_set_icc_equivalent((gs_color_space *)pcs_in, &islab, pdev->memory);
849
pcs = pcs_in->icc_equivalent;
853
csi = gs_color_space_get_index(pcs);
854
/* Note that if csi is ICC, check to see if this was one of
855
the default substitutes that we introduced for DeviceGray,
856
DeviceRGB or DeviceCMYK. If it is, then just write
857
the default color. Depending upon the flavor of PDF,
858
or other options, we may want to actually have all
859
the colors defined by ICC profiles and not do the following
860
substituion of the Device space. */
861
if (csi == gs_color_space_index_ICC) {
862
csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
865
*ppranges = 0; /* default */
867
case gs_color_space_index_DeviceGray:
868
cos_c_string_value(pvalue, pcsn->DeviceGray);
870
case gs_color_space_index_DeviceRGB:
871
cos_c_string_value(pvalue, pcsn->DeviceRGB);
873
case gs_color_space_index_DeviceCMYK:
874
cos_c_string_value(pvalue, pcsn->DeviceCMYK);
876
case gs_color_space_index_Pattern:
877
if (!pcs->params.pattern.has_base_space) {
878
cos_c_string_value(pvalue, "/Pattern");
882
case gs_color_space_index_ICC:
884
* Take a special early exit for unrecognized ICCBased color spaces,
885
* or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
888
if (pcs->cmm_icc_profile_data == NULL ||
889
pdev->CompatibilityLevel < 1.3
891
if (res_name != NULL)
892
return 0; /* Ignore .includecolorspace */
893
if (pcs->base_space != NULL) {
894
return pdf_color_space_named( pdev, pvalue, ppranges,
896
pcsn, by_name, NULL, 0);
898
switch( cs_num_components(pcs) ) {
900
cos_c_string_value(pvalue, pcsn->DeviceGray);
903
cos_c_string_value(pvalue, pcsn->DeviceRGB);
906
cos_c_string_value(pvalue, pcsn->DeviceCMYK);
918
if (pdev->params.ColorConversionStrategy == ccs_CMYK &&
919
csi != gs_color_space_index_DeviceCMYK &&
920
csi != gs_color_space_index_DeviceGray &&
921
csi != gs_color_space_index_Pattern) {
922
emprintf(pdev->memory,
923
"\nUnable to convert color space to CMYK, reverting strategy to LeaveColorUnchanged.\n");
924
pdev->params.ColorConversionStrategy = ccs_LeaveColorUnchanged;
926
if (pdev->params.ColorConversionStrategy == ccs_sRGB &&
927
csi != gs_color_space_index_DeviceRGB &&
928
csi != gs_color_space_index_DeviceGray &&
929
csi != gs_color_space_index_Pattern) {
930
emprintf(pdev->memory,
931
"\nUnable to convert color space to sRGB, reverting strategy to LeaveColorUnchanged.\n");
932
pdev->params.ColorConversionStrategy = ccs_LeaveColorUnchanged;
934
if (pdev->params.ColorConversionStrategy == ccs_Gray &&
935
csi != gs_color_space_index_DeviceGray &&
936
csi != gs_color_space_index_Pattern) {
937
emprintf(pdev->memory,
938
"\nUnable to convert color space to Gray, reverting strategy to LeaveColorUnchanged.\n");
939
pdev->params.ColorConversionStrategy = ccs_LeaveColorUnchanged;
941
/* Check whether we already have a PDF object for this color space. */
942
if (pcs->id != gs_no_id)
943
pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
947
s_init(&s, pdev->memory);
948
swrite_position_only(&s);
949
code = cs_serialize(pcs, &s);
951
return_error(gs_error_unregistered); /* Must not happen. */
952
serialized_size = stell(&s);
954
if (serialized_size <= sizeof(serialized0))
955
serialized = serialized0;
957
serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
958
if (serialized == NULL)
959
return_error(gs_error_VMerror);
961
swrite_string(&s, serialized, serialized_size);
962
code = cs_serialize(pcs, &s);
964
return_error(gs_error_unregistered); /* Must not happen. */
965
if (stell(&s) != serialized_size)
966
return_error(gs_error_unregistered); /* Must not happen. */
968
pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
970
if (serialized != serialized0)
971
gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
976
const pdf_color_space_t *const ppcs =
977
(const pdf_color_space_t *)pres;
979
if (ppranges != 0 && ppcs->ranges != 0)
980
*ppranges = ppcs->ranges;
981
pca = (cos_array_t *)pres->object;
985
/* Space has parameters -- create an array. */
986
pca = cos_array_alloc(pdev, "pdf_color_space");
988
return_error(gs_error_VMerror);
992
case gs_color_space_index_ICC:
993
code = pdf_iccbased_color_space(pdev, pvalue, pcs, pca);
996
case gs_color_space_index_CIEA: {
997
/* Check that we can represent this as a CalGray space. */
998
const gs_cie_a *pcie = pcs->params.a;
999
bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
1000
bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
1001
pcie->MatrixA.w == 1);
1004
pciec = (const gs_cie_common *)pcie;
1005
if (!pcie->common.MatrixLMN.is_identity) {
1006
code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
1007
&pcie->RangeA, ONE_STEP_NOT, NULL,
1011
if (unitary && identityA &&
1012
CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
1013
CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
1014
expts.v == expts.u && expts.w == expts.u
1017
} else if (unitary && identityA &&
1018
CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
1019
cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
1023
code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
1024
&pcie->RangeA, ONE_STEP_NOT, NULL,
1028
code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
1031
pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1033
return_error(gs_error_VMerror);
1035
code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
1041
/* Finish handling a CIE-based color space (Calxxx or Lab). */
1044
code = pdf_finish_cie_space(pca, pcd, pciec);
1047
case gs_color_space_index_CIEABC: {
1048
/* Check that we can represent this as a CalRGB space. */
1049
const gs_cie_abc *pcie = pcs->params.abc;
1050
bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
1052
const gs_matrix3 *pmat = NULL;
1053
cie_cache_one_step_t one_step =
1054
cie_cached_abc_is_one_step(pcie, &pmat);
1056
pciec = (const gs_cie_common *)pcie;
1060
if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
1064
if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
1070
if (cie_is_lab(pcie)) {
1071
/* Represent this as a Lab space. */
1072
pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1074
return_error(gs_error_VMerror);
1075
code = pdf_put_lab_color_space(pca, pcd, pcie->RangeABC.ranges);
1078
code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
1079
pcie->RangeABC.ranges,
1080
one_step, pmat, &ranges);
1084
code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
1087
pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
1089
return_error(gs_error_VMerror);
1090
if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
1091
code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
1095
if (!pmat->is_identity) {
1097
cos_array_alloc(pdev, "pdf_color_space(Matrix)");
1100
return_error(gs_error_VMerror);
1101
if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
1102
(code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
1103
(code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
1104
(code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
1105
COS_OBJECT_VALUE(&v, pcma))) < 0
1112
case gs_color_space_index_CIEDEF:
1113
code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
1114
(const gs_cie_common *)pcs->params.def,
1115
pcs->params.def->RangeDEF.ranges,
1116
ONE_STEP_NOT, NULL, &ranges);
1119
case gs_color_space_index_CIEDEFG:
1120
code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
1121
(const gs_cie_common *)pcs->params.defg,
1122
pcs->params.defg->RangeDEFG.ranges,
1123
ONE_STEP_NOT, NULL, &ranges);
1126
case gs_color_space_index_Indexed:
1127
code = pdf_indexed_color_space(pdev, pvalue, pcs, pca);
1130
case gs_color_space_index_DeviceN:
1131
if (!pdev->PreserveDeviceN)
1132
return_error(gs_error_rangecheck);
1133
if (pdev->CompatibilityLevel < 1.3)
1134
return_error(gs_error_rangecheck);
1135
pfn = gs_cspace_get_devn_function(pcs);
1136
/****** CURRENTLY WE ONLY HANDLE Functions ******/
1138
return_error(gs_error_rangecheck);
1141
cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
1144
uint name_string_length;
1145
cos_value_t v_attriburtes, *va = NULL;
1148
return_error(gs_error_VMerror);
1149
for (i = 0; i < pcs->params.device_n.num_components; ++i) {
1150
if ((code = pcs->params.device_n.get_colorname_string(
1152
pcs->params.device_n.names[i], &name_string,
1153
&name_string_length)) < 0 ||
1154
(code = pdf_string_to_cos_name(pdev, name_string,
1155
name_string_length, &v)) < 0 ||
1156
(code = cos_array_add_no_copy(psna, &v)) < 0)
1159
COS_OBJECT_VALUE(&v, psna);
1160
if (pcs->params.device_n.colorants != NULL) {
1161
cos_dict_t *colorants = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
1162
cos_value_t v_colorants, v_separation, v_colorant_name;
1163
const gs_device_n_attributes *csa;
1164
pdf_resource_t *pres_attributes;
1166
if (colorants == NULL)
1167
return_error(gs_error_VMerror);
1168
code = pdf_alloc_resource(pdev, resourceOther, 0, &pres_attributes, -1);
1171
cos_become(pres_attributes->object, cos_type_dict);
1172
COS_OBJECT_VALUE(&v_colorants, colorants);
1173
code = cos_dict_put((cos_dict_t *)pres_attributes->object,
1174
(const byte *)"/Colorants", 10, &v_colorants);
1177
for (csa = pcs->params.device_n.colorants; csa != NULL; csa = csa->next) {
1178
code = pcs->params.device_n.get_colorname_string(pdev->memory,
1179
csa->colorant_name, &name_string, &name_string_length);
1182
code = pdf_color_space_named(pdev, &v_separation, NULL, csa->cspace, pcsn, false, NULL, 0);
1185
code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v_colorant_name);
1188
code = cos_dict_put(colorants, v_colorant_name.contents.chars.data,
1189
v_colorant_name.contents.chars.size, &v_separation);
1193
code = pdf_substitute_resource(pdev, &pres_attributes, resourceOther, NULL, true);
1196
pres_attributes->where_used |= pdev->used_mask;
1197
va = &v_attriburtes;
1198
COS_OBJECT_VALUE(va, pres_attributes->object);
1200
if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
1202
pfn, &pdf_color_space_names, va)) < 0)
1207
case gs_color_space_index_Separation:
1208
if (!pdev->PreserveSeparation)
1209
return_error(gs_error_rangecheck);
1210
pfn = gs_cspace_get_sepr_function(pcs);
1211
/****** CURRENTLY WE ONLY HANDLE Functions ******/
1213
return_error(gs_error_rangecheck);
1216
uint name_string_length;
1217
if ((code = pcs->params.separation.get_colorname_string(
1219
pcs->params.separation.sep_name, &name_string,
1220
&name_string_length)) < 0 ||
1221
(code = pdf_string_to_cos_name(pdev, name_string,
1222
name_string_length, &v)) < 0 ||
1223
(code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
1225
pfn, &pdf_color_space_names, NULL)) < 0)
1230
case gs_color_space_index_Pattern:
1231
if ((code = pdf_color_space_named(pdev, pvalue, ppranges,
1233
&pdf_color_space_names, false, NULL, 0)) < 0 ||
1234
(code = cos_array_add(pca,
1235
cos_c_string_value(&v, "/Pattern"))) < 0 ||
1236
(code = cos_array_add(pca, pvalue)) < 0
1242
return_error(gs_error_rangecheck);
1246
* Register the color space as a resource, since it must be referenced
1247
* by name rather than directly.
1250
pdf_color_space_t *ppcs;
1253
(code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
1256
COS_FREE(pca, "pdf_color_space");
1259
pdf_reserve_object_id(pdev, pres, 0);
1260
if (res_name != NULL) {
1261
int l = min(name_length, sizeof(pres->rname) - 1);
1263
memcpy(pres->rname, res_name, l);
1266
ppcs = (pdf_color_space_t *)pres;
1267
if (serialized == serialized0) {
1268
serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
1269
if (serialized == NULL)
1270
return_error(gs_error_VMerror);
1271
memcpy(serialized, serialized0, serialized_size);
1273
ppcs->serialized = serialized;
1274
ppcs->serialized_size = serialized_size;
1276
int num_comp = gs_color_space_num_components(pcs);
1277
gs_range_t *copy_ranges = (gs_range_t *)
1278
gs_alloc_byte_array(pdev->pdf_memory, num_comp,
1279
sizeof(gs_range_t), "pdf_color_space");
1281
if (copy_ranges == 0) {
1282
COS_FREE(pca, "pdf_color_space");
1283
return_error(gs_error_VMerror);
1285
memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
1286
ppcs->ranges = copy_ranges;
1288
*ppranges = copy_ranges;
1291
pca->id = pres->object->id;
1292
COS_FREE(pres->object, "pdf_color_space");
1293
pres->object = (cos_object_t *)pca;
1294
cos_write_object(COS_OBJECT(pca), pdev, resourceColorSpace);
1298
/* Return a resource name rather than an object reference. */
1299
discard(COS_RESOURCE_VALUE(pvalue, pca));
1301
discard(COS_OBJECT_VALUE(pvalue, pca));
1303
pres->where_used |= pdev->used_mask;
1304
code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
1311
int free_color_space(gx_device_pdf *pdev, pdf_resource_t *pres)
1313
pdf_color_space_t *ppcs = (pdf_color_space_t *)pres;
1315
if (ppcs->serialized)
1316
gs_free_object(pdev->pdf_memory, ppcs->serialized, "free serialized colour space");
1318
cos_release(pres->object, "release ColorSpace object");
1319
gs_free_object(pdev->pdf_memory, pres->object, "free ColorSpace object");
1325
/* ---------------- Miscellaneous ---------------- */
1327
/* Create colored and uncolored Pattern color spaces. */
1329
pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
1330
pdf_resource_t **ppres, const char *cs_name)
1335
int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
1340
pprints1(pdev->strm, "%s\n", cs_name);
1341
pdf_end_resource(pdev, resourceColorSpace);
1342
(*ppres)->object->written = true; /* don't write at end */
1343
((pdf_color_space_t *)*ppres)->ranges = 0;
1344
((pdf_color_space_t *)*ppres)->serialized = 0;
1346
code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres);
1349
cos_resource_value(pvalue, (*ppres)->object);
1353
pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
1355
return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
1359
pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
1361
/* Only for process colors. */
1362
int ncomp = pdev->color_info.num_components;
1363
static const char *const pcs_names[5] = {
1364
0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
1365
"[/Pattern /DeviceCMYK]"
1368
return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
1372
pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev,
1373
const gs_color_space *pcs, cos_value_t *pvalue)
1375
/* Only for high level colors. */
1376
return pdf_color_space_named(pdev, pvalue, NULL, pcs, &pdf_color_space_names, true, NULL, 0);
1379
/* Set the ProcSets bits corresponding to an image color space. */
1381
pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
1383
const gs_color_space *pbcs = pcs;
1386
switch (gs_color_space_get_index(pbcs)) {
1387
case gs_color_space_index_DeviceGray:
1388
case gs_color_space_index_CIEA:
1389
/* We only handle CIEBasedA spaces that map to CalGray. */
1390
pdev->procsets |= ImageB;
1392
case gs_color_space_index_Indexed:
1393
pdev->procsets |= ImageI;
1394
pbcs = pcs->base_space;
1397
pdev->procsets |= ImageC;