1 /* Copyright (C) 1999, 2000, 2001 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevpdfc.c,v 1.54 2005/10/18 09:05:58 leonardo Exp $ */
18 /* Color space management and writing for pdfwrite driver */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gscspace.h" /* for gscie.h */
23 #include "gscdevn.h"
24 #include "gscie.h"
25 #include "gscindex.h"
26 #include "gscsepr.h"
27 #include "stream.h"
28 #include "gsicc.h"
29 #include "gserrors.h"
30 #include "gdevpdfx.h"
31 #include "gdevpdfg.h"
32 #include "gdevpdfc.h"
33 #include "gdevpdfo.h"
34 #include "strimpl.h"
35 #include "sstring.h"
36 #include "gxcspace.h"
37 #include <assert.h>
38
39 /*
40 * PDF doesn't have general CIEBased color spaces. However, it provides
41 * two methods for handling general CIE spaces:
42 *
43 * - For PDF 1.2 and above, we note that the transformation from L*a*b*
44 * space to XYZ space is invertible, so we can handle any PostScript
45 * CIEBased space by transforming color values in that space to XYZ,
46 * then inverse-transforming them to L*a*b* and using a PDF Lab space
47 * with the same WhitePoint and BlackPoint and appropriate ranges for
48 * a and b. This approach has the drawback that Y values outside the
49 * range [0..1] can't be represented: we just clamp them.
50 *
51 * - For PDF 1.3 and above, we can create an ICCBased space. This is
52 * actually necessary, not just an option, because for shadings (also
53 * introduced in PDF 1.3), we want color interpolation to occur in the
54 * original space.
55 *
56 * The Lab approach is not currently implemented, because it requires
57 * transforming all the sample values of images. The ICCBased approach is
58 * implemented for color spaces whose ranges lie within [0..1], which are
59 * the only ranges supported by the ICC standard: we think that removing
60 * this limitation would also require transforming image sample values.
61 */
62
63 /* GC descriptors */
64 public_st_pdf_color_space();
65
66 /* ------ CIE space testing ------ */
67
68 /* Test whether a cached CIE procedure is the identity function. */
69 #define CIE_CACHE_IS_IDENTITY(pc)\
70 ((pc)->floats.params.is_identity)
71 #define CIE_CACHE3_IS_IDENTITY(pca)\
72 (CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\
73 CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\
74 CIE_CACHE_IS_IDENTITY(&(pca)[2]))
75
76 /*
77 * Test whether a cached CIE procedure is an exponential. A cached
78 * procedure is exponential iff f(x) = k*(x^p). We make a very cursory
79 * check for this: we require that f(0) = 0, set k = f(1), set p =
80 * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
81 * two arbitrarily chosen values between 0 and 1. Naturally all this is
82 * done with some slop.
83 */
84 #define CC_INDEX_A (gx_cie_cache_size / 3)
85 #define CC_INDEX_B (gx_cie_cache_size * 2 / 3)
86 #define CC_INDEX_1 (gx_cie_cache_size - 1)
87 #define CC_KEY(i) ((i) / (double)CC_INDEX_1)
88 #define CC_KEY_A CC_KEY(CC_INDEX_A)
89 #define CC_KEY_B CC_KEY(CC_INDEX_B)
90
91 private bool
cie_values_are_exponential(floatp v0,floatp va,floatp vb,floatp k,float * pexpt)92 cie_values_are_exponential(floatp v0, floatp va, floatp vb, floatp k,
93 float *pexpt)
94 {
95 double p;
96
97 if (fabs(v0) >= 0.001 || fabs(k) < 0.001)
98 return false;
99 if (va == 0 || (va > 0) != (k > 0))
100 return false;
101 p = log(va / k) / log(CC_KEY_A);
102 if (fabs(vb - k * pow(CC_KEY_B, p)) >= 0.001)
103 return false;
104 *pexpt = p;
105 return true;
106 }
107
108 private bool
cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc,float * pexpt)109 cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt)
110 {
111 return cie_values_are_exponential(pc->floats.values[0],
112 pc->floats.values[CC_INDEX_A],
113 pc->floats.values[CC_INDEX_B],
114 pc->floats.values[CC_INDEX_1],
115 pexpt);
116 }
117 #define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\
118 (cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\
119 cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\
120 cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w))
121
122 private bool
cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc,float * pexpt)123 cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt)
124 {
125 return cie_values_are_exponential(pc->vecs.values[0].u,
126 pc->vecs.values[CC_INDEX_A].u,
127 pc->vecs.values[CC_INDEX_B].u,
128 pc->vecs.values[CC_INDEX_1].u,
129 pexpt);
130 }
131 #define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\
132 (cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\
133 cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\
134 cie_vector_cache_is_exponential(&(pca)[2], &(expts).w))
135
136 #undef CC_INDEX_A
137 #undef CC_INDEX_B
138 #undef CC_KEY_A
139 #undef CC_KEY_B
140
141 /*
142 * Test whether a cached CIEBasedABC space consists only of a single
143 * Decode step followed by a single Matrix step.
144 */
145 private cie_cache_one_step_t
cie_cached_abc_is_one_step(const gs_cie_abc * pcie,const gs_matrix3 ** ppmat)146 cie_cached_abc_is_one_step(const gs_cie_abc *pcie, const gs_matrix3 **ppmat)
147 {
148 /* The order of steps is, DecodeABC, MatrixABC, DecodeLMN, MatrixLMN. */
149
150 if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN)) {
151 if (pcie->MatrixABC.is_identity) {
152 *ppmat = &pcie->common.MatrixLMN;
153 return ONE_STEP_ABC;
154 }
155 if (pcie->common.MatrixLMN.is_identity) {
156 *ppmat = &pcie->MatrixABC;
157 return ONE_STEP_ABC;
158 }
159 }
160 if (CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC.caches)) {
161 if (pcie->MatrixABC.is_identity) {
162 *ppmat = &pcie->common.MatrixLMN;
163 return ONE_STEP_LMN;
164 }
165 }
166 return ONE_STEP_NOT;
167 }
168
169 /*
170 * Test whether a cached CIEBasedABC space is a L*a*b* space.
171 */
172 private bool
cie_scalar_cache_is_lab_lmn(const gs_cie_abc * pcie,int i)173 cie_scalar_cache_is_lab_lmn(const gs_cie_abc *pcie, int i)
174 {
175 double k = CC_KEY(i);
176 double g = (k >= 6.0 / 29 ? k * k * k :
177 (k - 4.0 / 29) * (108.0 / 841));
178
179 #define CC_V(j,i) (pcie->common.caches.DecodeLMN[j].floats.values[i])
180 #define CC_WP(uvw) (pcie->common.points.WhitePoint.uvw)
181
182 return (fabs(CC_V(0, i) - g * CC_WP(u)) < 0.001 &&
183 fabs(CC_V(1, i) - g * CC_WP(v)) < 0.001 &&
184 fabs(CC_V(2, i) - g * CC_WP(w)) < 0.001
185 );
186
187 #undef CC_V
188 #undef CC_WP
189 }
190 private bool
cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t * pvc,int i)191 cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t *pvc, int i)
192 {
193 const gx_cie_vector_cache *const pc3 = pvc->caches;
194 double k = CC_KEY(i);
195 double l0 = pc3[0].vecs.params.base,
196 l = l0 + k * (pc3[0].vecs.params.limit - l0);
197 double a0 = pc3[1].vecs.params.base,
198 a = a0 + k * (pc3[1].vecs.params.limit - a0);
199 double b0 = pc3[2].vecs.params.base,
200 b = b0 + k * (pc3[2].vecs.params.limit - b0);
201
202 return (fabs(cie_cached2float(pc3[0].vecs.values[i].u) -
203 (l + 16) / 116) < 0.001 &&
204 fabs(cie_cached2float(pc3[1].vecs.values[i].u) -
205 a / 500) < 0.001 &&
206 fabs(cie_cached2float(pc3[2].vecs.values[i].w) -
207 b / -200) < 0.001
208 );
209 }
210
211 private bool
cie_is_lab(const gs_cie_abc * pcie)212 cie_is_lab(const gs_cie_abc *pcie)
213 {
214 int i;
215
216 /* Check MatrixABC and MatrixLMN. */
217 if (!(pcie->MatrixABC.cu.u == 1 && pcie->MatrixABC.cu.v == 1 &&
218 pcie->MatrixABC.cu.w == 1 &&
219 pcie->MatrixABC.cv.u == 1 && pcie->MatrixABC.cv.v == 0 &&
220 pcie->MatrixABC.cv.w == 0 &&
221 pcie->MatrixABC.cw.u == 0 && pcie->MatrixABC.cw.v == 0 &&
222 pcie->MatrixABC.cw.w == -1 &&
223 pcie->common.MatrixLMN.is_identity
224 ))
225 return false;
226
227 /* Check DecodeABC and DecodeLMN. */
228 for (i = 0; i <= CC_INDEX_1; ++i)
229 if (!(cie_vector_cache_is_lab_abc(&pcie->caches.DecodeABC, i) &&
230 cie_scalar_cache_is_lab_lmn(pcie, i)
231 ))
232 return false;
233
234 return true;
235 }
236
237 #undef CC_INDEX_1
238 #undef CC_KEY
239
240 /* Test whether one or more CIE-based ranges are [0..1]. */
241 private bool
cie_ranges_are_0_1(const gs_range * prange,int n)242 cie_ranges_are_0_1(const gs_range *prange, int n)
243 {
244 int i;
245
246 for (i = 0; i < n; ++i)
247 if (prange[i].rmin != 0 || prange[i].rmax != 1)
248 return false;
249 return true;
250 }
251
252 /* ------ Utilities ------ */
253
254 /* Add a 3-element vector to a Cos array or dictionary. */
255 private int
cos_array_add_vector3(cos_array_t * pca,const gs_vector3 * pvec)256 cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec)
257 {
258 int code = cos_array_add_real(pca, pvec->u);
259
260 if (code >= 0)
261 code = cos_array_add_real(pca, pvec->v);
262 if (code >= 0)
263 code = cos_array_add_real(pca, pvec->w);
264 return code;
265 }
266 private int
cos_dict_put_c_key_vector3(cos_dict_t * pcd,const char * key,const gs_vector3 * pvec)267 cos_dict_put_c_key_vector3(cos_dict_t *pcd, const char *key,
268 const gs_vector3 *pvec)
269 {
270 cos_array_t *pca = cos_array_alloc(pcd->pdev, "cos_array_from_vector3");
271 int code;
272
273 if (pca == 0)
274 return_error(gs_error_VMerror);
275 code = cos_array_add_vector3(pca, pvec);
276 if (code < 0) {
277 COS_FREE(pca, "cos_array_from_vector3");
278 return code;
279 }
280 return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
281 }
282
283 /*
284 * Finish creating a CIE-based color space (Calxxx or Lab.)
285 * This procedure is exported for gdevpdfk.c.
286 */
287 int
pdf_finish_cie_space(cos_array_t * pca,cos_dict_t * pcd,const gs_cie_common * pciec)288 pdf_finish_cie_space(cos_array_t *pca, cos_dict_t *pcd,
289 const gs_cie_common *pciec)
290 {
291 int code = cos_dict_put_c_key_vector3(pcd, "/WhitePoint",
292 &pciec->points.WhitePoint);
293
294 if (code < 0)
295 return code;
296 if (pciec->points.BlackPoint.u != 0 ||
297 pciec->points.BlackPoint.v != 0 ||
298 pciec->points.BlackPoint.w != 0
299 ) {
300 code = cos_dict_put_c_key_vector3(pcd, "/BlackPoint",
301 &pciec->points.BlackPoint);
302 if (code < 0)
303 return code;
304 }
305 return cos_array_add_object(pca, COS_OBJECT(pcd));
306 }
307
308 /* ------ Color space writing ------ */
309
310 /* Define standard and short color space names. */
311 const pdf_color_space_names_t pdf_color_space_names = {
312 PDF_COLOR_SPACE_NAMES
313 };
314 const pdf_color_space_names_t pdf_color_space_names_short = {
315 PDF_COLOR_SPACE_NAMES_SHORT
316 };
317
318 /*
319 * Create a local Device{Gray,RGB,CMYK} color space corresponding to the
320 * given number of components.
321 */
322 int
pdf_cspace_init_Device(const gs_memory_t * mem,gs_color_space * pcs,int num_components)323 pdf_cspace_init_Device(const gs_memory_t *mem, gs_color_space *pcs, int num_components)
324 {
325 switch (num_components) {
326 case 1: gs_cspace_init_DeviceGray(mem, pcs); break;
327 case 3: gs_cspace_init_DeviceRGB(mem, pcs); break;
328 case 4: gs_cspace_init_DeviceCMYK(mem, pcs); break;
329 default: return_error(gs_error_rangecheck);
330 }
331 return 0;
332 }
333
334 /* Create a Separation or DeviceN color space (internal). */
335 private int
pdf_separation_color_space(gx_device_pdf * pdev,cos_array_t * pca,const char * csname,const cos_value_t * snames,const gs_color_space * alt_space,const gs_function_t * pfn,const pdf_color_space_names_t * pcsn)336 pdf_separation_color_space(gx_device_pdf *pdev,
337 cos_array_t *pca, const char *csname,
338 const cos_value_t *snames,
339 const gs_color_space *alt_space,
340 const gs_function_t *pfn,
341 const pdf_color_space_names_t *pcsn)
342 {
343 cos_value_t v;
344 const gs_range_t *ranges;
345 int code;
346
347 if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
348 (code = cos_array_add_no_copy(pca, snames)) < 0 ||
349 (code = pdf_color_space(pdev, &v, &ranges, alt_space, pcsn, false)) < 0 ||
350 (code = cos_array_add(pca, &v)) < 0 ||
351 (code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
352 (code = cos_array_add(pca, &v)) < 0
353 )
354 return code;
355 return 0;
356 }
357
358 /*
359 * Create an Indexed color space. This is a single-use procedure,
360 * broken out only for readability.
361 */
362 private int
pdf_indexed_color_space(gx_device_pdf * pdev,cos_value_t * pvalue,const gs_color_space * pcs,cos_array_t * pca)363 pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
364 const gs_color_space *pcs, cos_array_t *pca)
365 {
366 const gs_indexed_params *pip = &pcs->params.indexed;
367 const gs_color_space *base_space =
368 (const gs_color_space *)&pip->base_space;
369 int num_entries = pip->hival + 1;
370 int num_components = gs_color_space_num_components(base_space);
371 uint table_size = num_entries * num_components;
372 /* Guess at the extra space needed for PS string encoding. */
373 uint string_size = 2 + table_size * 4;
374 uint string_used;
375 byte buf[100]; /* arbitrary */
376 stream_AXE_state st;
377 stream s, es;
378 gs_memory_t *mem = pdev->pdf_memory;
379 byte *table;
380 byte *palette;
381 gs_color_space cs_gray;
382 cos_value_t v;
383 int code;
384
385 /* PDF doesn't support Indexed color spaces with more than 256 entries. */
386 if (num_entries > 256)
387 return_error(gs_error_rangecheck);
388 if (pdev->CompatibilityLevel < 1.3) {
389 switch (gs_color_space_get_index(pcs)) {
390 case gs_color_space_index_Pattern:
391 case gs_color_space_index_Separation:
392 case gs_color_space_index_Indexed:
393 case gs_color_space_index_DeviceN:
394 return_error(gs_error_rangecheck);
395 default: DO_NOTHING;
396 }
397
398 }
399 table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
400 palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
401 if (table == 0 || palette == 0) {
402 gs_free_string(mem, palette, table_size,
403 "pdf_color_space(palette)");
404 gs_free_string(mem, table, string_size,
405 "pdf_color_space(table)");
406 return_error(gs_error_VMerror);
407 }
408 swrite_string(&s, table, string_size);
409 s_init(&es, mem);
410 s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
411 s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
412 sputc(&s, '(');
413 if (pcs->params.indexed.use_proc) {
414 gs_client_color cmin, cmax;
415 byte *pnext = palette;
416 int i, j;
417
418 /* Find the legal range for the color components. */
419 for (j = 0; j < num_components; ++j)
420 cmin.paint.values[j] = (float)min_long,
421 cmax.paint.values[j] = (float)max_long;
422 gs_color_space_restrict_color(&cmin, base_space);
423 gs_color_space_restrict_color(&cmax, base_space);
424 /*
425 * Compute the palette values, with the legal range for each
426 * one mapped to [0 .. 255].
427 */
428 for (i = 0; i < num_entries; ++i) {
429 gs_client_color cc;
430
431 gs_cspace_indexed_lookup(&pcs->params.indexed, i, &cc);
432 for (j = 0; j < num_components; ++j) {
433 float v = (cc.paint.values[j] - cmin.paint.values[j])
434 * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
435
436 *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
437 }
438 }
439 } else
440 memcpy(palette, pip->lookup.table.data, table_size);
441 if (gs_color_space_get_index(base_space) ==
442 gs_color_space_index_DeviceRGB
443 ) {
444 /* Check for an all-gray palette3. */
445 int i;
446
447 for (i = table_size; (i -= 3) >= 0; )
448 if (palette[i] != palette[i + 1] ||
449 palette[i] != palette[i + 2]
450 )
451 break;
452 if (i < 0) {
453 /* Change the color space to DeviceGray. */
454 for (i = 0; i < num_entries; ++i)
455 palette[i] = palette[i * 3];
456 table_size = num_entries;
457 gs_cspace_init_DeviceGray(mem, &cs_gray);
458 base_space = &cs_gray;
459 }
460 }
461 stream_write(&es, palette, table_size);
462 gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
463 sclose(&es);
464 sflush(&s);
465 string_used = (uint)stell(&s);
466 table = gs_resize_string(mem, table, string_size, string_used,
467 "pdf_color_space(table)");
468 /*
469 * Since the array is always referenced by name as a resource
470 * rather than being written as a value, even for in-line images,
471 * always use the full name for the color space.
472 *
473 * We don't have to worry about the range of the base space:
474 * in PDF, unlike PostScript, the values from the lookup table are
475 * scaled automatically.
476 */
477 if ((code = pdf_color_space(pdev, pvalue, NULL, base_space,
478 &pdf_color_space_names, false)) < 0 ||
479 (code = cos_array_add(pca,
480 cos_c_string_value(&v,
481 pdf_color_space_names.Indexed
482 /*pcsn->Indexed*/))) < 0 ||
483 (code = cos_array_add(pca, pvalue)) < 0 ||
484 (code = cos_array_add_int(pca, pip->hival)) < 0 ||
485 (code = cos_array_add_no_copy(pca,
486 cos_string_value(&v, table,
487 string_used))) < 0
488 )
489 return code;
490 return 0;
491 }
492
493 /*
494 * Find a color space resource by seriialized data.
495 */
496 private pdf_resource_t *
pdf_find_cspace_resource(gx_device_pdf * pdev,const byte * serialized,uint serialized_size)497 pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size)
498 {
499 pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains;
500 pdf_resource_t *pres;
501 int i;
502
503 for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
504 for (pres = pchain[i]; pres != 0; pres = pres->next) {
505 const pdf_color_space_t *const ppcs =
506 (const pdf_color_space_t *)pres;
507 if (ppcs->serialized_size != serialized_size)
508 continue;
509 if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size))
510 return pres;
511 }
512 }
513 return NULL;
514 }
515
516
517 /*
518 * Create a PDF color space corresponding to a PostScript color space.
519 * For parameterless color spaces, set *pvalue to a (literal) string with
520 * the color space name; for other color spaces, create a cos_array_t if
521 * necessary and set *pvalue to refer to it. In the latter case, if
522 * by_name is true, return a string /Rxxxx rather than a reference to
523 * the actual object.
524 *
525 * If ppranges is not NULL, then if the domain of the color space had
526 * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
527 * to the ranges in *ppranges, otherwise set *ppranges to 0.
528 */
529 int
pdf_color_space_named(gx_device_pdf * pdev,cos_value_t * pvalue,const gs_range_t ** ppranges,const gs_color_space * pcs,const pdf_color_space_names_t * pcsn,bool by_name,const byte * res_name,int name_length)530 pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue,
531 const gs_range_t **ppranges,
532 const gs_color_space *pcs,
533 const pdf_color_space_names_t *pcsn,
534 bool by_name, const byte *res_name, int name_length)
535 {
536 gs_color_space_index csi = gs_color_space_get_index(pcs);
537 cos_array_t *pca;
538 cos_dict_t *pcd;
539 cos_value_t v;
540 const gs_cie_common *pciec;
541 gs_function_t *pfn;
542 const gs_range_t *ranges = 0;
543 uint serialized_size;
544 byte *serialized = NULL, serialized0[100];
545 pdf_resource_t *pres = NULL;
546 int code;
547
548 if (ppranges)
549 *ppranges = 0; /* default */
550 switch (csi) {
551 case gs_color_space_index_DeviceGray:
552 cos_c_string_value(pvalue, pcsn->DeviceGray);
553 return 0;
554 case gs_color_space_index_DeviceRGB:
555 cos_c_string_value(pvalue, pcsn->DeviceRGB);
556 return 0;
557 case gs_color_space_index_DeviceCMYK:
558 cos_c_string_value(pvalue, pcsn->DeviceCMYK);
559 return 0;
560 case gs_color_space_index_Pattern:
561 if (!pcs->params.pattern.has_base_space) {
562 cos_c_string_value(pvalue, "/Pattern");
563 return 0;
564 }
565 break;
566 case gs_color_space_index_CIEICC:
567 /*
568 * Take a special early exit for unrecognized ICCBased color spaces,
569 * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
570 */
571 if (pcs->params.icc.picc_info->picc == 0 ||
572 pdev->CompatibilityLevel < 1.3
573 ) {
574 if (res_name != NULL)
575 return 0; /* Ignore .includecolorspace */
576 return pdf_color_space( pdev, pvalue, ppranges,
577 (const gs_color_space *)
578 &pcs->params.icc.alt_space,
579 pcsn, by_name);
580 }
581 break;
582 default:
583 break;
584 }
585
586 /* Check whether we already have a PDF object for this color space. */
587 if (pcs->id != gs_no_id)
588 pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
589 if (pres == NULL) {
590 stream s;
591
592 s_init(&s, pdev->memory);
593 swrite_position_only(&s);
594 code = cs_serialize(pcs, &s);
595 if (code < 0)
596 return_error(gs_error_unregistered); /* Must not happen. */
597 serialized_size = stell(&s);
598 sclose(&s);
599 if (serialized_size <= sizeof(serialized0))
600 serialized = serialized0;
601 else {
602 serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
603 if (serialized == NULL)
604 return_error(gs_error_VMerror);
605 }
606 swrite_string(&s, serialized, serialized_size);
607 code = cs_serialize(pcs, &s);
608 if (code < 0)
609 return_error(gs_error_unregistered); /* Must not happen. */
610 if (stell(&s) != serialized_size)
611 return_error(gs_error_unregistered); /* Must not happen. */
612 sclose(&s);
613 pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
614 if (pres != NULL) {
615 if (serialized != serialized0)
616 gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
617 serialized = NULL;
618 }
619 }
620 if (pres) {
621 const pdf_color_space_t *const ppcs =
622 (const pdf_color_space_t *)pres;
623
624 if (ppranges != 0 && ppcs->ranges != 0)
625 *ppranges = ppcs->ranges;
626 pca = (cos_array_t *)pres->object;
627 goto ret;
628 }
629
630 /* Space has parameters -- create an array. */
631 pca = cos_array_alloc(pdev, "pdf_color_space");
632 if (pca == 0)
633 return_error(gs_error_VMerror);
634
635 switch (csi) {
636
637 case gs_color_space_index_CIEICC:
638 code = pdf_iccbased_color_space(pdev, pvalue, pcs, pca);
639 break;
640
641 case gs_color_space_index_CIEA: {
642 /* Check that we can represent this as a CalGray space. */
643 const gs_cie_a *pcie = pcs->params.a;
644 bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
645 bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
646 pcie->MatrixA.w == 1);
647 gs_vector3 expts;
648
649 pciec = (const gs_cie_common *)pcie;
650 if (!pcie->common.MatrixLMN.is_identity) {
651 code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
652 &pcie->RangeA, ONE_STEP_NOT, NULL,
653 &ranges);
654 break;
655 }
656 if (unitary && identityA &&
657 CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
658 CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
659 expts.v == expts.u && expts.w == expts.u
660 ) {
661 DO_NOTHING;
662 } else if (unitary && identityA &&
663 CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
664 cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
665 ) {
666 DO_NOTHING;
667 } else {
668 code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
669 &pcie->RangeA, ONE_STEP_NOT, NULL,
670 &ranges);
671 break;
672 }
673 code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
674 if (code < 0)
675 return code;
676 pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
677 if (pcd == 0)
678 return_error(gs_error_VMerror);
679 if (expts.u != 1) {
680 code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
681 if (code < 0)
682 return code;
683 }
684 }
685 cal:
686 /* Finish handling a CIE-based color space (Calxxx or Lab). */
687 if (code < 0)
688 return code;
689 code = pdf_finish_cie_space(pca, pcd, pciec);
690 break;
691
692 case gs_color_space_index_CIEABC: {
693 /* Check that we can represent this as a CalRGB space. */
694 const gs_cie_abc *pcie = pcs->params.abc;
695 bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
696 gs_vector3 expts;
697 const gs_matrix3 *pmat = NULL;
698 cie_cache_one_step_t one_step =
699 cie_cached_abc_is_one_step(pcie, &pmat);
700
701 pciec = (const gs_cie_common *)pcie;
702 if (unitary) {
703 switch (one_step) {
704 case ONE_STEP_ABC:
705 if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
706 goto calrgb;
707 break;
708 case ONE_STEP_LMN:
709 if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
710 goto calrgb;
711 default:
712 break;
713 }
714 }
715 if (cie_is_lab(pcie)) {
716 /* Represent this as a Lab space. */
717 pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
718 if (pcd == 0)
719 return_error(gs_error_VMerror);
720 code = pdf_put_lab_color_space(pca, pcd, pcie->RangeABC.ranges);
721 goto cal;
722 } else {
723 code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
724 pcie->RangeABC.ranges,
725 one_step, pmat, &ranges);
726 break;
727 }
728 calrgb:
729 code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
730 if (code < 0)
731 return code;
732 pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
733 if (pcd == 0)
734 return_error(gs_error_VMerror);
735 if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
736 code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
737 if (code < 0)
738 return code;
739 }
740 if (!pmat->is_identity) {
741 cos_array_t *pcma =
742 cos_array_alloc(pdev, "pdf_color_space(Matrix)");
743
744 if (pcma == 0)
745 return_error(gs_error_VMerror);
746 if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
747 (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
748 (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
749 (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
750 COS_OBJECT_VALUE(&v, pcma))) < 0
751 )
752 return code;
753 }
754 }
755 goto cal;
756
757 case gs_color_space_index_CIEDEF:
758 code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
759 (const gs_cie_common *)pcs->params.def,
760 pcs->params.def->RangeDEF.ranges,
761 ONE_STEP_NOT, NULL, &ranges);
762 break;
763
764 case gs_color_space_index_CIEDEFG:
765 code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
766 (const gs_cie_common *)pcs->params.defg,
767 pcs->params.defg->RangeDEFG.ranges,
768 ONE_STEP_NOT, NULL, &ranges);
769 break;
770
771 case gs_color_space_index_Indexed:
772 code = pdf_indexed_color_space(pdev, pvalue, pcs, pca);
773 break;
774
775 case gs_color_space_index_DeviceN:
776 if (pdev->CompatibilityLevel < 1.3)
777 return_error(gs_error_rangecheck);
778 pfn = gs_cspace_get_devn_function(pcs);
779 /****** CURRENTLY WE ONLY HANDLE Functions ******/
780 if (pfn == 0)
781 return_error(gs_error_rangecheck);
782 {
783 cos_array_t *psna =
784 cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
785 int i;
786 byte *name_string;
787 uint name_string_length;
788
789 if (psna == 0)
790 return_error(gs_error_VMerror);
791 for (i = 0; i < pcs->params.device_n.num_components; ++i) {
792 if ((code = pcs->params.device_n.get_colorname_string(
793 pdev->memory,
794 pcs->params.device_n.names[i], &name_string,
795 &name_string_length)) < 0 ||
796 (code = pdf_string_to_cos_name(pdev, name_string,
797 name_string_length, &v)) < 0 ||
798 (code = cos_array_add_no_copy(psna, &v)) < 0)
799 return code;
800 }
801 COS_OBJECT_VALUE(&v, psna);
802 if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
803 (const gs_color_space *)
804 &pcs->params.device_n.alt_space,
805 pfn, &pdf_color_space_names)) < 0)
806 return code;
807 }
808 break;
809
810 case gs_color_space_index_Separation:
811 pfn = gs_cspace_get_sepr_function(pcs);
812 /****** CURRENTLY WE ONLY HANDLE Functions ******/
813 if (pfn == 0)
814 return_error(gs_error_rangecheck);
815 {
816 byte *name_string;
817 uint name_string_length;
818 if ((code = pcs->params.separation.get_colorname_string(
819 pdev->memory,
820 pcs->params.separation.sep_name, &name_string,
821 &name_string_length)) < 0 ||
822 (code = pdf_string_to_cos_name(pdev, name_string,
823 name_string_length, &v)) < 0 ||
824 (code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
825 (const gs_color_space *)
826 &pcs->params.separation.alt_space,
827 pfn, &pdf_color_space_names)) < 0)
828 return code;
829 }
830 break;
831
832 case gs_color_space_index_Pattern:
833 if ((code = pdf_color_space(pdev, pvalue, ppranges,
834 (const gs_color_space *)
835 &pcs->params.pattern.base_space,
836 &pdf_color_space_names, false)) < 0 ||
837 (code = cos_array_add(pca,
838 cos_c_string_value(&v, "/Pattern"))) < 0 ||
839 (code = cos_array_add(pca, pvalue)) < 0
840 )
841 return code;
842 break;
843
844 default:
845 return_error(gs_error_rangecheck);
846 }
847 /*
848 * Register the color space as a resource, since it must be referenced
849 * by name rather than directly.
850 */
851 {
852 pdf_color_space_t *ppcs;
853
854 if (code < 0 ||
855 (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
856 &pres, -1)) < 0
857 ) {
858 COS_FREE(pca, "pdf_color_space");
859 return code;
860 }
861 pdf_reserve_object_id(pdev, pres, 0);
862 if (res_name != NULL) {
863 int l = min(name_length, sizeof(pres->rname) - 1);
864
865 memcpy(pres->rname, res_name, l);
866 pres->rname[l] = 0;
867 }
868 ppcs = (pdf_color_space_t *)pres;
869 if (serialized == serialized0) {
870 serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
871 if (serialized == NULL)
872 return_error(gs_error_VMerror);
873 memcpy(serialized, serialized0, serialized_size);
874 }
875 ppcs->serialized = serialized;
876 ppcs->serialized_size = serialized_size;
877 if (ranges) {
878 int num_comp = gs_color_space_num_components(pcs);
879 gs_range_t *copy_ranges = (gs_range_t *)
880 gs_alloc_byte_array(pdev->pdf_memory, num_comp,
881 sizeof(gs_range_t), "pdf_color_space");
882
883 if (copy_ranges == 0) {
884 COS_FREE(pca, "pdf_color_space");
885 return_error(gs_error_VMerror);
886 }
887 memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
888 ppcs->ranges = copy_ranges;
889 if (ppranges)
890 *ppranges = copy_ranges;
891 } else
892 ppcs->ranges = 0;
893 pca->id = pres->object->id;
894 COS_FREE(pres->object, "pdf_color_space");
895 pres->object = (cos_object_t *)pca;
896 cos_write_object(COS_OBJECT(pca), pdev);
897 }
898 ret:
899 if (by_name) {
900 /* Return a resource name rather than an object reference. */
901 discard(COS_RESOURCE_VALUE(pvalue, pca));
902 } else
903 discard(COS_OBJECT_VALUE(pvalue, pca));
904 if (pres != NULL) {
905 pres->where_used |= pdev->used_mask;
906 code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
907 if (code < 0)
908 return code;
909 }
910 return 0;
911 }
912
913 int
pdf_color_space(gx_device_pdf * pdev,cos_value_t * pvalue,const gs_range_t ** ppranges,const gs_color_space * pcs,const pdf_color_space_names_t * pcsn,bool by_name)914 pdf_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
915 const gs_range_t **ppranges,
916 const gs_color_space *pcs,
917 const pdf_color_space_names_t *pcsn,
918 bool by_name)
919 {
920 return pdf_color_space_named(pdev, pvalue, ppranges, pcs, pcsn, by_name, NULL, 0);
921 }
922
923 /* ---------------- Miscellaneous ---------------- */
924
925 /* Create colored and uncolored Pattern color spaces. */
926 private int
pdf_pattern_space(gx_device_pdf * pdev,cos_value_t * pvalue,pdf_resource_t ** ppres,const char * cs_name)927 pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
928 pdf_resource_t **ppres, const char *cs_name)
929 {
930 int code;
931
932 if (!*ppres) {
933 int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
934 ppres);
935
936 if (code < 0)
937 return code;
938 pprints1(pdev->strm, "%s\n", cs_name);
939 pdf_end_resource(pdev);
940 (*ppres)->object->written = true; /* don't write at end */
941 ((pdf_color_space_t *)*ppres)->ranges = 0;
942 ((pdf_color_space_t *)*ppres)->serialized = 0;
943 }
944 code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres);
945 if (code < 0)
946 return code;
947 cos_resource_value(pvalue, (*ppres)->object);
948 return 0;
949 }
950 int
pdf_cs_Pattern_colored(gx_device_pdf * pdev,cos_value_t * pvalue)951 pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
952 {
953 return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
954 "[/Pattern]");
955 }
956 int
pdf_cs_Pattern_uncolored(gx_device_pdf * pdev,cos_value_t * pvalue)957 pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
958 {
959 /* Only for process colors. */
960 int ncomp = pdev->color_info.num_components;
961 static const char *const pcs_names[5] = {
962 0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
963 "[/Pattern /DeviceCMYK]"
964 };
965
966 return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
967 pcs_names[ncomp]);
968 }
969 int
pdf_cs_Pattern_uncolored_hl(gx_device_pdf * pdev,const gs_color_space * pcs,cos_value_t * pvalue)970 pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev,
971 const gs_color_space *pcs, cos_value_t *pvalue)
972 {
973 /* Only for high level colors. */
974 return pdf_color_space(pdev, pvalue, NULL, pcs, &pdf_color_space_names, true);
975 }
976
977 /* Set the ProcSets bits corresponding to an image color space. */
978 void
pdf_color_space_procsets(gx_device_pdf * pdev,const gs_color_space * pcs)979 pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
980 {
981 const gs_color_space *pbcs = pcs;
982
983 csw:
984 switch (gs_color_space_get_index(pbcs)) {
985 case gs_color_space_index_DeviceGray:
986 case gs_color_space_index_CIEA:
987 /* We only handle CIEBasedA spaces that map to CalGray. */
988 pdev->procsets |= ImageB;
989 break;
990 case gs_color_space_index_Indexed:
991 pdev->procsets |= ImageI;
992 pbcs = (const gs_color_space *)&pcs->params.indexed.base_space;
993 goto csw;
994 default:
995 pdev->procsets |= ImageC;
996 break;
997 }
998 }
999