xref: /plan9/sys/src/cmd/gs/src/gdevpdfc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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