13ff48bf5SDavid du Colombier /* Copyright (C) 1999, 2000, 2001 Aladdin Enterprises. All rights reserved.
23ff48bf5SDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
53ff48bf5SDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gdevpdfc.c,v 1.54 2005/10/18 09:05:58 leonardo Exp $ */
183ff48bf5SDavid du Colombier /* Color space management and writing for pdfwrite driver */
193ff48bf5SDavid du Colombier #include "math_.h"
203ff48bf5SDavid du Colombier #include "memory_.h"
213ff48bf5SDavid du Colombier #include "gx.h"
223ff48bf5SDavid du Colombier #include "gscspace.h" /* for gscie.h */
233ff48bf5SDavid du Colombier #include "gscdevn.h"
243ff48bf5SDavid du Colombier #include "gscie.h"
253ff48bf5SDavid du Colombier #include "gscindex.h"
263ff48bf5SDavid du Colombier #include "gscsepr.h"
273ff48bf5SDavid du Colombier #include "stream.h"
283ff48bf5SDavid du Colombier #include "gsicc.h"
293ff48bf5SDavid du Colombier #include "gserrors.h"
303ff48bf5SDavid du Colombier #include "gdevpdfx.h"
313ff48bf5SDavid du Colombier #include "gdevpdfg.h"
32*593dc095SDavid du Colombier #include "gdevpdfc.h"
333ff48bf5SDavid du Colombier #include "gdevpdfo.h"
343ff48bf5SDavid du Colombier #include "strimpl.h"
353ff48bf5SDavid du Colombier #include "sstring.h"
36*593dc095SDavid du Colombier #include "gxcspace.h"
37*593dc095SDavid du Colombier #include <assert.h>
38*593dc095SDavid du Colombier
39*593dc095SDavid du Colombier /*
40*593dc095SDavid du Colombier * PDF doesn't have general CIEBased color spaces. However, it provides
41*593dc095SDavid du Colombier * two methods for handling general CIE spaces:
42*593dc095SDavid du Colombier *
43*593dc095SDavid du Colombier * - For PDF 1.2 and above, we note that the transformation from L*a*b*
44*593dc095SDavid du Colombier * space to XYZ space is invertible, so we can handle any PostScript
45*593dc095SDavid du Colombier * CIEBased space by transforming color values in that space to XYZ,
46*593dc095SDavid du Colombier * then inverse-transforming them to L*a*b* and using a PDF Lab space
47*593dc095SDavid du Colombier * with the same WhitePoint and BlackPoint and appropriate ranges for
48*593dc095SDavid du Colombier * a and b. This approach has the drawback that Y values outside the
49*593dc095SDavid du Colombier * range [0..1] can't be represented: we just clamp them.
50*593dc095SDavid du Colombier *
51*593dc095SDavid du Colombier * - For PDF 1.3 and above, we can create an ICCBased space. This is
52*593dc095SDavid du Colombier * actually necessary, not just an option, because for shadings (also
53*593dc095SDavid du Colombier * introduced in PDF 1.3), we want color interpolation to occur in the
54*593dc095SDavid du Colombier * original space.
55*593dc095SDavid du Colombier *
56*593dc095SDavid du Colombier * The Lab approach is not currently implemented, because it requires
57*593dc095SDavid du Colombier * transforming all the sample values of images. The ICCBased approach is
58*593dc095SDavid du Colombier * implemented for color spaces whose ranges lie within [0..1], which are
59*593dc095SDavid du Colombier * the only ranges supported by the ICC standard: we think that removing
60*593dc095SDavid du Colombier * this limitation would also require transforming image sample values.
61*593dc095SDavid du Colombier */
62*593dc095SDavid du Colombier
63*593dc095SDavid du Colombier /* GC descriptors */
64*593dc095SDavid du Colombier public_st_pdf_color_space();
653ff48bf5SDavid du Colombier
663ff48bf5SDavid du Colombier /* ------ CIE space testing ------ */
673ff48bf5SDavid du Colombier
683ff48bf5SDavid du Colombier /* Test whether a cached CIE procedure is the identity function. */
693ff48bf5SDavid du Colombier #define CIE_CACHE_IS_IDENTITY(pc)\
703ff48bf5SDavid du Colombier ((pc)->floats.params.is_identity)
713ff48bf5SDavid du Colombier #define CIE_CACHE3_IS_IDENTITY(pca)\
723ff48bf5SDavid du Colombier (CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\
733ff48bf5SDavid du Colombier CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\
743ff48bf5SDavid du Colombier CIE_CACHE_IS_IDENTITY(&(pca)[2]))
753ff48bf5SDavid du Colombier
763ff48bf5SDavid du Colombier /*
773ff48bf5SDavid du Colombier * Test whether a cached CIE procedure is an exponential. A cached
783ff48bf5SDavid du Colombier * procedure is exponential iff f(x) = k*(x^p). We make a very cursory
793ff48bf5SDavid du Colombier * check for this: we require that f(0) = 0, set k = f(1), set p =
803ff48bf5SDavid du Colombier * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
813ff48bf5SDavid du Colombier * two arbitrarily chosen values between 0 and 1. Naturally all this is
823ff48bf5SDavid du Colombier * done with some slop.
833ff48bf5SDavid du Colombier */
843ff48bf5SDavid du Colombier #define CC_INDEX_A (gx_cie_cache_size / 3)
853ff48bf5SDavid du Colombier #define CC_INDEX_B (gx_cie_cache_size * 2 / 3)
86*593dc095SDavid du Colombier #define CC_INDEX_1 (gx_cie_cache_size - 1)
87*593dc095SDavid du Colombier #define CC_KEY(i) ((i) / (double)CC_INDEX_1)
88*593dc095SDavid du Colombier #define CC_KEY_A CC_KEY(CC_INDEX_A)
89*593dc095SDavid du Colombier #define CC_KEY_B CC_KEY(CC_INDEX_B)
903ff48bf5SDavid du Colombier
913ff48bf5SDavid du Colombier private bool
cie_values_are_exponential(floatp v0,floatp va,floatp vb,floatp k,float * pexpt)92*593dc095SDavid du Colombier cie_values_are_exponential(floatp v0, floatp va, floatp vb, floatp k,
93*593dc095SDavid du Colombier float *pexpt)
943ff48bf5SDavid du Colombier {
953ff48bf5SDavid du Colombier double p;
963ff48bf5SDavid du Colombier
97*593dc095SDavid du Colombier if (fabs(v0) >= 0.001 || fabs(k) < 0.001)
983ff48bf5SDavid du Colombier return false;
993ff48bf5SDavid du Colombier if (va == 0 || (va > 0) != (k > 0))
1003ff48bf5SDavid du Colombier return false;
101*593dc095SDavid du Colombier p = log(va / k) / log(CC_KEY_A);
102*593dc095SDavid du Colombier if (fabs(vb - k * pow(CC_KEY_B, p)) >= 0.001)
1033ff48bf5SDavid du Colombier return false;
1043ff48bf5SDavid du Colombier *pexpt = p;
1053ff48bf5SDavid du Colombier return true;
1063ff48bf5SDavid du Colombier }
1073ff48bf5SDavid du Colombier
1083ff48bf5SDavid du Colombier private bool
cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc,float * pexpt)1093ff48bf5SDavid du Colombier cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt)
1103ff48bf5SDavid du Colombier {
111*593dc095SDavid du Colombier return cie_values_are_exponential(pc->floats.values[0],
112*593dc095SDavid du Colombier pc->floats.values[CC_INDEX_A],
1133ff48bf5SDavid du Colombier pc->floats.values[CC_INDEX_B],
114*593dc095SDavid du Colombier pc->floats.values[CC_INDEX_1],
1153ff48bf5SDavid du Colombier pexpt);
1163ff48bf5SDavid du Colombier }
1173ff48bf5SDavid du Colombier #define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\
1183ff48bf5SDavid du Colombier (cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\
1193ff48bf5SDavid du Colombier cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\
1203ff48bf5SDavid du Colombier cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w))
1213ff48bf5SDavid du Colombier
1223ff48bf5SDavid du Colombier private bool
cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc,float * pexpt)1233ff48bf5SDavid du Colombier cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt)
1243ff48bf5SDavid du Colombier {
125*593dc095SDavid du Colombier return cie_values_are_exponential(pc->vecs.values[0].u,
126*593dc095SDavid du Colombier pc->vecs.values[CC_INDEX_A].u,
1273ff48bf5SDavid du Colombier pc->vecs.values[CC_INDEX_B].u,
128*593dc095SDavid du Colombier pc->vecs.values[CC_INDEX_1].u,
1293ff48bf5SDavid du Colombier pexpt);
1303ff48bf5SDavid du Colombier }
1313ff48bf5SDavid du Colombier #define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\
1323ff48bf5SDavid du Colombier (cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\
1333ff48bf5SDavid du Colombier cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\
1343ff48bf5SDavid du Colombier cie_vector_cache_is_exponential(&(pca)[2], &(expts).w))
1353ff48bf5SDavid du Colombier
1363ff48bf5SDavid du Colombier #undef CC_INDEX_A
1373ff48bf5SDavid du Colombier #undef CC_INDEX_B
138*593dc095SDavid du Colombier #undef CC_KEY_A
139*593dc095SDavid du Colombier #undef CC_KEY_B
1403ff48bf5SDavid du Colombier
1413ff48bf5SDavid du Colombier /*
142*593dc095SDavid du Colombier * Test whether a cached CIEBasedABC space consists only of a single
143*593dc095SDavid du Colombier * Decode step followed by a single Matrix step.
1443ff48bf5SDavid du Colombier */
145*593dc095SDavid du Colombier private cie_cache_one_step_t
cie_cached_abc_is_one_step(const gs_cie_abc * pcie,const gs_matrix3 ** ppmat)146*593dc095SDavid du Colombier cie_cached_abc_is_one_step(const gs_cie_abc *pcie, const gs_matrix3 **ppmat)
1473ff48bf5SDavid du Colombier {
148*593dc095SDavid du Colombier /* The order of steps is, DecodeABC, MatrixABC, DecodeLMN, MatrixLMN. */
149*593dc095SDavid du Colombier
150*593dc095SDavid du Colombier if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN)) {
151*593dc095SDavid du Colombier if (pcie->MatrixABC.is_identity) {
152*593dc095SDavid du Colombier *ppmat = &pcie->common.MatrixLMN;
153*593dc095SDavid du Colombier return ONE_STEP_ABC;
1543ff48bf5SDavid du Colombier }
155*593dc095SDavid du Colombier if (pcie->common.MatrixLMN.is_identity) {
156*593dc095SDavid du Colombier *ppmat = &pcie->MatrixABC;
157*593dc095SDavid du Colombier return ONE_STEP_ABC;
1583ff48bf5SDavid du Colombier }
1593ff48bf5SDavid du Colombier }
160*593dc095SDavid du Colombier if (CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC.caches)) {
161*593dc095SDavid du Colombier if (pcie->MatrixABC.is_identity) {
162*593dc095SDavid du Colombier *ppmat = &pcie->common.MatrixLMN;
163*593dc095SDavid du Colombier return ONE_STEP_LMN;
1643ff48bf5SDavid du Colombier }
1653ff48bf5SDavid du Colombier }
166*593dc095SDavid du Colombier return ONE_STEP_NOT;
1673ff48bf5SDavid du Colombier }
1683ff48bf5SDavid du Colombier
1693ff48bf5SDavid du Colombier /*
170*593dc095SDavid du Colombier * Test whether a cached CIEBasedABC space is a L*a*b* space.
1713ff48bf5SDavid du Colombier */
172*593dc095SDavid du Colombier private bool
cie_scalar_cache_is_lab_lmn(const gs_cie_abc * pcie,int i)173*593dc095SDavid du Colombier cie_scalar_cache_is_lab_lmn(const gs_cie_abc *pcie, int i)
1743ff48bf5SDavid du Colombier {
175*593dc095SDavid du Colombier double k = CC_KEY(i);
176*593dc095SDavid du Colombier double g = (k >= 6.0 / 29 ? k * k * k :
177*593dc095SDavid du Colombier (k - 4.0 / 29) * (108.0 / 841));
178*593dc095SDavid du Colombier
179*593dc095SDavid du Colombier #define CC_V(j,i) (pcie->common.caches.DecodeLMN[j].floats.values[i])
180*593dc095SDavid du Colombier #define CC_WP(uvw) (pcie->common.points.WhitePoint.uvw)
181*593dc095SDavid du Colombier
182*593dc095SDavid du Colombier return (fabs(CC_V(0, i) - g * CC_WP(u)) < 0.001 &&
183*593dc095SDavid du Colombier fabs(CC_V(1, i) - g * CC_WP(v)) < 0.001 &&
184*593dc095SDavid du Colombier fabs(CC_V(2, i) - g * CC_WP(w)) < 0.001
185*593dc095SDavid du Colombier );
186*593dc095SDavid du Colombier
187*593dc095SDavid du Colombier #undef CC_V
188*593dc095SDavid du Colombier #undef CC_WP
1893ff48bf5SDavid du Colombier }
190*593dc095SDavid du Colombier private bool
cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t * pvc,int i)191*593dc095SDavid du Colombier cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t *pvc, int i)
192*593dc095SDavid du Colombier {
193*593dc095SDavid du Colombier const gx_cie_vector_cache *const pc3 = pvc->caches;
194*593dc095SDavid du Colombier double k = CC_KEY(i);
195*593dc095SDavid du Colombier double l0 = pc3[0].vecs.params.base,
196*593dc095SDavid du Colombier l = l0 + k * (pc3[0].vecs.params.limit - l0);
197*593dc095SDavid du Colombier double a0 = pc3[1].vecs.params.base,
198*593dc095SDavid du Colombier a = a0 + k * (pc3[1].vecs.params.limit - a0);
199*593dc095SDavid du Colombier double b0 = pc3[2].vecs.params.base,
200*593dc095SDavid du Colombier b = b0 + k * (pc3[2].vecs.params.limit - b0);
201*593dc095SDavid du Colombier
202*593dc095SDavid du Colombier return (fabs(cie_cached2float(pc3[0].vecs.values[i].u) -
203*593dc095SDavid du Colombier (l + 16) / 116) < 0.001 &&
204*593dc095SDavid du Colombier fabs(cie_cached2float(pc3[1].vecs.values[i].u) -
205*593dc095SDavid du Colombier a / 500) < 0.001 &&
206*593dc095SDavid du Colombier fabs(cie_cached2float(pc3[2].vecs.values[i].w) -
207*593dc095SDavid du Colombier b / -200) < 0.001
208*593dc095SDavid du Colombier );
2093ff48bf5SDavid du Colombier }
2103ff48bf5SDavid du Colombier
211*593dc095SDavid du Colombier private bool
cie_is_lab(const gs_cie_abc * pcie)212*593dc095SDavid du Colombier cie_is_lab(const gs_cie_abc *pcie)
213*593dc095SDavid du Colombier {
214*593dc095SDavid du Colombier int i;
215*593dc095SDavid du Colombier
216*593dc095SDavid du Colombier /* Check MatrixABC and MatrixLMN. */
217*593dc095SDavid du Colombier if (!(pcie->MatrixABC.cu.u == 1 && pcie->MatrixABC.cu.v == 1 &&
218*593dc095SDavid du Colombier pcie->MatrixABC.cu.w == 1 &&
219*593dc095SDavid du Colombier pcie->MatrixABC.cv.u == 1 && pcie->MatrixABC.cv.v == 0 &&
220*593dc095SDavid du Colombier pcie->MatrixABC.cv.w == 0 &&
221*593dc095SDavid du Colombier pcie->MatrixABC.cw.u == 0 && pcie->MatrixABC.cw.v == 0 &&
222*593dc095SDavid du Colombier pcie->MatrixABC.cw.w == -1 &&
223*593dc095SDavid du Colombier pcie->common.MatrixLMN.is_identity
224*593dc095SDavid du Colombier ))
225*593dc095SDavid du Colombier return false;
226*593dc095SDavid du Colombier
227*593dc095SDavid du Colombier /* Check DecodeABC and DecodeLMN. */
228*593dc095SDavid du Colombier for (i = 0; i <= CC_INDEX_1; ++i)
229*593dc095SDavid du Colombier if (!(cie_vector_cache_is_lab_abc(&pcie->caches.DecodeABC, i) &&
230*593dc095SDavid du Colombier cie_scalar_cache_is_lab_lmn(pcie, i)
231*593dc095SDavid du Colombier ))
232*593dc095SDavid du Colombier return false;
233*593dc095SDavid du Colombier
234*593dc095SDavid du Colombier return true;
235*593dc095SDavid du Colombier }
236*593dc095SDavid du Colombier
237*593dc095SDavid du Colombier #undef CC_INDEX_1
238*593dc095SDavid du Colombier #undef CC_KEY
239*593dc095SDavid du Colombier
240*593dc095SDavid du Colombier /* Test whether one or more CIE-based ranges are [0..1]. */
241*593dc095SDavid du Colombier private bool
cie_ranges_are_0_1(const gs_range * prange,int n)242*593dc095SDavid du Colombier cie_ranges_are_0_1(const gs_range *prange, int n)
243*593dc095SDavid du Colombier {
244*593dc095SDavid du Colombier int i;
245*593dc095SDavid du Colombier
246*593dc095SDavid du Colombier for (i = 0; i < n; ++i)
247*593dc095SDavid du Colombier if (prange[i].rmin != 0 || prange[i].rmax != 1)
248*593dc095SDavid du Colombier return false;
249*593dc095SDavid du Colombier return true;
250*593dc095SDavid du Colombier }
251*593dc095SDavid du Colombier
252*593dc095SDavid du Colombier /* ------ Utilities ------ */
253*593dc095SDavid du Colombier
2543ff48bf5SDavid du Colombier /* Add a 3-element vector to a Cos array or dictionary. */
2553ff48bf5SDavid du Colombier private int
cos_array_add_vector3(cos_array_t * pca,const gs_vector3 * pvec)2563ff48bf5SDavid du Colombier cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec)
2573ff48bf5SDavid du Colombier {
2583ff48bf5SDavid du Colombier int code = cos_array_add_real(pca, pvec->u);
2593ff48bf5SDavid du Colombier
2603ff48bf5SDavid du Colombier if (code >= 0)
2613ff48bf5SDavid du Colombier code = cos_array_add_real(pca, pvec->v);
2623ff48bf5SDavid du Colombier if (code >= 0)
2633ff48bf5SDavid du Colombier code = cos_array_add_real(pca, pvec->w);
2643ff48bf5SDavid du Colombier return code;
2653ff48bf5SDavid du Colombier }
2663ff48bf5SDavid du Colombier private int
cos_dict_put_c_key_vector3(cos_dict_t * pcd,const char * key,const gs_vector3 * pvec)2673ff48bf5SDavid du Colombier cos_dict_put_c_key_vector3(cos_dict_t *pcd, const char *key,
2683ff48bf5SDavid du Colombier const gs_vector3 *pvec)
2693ff48bf5SDavid du Colombier {
2703ff48bf5SDavid du Colombier cos_array_t *pca = cos_array_alloc(pcd->pdev, "cos_array_from_vector3");
2713ff48bf5SDavid du Colombier int code;
2723ff48bf5SDavid du Colombier
2733ff48bf5SDavid du Colombier if (pca == 0)
2743ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
2753ff48bf5SDavid du Colombier code = cos_array_add_vector3(pca, pvec);
2763ff48bf5SDavid du Colombier if (code < 0) {
2773ff48bf5SDavid du Colombier COS_FREE(pca, "cos_array_from_vector3");
2783ff48bf5SDavid du Colombier return code;
2793ff48bf5SDavid du Colombier }
2803ff48bf5SDavid du Colombier return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
2813ff48bf5SDavid du Colombier }
2823ff48bf5SDavid du Colombier
283*593dc095SDavid du Colombier /*
284*593dc095SDavid du Colombier * Finish creating a CIE-based color space (Calxxx or Lab.)
285*593dc095SDavid du Colombier * This procedure is exported for gdevpdfk.c.
286*593dc095SDavid du Colombier */
287*593dc095SDavid du Colombier int
pdf_finish_cie_space(cos_array_t * pca,cos_dict_t * pcd,const gs_cie_common * pciec)288*593dc095SDavid du Colombier pdf_finish_cie_space(cos_array_t *pca, cos_dict_t *pcd,
289*593dc095SDavid du Colombier const gs_cie_common *pciec)
290*593dc095SDavid du Colombier {
291*593dc095SDavid du Colombier int code = cos_dict_put_c_key_vector3(pcd, "/WhitePoint",
292*593dc095SDavid du Colombier &pciec->points.WhitePoint);
293*593dc095SDavid du Colombier
294*593dc095SDavid du Colombier if (code < 0)
295*593dc095SDavid du Colombier return code;
296*593dc095SDavid du Colombier if (pciec->points.BlackPoint.u != 0 ||
297*593dc095SDavid du Colombier pciec->points.BlackPoint.v != 0 ||
298*593dc095SDavid du Colombier pciec->points.BlackPoint.w != 0
299*593dc095SDavid du Colombier ) {
300*593dc095SDavid du Colombier code = cos_dict_put_c_key_vector3(pcd, "/BlackPoint",
301*593dc095SDavid du Colombier &pciec->points.BlackPoint);
302*593dc095SDavid du Colombier if (code < 0)
303*593dc095SDavid du Colombier return code;
304*593dc095SDavid du Colombier }
305*593dc095SDavid du Colombier return cos_array_add_object(pca, COS_OBJECT(pcd));
306*593dc095SDavid du Colombier }
307*593dc095SDavid du Colombier
308*593dc095SDavid du Colombier /* ------ Color space writing ------ */
309*593dc095SDavid du Colombier
310*593dc095SDavid du Colombier /* Define standard and short color space names. */
311*593dc095SDavid du Colombier const pdf_color_space_names_t pdf_color_space_names = {
312*593dc095SDavid du Colombier PDF_COLOR_SPACE_NAMES
313*593dc095SDavid du Colombier };
314*593dc095SDavid du Colombier const pdf_color_space_names_t pdf_color_space_names_short = {
315*593dc095SDavid du Colombier PDF_COLOR_SPACE_NAMES_SHORT
316*593dc095SDavid du Colombier };
317*593dc095SDavid du Colombier
318*593dc095SDavid du Colombier /*
319*593dc095SDavid du Colombier * Create a local Device{Gray,RGB,CMYK} color space corresponding to the
320*593dc095SDavid du Colombier * given number of components.
321*593dc095SDavid du Colombier */
322*593dc095SDavid du Colombier int
pdf_cspace_init_Device(const gs_memory_t * mem,gs_color_space * pcs,int num_components)323*593dc095SDavid du Colombier pdf_cspace_init_Device(const gs_memory_t *mem, gs_color_space *pcs, int num_components)
324*593dc095SDavid du Colombier {
325*593dc095SDavid du Colombier switch (num_components) {
326*593dc095SDavid du Colombier case 1: gs_cspace_init_DeviceGray(mem, pcs); break;
327*593dc095SDavid du Colombier case 3: gs_cspace_init_DeviceRGB(mem, pcs); break;
328*593dc095SDavid du Colombier case 4: gs_cspace_init_DeviceCMYK(mem, pcs); break;
329*593dc095SDavid du Colombier default: return_error(gs_error_rangecheck);
330*593dc095SDavid du Colombier }
331*593dc095SDavid du Colombier return 0;
332*593dc095SDavid du Colombier }
333*593dc095SDavid du Colombier
3343ff48bf5SDavid du Colombier /* Create a Separation or DeviceN color space (internal). */
3353ff48bf5SDavid du Colombier 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)3363ff48bf5SDavid du Colombier pdf_separation_color_space(gx_device_pdf *pdev,
3373ff48bf5SDavid du Colombier cos_array_t *pca, const char *csname,
3383ff48bf5SDavid du Colombier const cos_value_t *snames,
3393ff48bf5SDavid du Colombier const gs_color_space *alt_space,
3403ff48bf5SDavid du Colombier const gs_function_t *pfn,
3413ff48bf5SDavid du Colombier const pdf_color_space_names_t *pcsn)
3423ff48bf5SDavid du Colombier {
3433ff48bf5SDavid du Colombier cos_value_t v;
344*593dc095SDavid du Colombier const gs_range_t *ranges;
3453ff48bf5SDavid du Colombier int code;
3463ff48bf5SDavid du Colombier
3473ff48bf5SDavid du Colombier if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
3483ff48bf5SDavid du Colombier (code = cos_array_add_no_copy(pca, snames)) < 0 ||
349*593dc095SDavid du Colombier (code = pdf_color_space(pdev, &v, &ranges, alt_space, pcsn, false)) < 0 ||
3503ff48bf5SDavid du Colombier (code = cos_array_add(pca, &v)) < 0 ||
351*593dc095SDavid du Colombier (code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
3523ff48bf5SDavid du Colombier (code = cos_array_add(pca, &v)) < 0
3533ff48bf5SDavid du Colombier )
3543ff48bf5SDavid du Colombier return code;
3553ff48bf5SDavid du Colombier return 0;
3563ff48bf5SDavid du Colombier }
3573ff48bf5SDavid du Colombier
3583ff48bf5SDavid du Colombier /*
359*593dc095SDavid du Colombier * Create an Indexed color space. This is a single-use procedure,
360*593dc095SDavid du Colombier * broken out only for readability.
361*593dc095SDavid du Colombier */
362*593dc095SDavid du Colombier private int
pdf_indexed_color_space(gx_device_pdf * pdev,cos_value_t * pvalue,const gs_color_space * pcs,cos_array_t * pca)363*593dc095SDavid du Colombier pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
364*593dc095SDavid du Colombier const gs_color_space *pcs, cos_array_t *pca)
365*593dc095SDavid du Colombier {
366*593dc095SDavid du Colombier const gs_indexed_params *pip = &pcs->params.indexed;
367*593dc095SDavid du Colombier const gs_color_space *base_space =
368*593dc095SDavid du Colombier (const gs_color_space *)&pip->base_space;
369*593dc095SDavid du Colombier int num_entries = pip->hival + 1;
370*593dc095SDavid du Colombier int num_components = gs_color_space_num_components(base_space);
371*593dc095SDavid du Colombier uint table_size = num_entries * num_components;
372*593dc095SDavid du Colombier /* Guess at the extra space needed for PS string encoding. */
373*593dc095SDavid du Colombier uint string_size = 2 + table_size * 4;
374*593dc095SDavid du Colombier uint string_used;
375*593dc095SDavid du Colombier byte buf[100]; /* arbitrary */
376*593dc095SDavid du Colombier stream_AXE_state st;
377*593dc095SDavid du Colombier stream s, es;
378*593dc095SDavid du Colombier gs_memory_t *mem = pdev->pdf_memory;
379*593dc095SDavid du Colombier byte *table;
380*593dc095SDavid du Colombier byte *palette;
381*593dc095SDavid du Colombier gs_color_space cs_gray;
382*593dc095SDavid du Colombier cos_value_t v;
383*593dc095SDavid du Colombier int code;
384*593dc095SDavid du Colombier
385*593dc095SDavid du Colombier /* PDF doesn't support Indexed color spaces with more than 256 entries. */
386*593dc095SDavid du Colombier if (num_entries > 256)
387*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
388*593dc095SDavid du Colombier if (pdev->CompatibilityLevel < 1.3) {
389*593dc095SDavid du Colombier switch (gs_color_space_get_index(pcs)) {
390*593dc095SDavid du Colombier case gs_color_space_index_Pattern:
391*593dc095SDavid du Colombier case gs_color_space_index_Separation:
392*593dc095SDavid du Colombier case gs_color_space_index_Indexed:
393*593dc095SDavid du Colombier case gs_color_space_index_DeviceN:
394*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
395*593dc095SDavid du Colombier default: DO_NOTHING;
396*593dc095SDavid du Colombier }
397*593dc095SDavid du Colombier
398*593dc095SDavid du Colombier }
399*593dc095SDavid du Colombier table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
400*593dc095SDavid du Colombier palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
401*593dc095SDavid du Colombier if (table == 0 || palette == 0) {
402*593dc095SDavid du Colombier gs_free_string(mem, palette, table_size,
403*593dc095SDavid du Colombier "pdf_color_space(palette)");
404*593dc095SDavid du Colombier gs_free_string(mem, table, string_size,
405*593dc095SDavid du Colombier "pdf_color_space(table)");
406*593dc095SDavid du Colombier return_error(gs_error_VMerror);
407*593dc095SDavid du Colombier }
408*593dc095SDavid du Colombier swrite_string(&s, table, string_size);
409*593dc095SDavid du Colombier s_init(&es, mem);
410*593dc095SDavid du Colombier s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
411*593dc095SDavid du Colombier s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
412*593dc095SDavid du Colombier sputc(&s, '(');
413*593dc095SDavid du Colombier if (pcs->params.indexed.use_proc) {
414*593dc095SDavid du Colombier gs_client_color cmin, cmax;
415*593dc095SDavid du Colombier byte *pnext = palette;
416*593dc095SDavid du Colombier int i, j;
417*593dc095SDavid du Colombier
418*593dc095SDavid du Colombier /* Find the legal range for the color components. */
419*593dc095SDavid du Colombier for (j = 0; j < num_components; ++j)
420*593dc095SDavid du Colombier cmin.paint.values[j] = (float)min_long,
421*593dc095SDavid du Colombier cmax.paint.values[j] = (float)max_long;
422*593dc095SDavid du Colombier gs_color_space_restrict_color(&cmin, base_space);
423*593dc095SDavid du Colombier gs_color_space_restrict_color(&cmax, base_space);
424*593dc095SDavid du Colombier /*
425*593dc095SDavid du Colombier * Compute the palette values, with the legal range for each
426*593dc095SDavid du Colombier * one mapped to [0 .. 255].
427*593dc095SDavid du Colombier */
428*593dc095SDavid du Colombier for (i = 0; i < num_entries; ++i) {
429*593dc095SDavid du Colombier gs_client_color cc;
430*593dc095SDavid du Colombier
431*593dc095SDavid du Colombier gs_cspace_indexed_lookup(&pcs->params.indexed, i, &cc);
432*593dc095SDavid du Colombier for (j = 0; j < num_components; ++j) {
433*593dc095SDavid du Colombier float v = (cc.paint.values[j] - cmin.paint.values[j])
434*593dc095SDavid du Colombier * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
435*593dc095SDavid du Colombier
436*593dc095SDavid du Colombier *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
437*593dc095SDavid du Colombier }
438*593dc095SDavid du Colombier }
439*593dc095SDavid du Colombier } else
440*593dc095SDavid du Colombier memcpy(palette, pip->lookup.table.data, table_size);
441*593dc095SDavid du Colombier if (gs_color_space_get_index(base_space) ==
442*593dc095SDavid du Colombier gs_color_space_index_DeviceRGB
443*593dc095SDavid du Colombier ) {
444*593dc095SDavid du Colombier /* Check for an all-gray palette3. */
445*593dc095SDavid du Colombier int i;
446*593dc095SDavid du Colombier
447*593dc095SDavid du Colombier for (i = table_size; (i -= 3) >= 0; )
448*593dc095SDavid du Colombier if (palette[i] != palette[i + 1] ||
449*593dc095SDavid du Colombier palette[i] != palette[i + 2]
450*593dc095SDavid du Colombier )
451*593dc095SDavid du Colombier break;
452*593dc095SDavid du Colombier if (i < 0) {
453*593dc095SDavid du Colombier /* Change the color space to DeviceGray. */
454*593dc095SDavid du Colombier for (i = 0; i < num_entries; ++i)
455*593dc095SDavid du Colombier palette[i] = palette[i * 3];
456*593dc095SDavid du Colombier table_size = num_entries;
457*593dc095SDavid du Colombier gs_cspace_init_DeviceGray(mem, &cs_gray);
458*593dc095SDavid du Colombier base_space = &cs_gray;
459*593dc095SDavid du Colombier }
460*593dc095SDavid du Colombier }
461*593dc095SDavid du Colombier stream_write(&es, palette, table_size);
462*593dc095SDavid du Colombier gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
463*593dc095SDavid du Colombier sclose(&es);
464*593dc095SDavid du Colombier sflush(&s);
465*593dc095SDavid du Colombier string_used = (uint)stell(&s);
466*593dc095SDavid du Colombier table = gs_resize_string(mem, table, string_size, string_used,
467*593dc095SDavid du Colombier "pdf_color_space(table)");
468*593dc095SDavid du Colombier /*
469*593dc095SDavid du Colombier * Since the array is always referenced by name as a resource
470*593dc095SDavid du Colombier * rather than being written as a value, even for in-line images,
471*593dc095SDavid du Colombier * always use the full name for the color space.
472*593dc095SDavid du Colombier *
473*593dc095SDavid du Colombier * We don't have to worry about the range of the base space:
474*593dc095SDavid du Colombier * in PDF, unlike PostScript, the values from the lookup table are
475*593dc095SDavid du Colombier * scaled automatically.
476*593dc095SDavid du Colombier */
477*593dc095SDavid du Colombier if ((code = pdf_color_space(pdev, pvalue, NULL, base_space,
478*593dc095SDavid du Colombier &pdf_color_space_names, false)) < 0 ||
479*593dc095SDavid du Colombier (code = cos_array_add(pca,
480*593dc095SDavid du Colombier cos_c_string_value(&v,
481*593dc095SDavid du Colombier pdf_color_space_names.Indexed
482*593dc095SDavid du Colombier /*pcsn->Indexed*/))) < 0 ||
483*593dc095SDavid du Colombier (code = cos_array_add(pca, pvalue)) < 0 ||
484*593dc095SDavid du Colombier (code = cos_array_add_int(pca, pip->hival)) < 0 ||
485*593dc095SDavid du Colombier (code = cos_array_add_no_copy(pca,
486*593dc095SDavid du Colombier cos_string_value(&v, table,
487*593dc095SDavid du Colombier string_used))) < 0
488*593dc095SDavid du Colombier )
489*593dc095SDavid du Colombier return code;
490*593dc095SDavid du Colombier return 0;
491*593dc095SDavid du Colombier }
492*593dc095SDavid du Colombier
493*593dc095SDavid du Colombier /*
494*593dc095SDavid du Colombier * Find a color space resource by seriialized data.
495*593dc095SDavid du Colombier */
496*593dc095SDavid du Colombier private pdf_resource_t *
pdf_find_cspace_resource(gx_device_pdf * pdev,const byte * serialized,uint serialized_size)497*593dc095SDavid du Colombier pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size)
498*593dc095SDavid du Colombier {
499*593dc095SDavid du Colombier pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains;
500*593dc095SDavid du Colombier pdf_resource_t *pres;
501*593dc095SDavid du Colombier int i;
502*593dc095SDavid du Colombier
503*593dc095SDavid du Colombier for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
504*593dc095SDavid du Colombier for (pres = pchain[i]; pres != 0; pres = pres->next) {
505*593dc095SDavid du Colombier const pdf_color_space_t *const ppcs =
506*593dc095SDavid du Colombier (const pdf_color_space_t *)pres;
507*593dc095SDavid du Colombier if (ppcs->serialized_size != serialized_size)
508*593dc095SDavid du Colombier continue;
509*593dc095SDavid du Colombier if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size))
510*593dc095SDavid du Colombier return pres;
511*593dc095SDavid du Colombier }
512*593dc095SDavid du Colombier }
513*593dc095SDavid du Colombier return NULL;
514*593dc095SDavid du Colombier }
515*593dc095SDavid du Colombier
516*593dc095SDavid du Colombier
517*593dc095SDavid du Colombier /*
5183ff48bf5SDavid du Colombier * Create a PDF color space corresponding to a PostScript color space.
5193ff48bf5SDavid du Colombier * For parameterless color spaces, set *pvalue to a (literal) string with
520*593dc095SDavid du Colombier * the color space name; for other color spaces, create a cos_array_t if
521*593dc095SDavid du Colombier * necessary and set *pvalue to refer to it. In the latter case, if
522*593dc095SDavid du Colombier * by_name is true, return a string /Rxxxx rather than a reference to
523*593dc095SDavid du Colombier * the actual object.
524*593dc095SDavid du Colombier *
525*593dc095SDavid du Colombier * If ppranges is not NULL, then if the domain of the color space had
526*593dc095SDavid du Colombier * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
527*593dc095SDavid du Colombier * to the ranges in *ppranges, otherwise set *ppranges to 0.
5283ff48bf5SDavid du Colombier */
5293ff48bf5SDavid du Colombier 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*593dc095SDavid du Colombier pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue,
531*593dc095SDavid du Colombier const gs_range_t **ppranges,
5323ff48bf5SDavid du Colombier const gs_color_space *pcs,
5333ff48bf5SDavid du Colombier const pdf_color_space_names_t *pcsn,
534*593dc095SDavid du Colombier bool by_name, const byte *res_name, int name_length)
5353ff48bf5SDavid du Colombier {
5363ff48bf5SDavid du Colombier gs_color_space_index csi = gs_color_space_get_index(pcs);
5373ff48bf5SDavid du Colombier cos_array_t *pca;
5383ff48bf5SDavid du Colombier cos_dict_t *pcd;
5393ff48bf5SDavid du Colombier cos_value_t v;
5403ff48bf5SDavid du Colombier const gs_cie_common *pciec;
5413ff48bf5SDavid du Colombier gs_function_t *pfn;
542*593dc095SDavid du Colombier const gs_range_t *ranges = 0;
543*593dc095SDavid du Colombier uint serialized_size;
544*593dc095SDavid du Colombier byte *serialized = NULL, serialized0[100];
545*593dc095SDavid du Colombier pdf_resource_t *pres = NULL;
5463ff48bf5SDavid du Colombier int code;
5473ff48bf5SDavid du Colombier
548*593dc095SDavid du Colombier if (ppranges)
549*593dc095SDavid du Colombier *ppranges = 0; /* default */
5503ff48bf5SDavid du Colombier switch (csi) {
5513ff48bf5SDavid du Colombier case gs_color_space_index_DeviceGray:
5523ff48bf5SDavid du Colombier cos_c_string_value(pvalue, pcsn->DeviceGray);
5533ff48bf5SDavid du Colombier return 0;
5543ff48bf5SDavid du Colombier case gs_color_space_index_DeviceRGB:
5553ff48bf5SDavid du Colombier cos_c_string_value(pvalue, pcsn->DeviceRGB);
5563ff48bf5SDavid du Colombier return 0;
5573ff48bf5SDavid du Colombier case gs_color_space_index_DeviceCMYK:
5583ff48bf5SDavid du Colombier cos_c_string_value(pvalue, pcsn->DeviceCMYK);
5593ff48bf5SDavid du Colombier return 0;
5603ff48bf5SDavid du Colombier case gs_color_space_index_Pattern:
5613ff48bf5SDavid du Colombier if (!pcs->params.pattern.has_base_space) {
5623ff48bf5SDavid du Colombier cos_c_string_value(pvalue, "/Pattern");
5633ff48bf5SDavid du Colombier return 0;
5643ff48bf5SDavid du Colombier }
5653ff48bf5SDavid du Colombier break;
5663ff48bf5SDavid du Colombier case gs_color_space_index_CIEICC:
5673ff48bf5SDavid du Colombier /*
5683ff48bf5SDavid du Colombier * Take a special early exit for unrecognized ICCBased color spaces,
5693ff48bf5SDavid du Colombier * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
5703ff48bf5SDavid du Colombier */
5713ff48bf5SDavid du Colombier if (pcs->params.icc.picc_info->picc == 0 ||
5723ff48bf5SDavid du Colombier pdev->CompatibilityLevel < 1.3
573*593dc095SDavid du Colombier ) {
574*593dc095SDavid du Colombier if (res_name != NULL)
575*593dc095SDavid du Colombier return 0; /* Ignore .includecolorspace */
576*593dc095SDavid du Colombier return pdf_color_space( pdev, pvalue, ppranges,
5773ff48bf5SDavid du Colombier (const gs_color_space *)
5783ff48bf5SDavid du Colombier &pcs->params.icc.alt_space,
5793ff48bf5SDavid du Colombier pcsn, by_name);
580*593dc095SDavid du Colombier }
5813ff48bf5SDavid du Colombier break;
5823ff48bf5SDavid du Colombier default:
5833ff48bf5SDavid du Colombier break;
5843ff48bf5SDavid du Colombier }
5853ff48bf5SDavid du Colombier
586*593dc095SDavid du Colombier /* Check whether we already have a PDF object for this color space. */
587*593dc095SDavid du Colombier if (pcs->id != gs_no_id)
588*593dc095SDavid du Colombier pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
589*593dc095SDavid du Colombier if (pres == NULL) {
590*593dc095SDavid du Colombier stream s;
591*593dc095SDavid du Colombier
592*593dc095SDavid du Colombier s_init(&s, pdev->memory);
593*593dc095SDavid du Colombier swrite_position_only(&s);
594*593dc095SDavid du Colombier code = cs_serialize(pcs, &s);
595*593dc095SDavid du Colombier if (code < 0)
596*593dc095SDavid du Colombier return_error(gs_error_unregistered); /* Must not happen. */
597*593dc095SDavid du Colombier serialized_size = stell(&s);
598*593dc095SDavid du Colombier sclose(&s);
599*593dc095SDavid du Colombier if (serialized_size <= sizeof(serialized0))
600*593dc095SDavid du Colombier serialized = serialized0;
601*593dc095SDavid du Colombier else {
602*593dc095SDavid du Colombier serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
603*593dc095SDavid du Colombier if (serialized == NULL)
604*593dc095SDavid du Colombier return_error(gs_error_VMerror);
605*593dc095SDavid du Colombier }
606*593dc095SDavid du Colombier swrite_string(&s, serialized, serialized_size);
607*593dc095SDavid du Colombier code = cs_serialize(pcs, &s);
608*593dc095SDavid du Colombier if (code < 0)
609*593dc095SDavid du Colombier return_error(gs_error_unregistered); /* Must not happen. */
610*593dc095SDavid du Colombier if (stell(&s) != serialized_size)
611*593dc095SDavid du Colombier return_error(gs_error_unregistered); /* Must not happen. */
612*593dc095SDavid du Colombier sclose(&s);
613*593dc095SDavid du Colombier pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
614*593dc095SDavid du Colombier if (pres != NULL) {
615*593dc095SDavid du Colombier if (serialized != serialized0)
616*593dc095SDavid du Colombier gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
617*593dc095SDavid du Colombier serialized = NULL;
618*593dc095SDavid du Colombier }
619*593dc095SDavid du Colombier }
620*593dc095SDavid du Colombier if (pres) {
621*593dc095SDavid du Colombier const pdf_color_space_t *const ppcs =
622*593dc095SDavid du Colombier (const pdf_color_space_t *)pres;
623*593dc095SDavid du Colombier
624*593dc095SDavid du Colombier if (ppranges != 0 && ppcs->ranges != 0)
625*593dc095SDavid du Colombier *ppranges = ppcs->ranges;
626*593dc095SDavid du Colombier pca = (cos_array_t *)pres->object;
627*593dc095SDavid du Colombier goto ret;
628*593dc095SDavid du Colombier }
629*593dc095SDavid du Colombier
6303ff48bf5SDavid du Colombier /* Space has parameters -- create an array. */
6313ff48bf5SDavid du Colombier pca = cos_array_alloc(pdev, "pdf_color_space");
6323ff48bf5SDavid du Colombier if (pca == 0)
6333ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
634*593dc095SDavid du Colombier
6353ff48bf5SDavid du Colombier switch (csi) {
6363ff48bf5SDavid du Colombier
637*593dc095SDavid du Colombier case gs_color_space_index_CIEICC:
638*593dc095SDavid du Colombier code = pdf_iccbased_color_space(pdev, pvalue, pcs, pca);
6393ff48bf5SDavid du Colombier break;
6403ff48bf5SDavid du Colombier
6413ff48bf5SDavid du Colombier case gs_color_space_index_CIEA: {
6423ff48bf5SDavid du Colombier /* Check that we can represent this as a CalGray space. */
6433ff48bf5SDavid du Colombier const gs_cie_a *pcie = pcs->params.a;
644*593dc095SDavid du Colombier bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
645*593dc095SDavid du Colombier bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
646*593dc095SDavid du Colombier pcie->MatrixA.w == 1);
6473ff48bf5SDavid du Colombier gs_vector3 expts;
6483ff48bf5SDavid du Colombier
6493ff48bf5SDavid du Colombier pciec = (const gs_cie_common *)pcie;
650*593dc095SDavid du Colombier if (!pcie->common.MatrixLMN.is_identity) {
651*593dc095SDavid du Colombier code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
652*593dc095SDavid du Colombier &pcie->RangeA, ONE_STEP_NOT, NULL,
653*593dc095SDavid du Colombier &ranges);
654*593dc095SDavid du Colombier break;
655*593dc095SDavid du Colombier }
656*593dc095SDavid du Colombier if (unitary && identityA &&
657*593dc095SDavid du Colombier CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
6583ff48bf5SDavid du Colombier CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
6593ff48bf5SDavid du Colombier expts.v == expts.u && expts.w == expts.u
6603ff48bf5SDavid du Colombier ) {
6613ff48bf5SDavid du Colombier DO_NOTHING;
662*593dc095SDavid du Colombier } else if (unitary && identityA &&
663*593dc095SDavid du Colombier CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
6643ff48bf5SDavid du Colombier cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
6653ff48bf5SDavid du Colombier ) {
6663ff48bf5SDavid du Colombier DO_NOTHING;
667*593dc095SDavid du Colombier } else {
668*593dc095SDavid du Colombier code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
669*593dc095SDavid du Colombier &pcie->RangeA, ONE_STEP_NOT, NULL,
670*593dc095SDavid du Colombier &ranges);
671*593dc095SDavid du Colombier break;
672*593dc095SDavid du Colombier }
6733ff48bf5SDavid du Colombier code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
6743ff48bf5SDavid du Colombier if (code < 0)
6753ff48bf5SDavid du Colombier return code;
6763ff48bf5SDavid du Colombier pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
6773ff48bf5SDavid du Colombier if (pcd == 0)
6783ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
6793ff48bf5SDavid du Colombier if (expts.u != 1) {
6803ff48bf5SDavid du Colombier code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
6813ff48bf5SDavid du Colombier if (code < 0)
6823ff48bf5SDavid du Colombier return code;
6833ff48bf5SDavid du Colombier }
6843ff48bf5SDavid du Colombier }
6853ff48bf5SDavid du Colombier cal:
686*593dc095SDavid du Colombier /* Finish handling a CIE-based color space (Calxxx or Lab). */
6873ff48bf5SDavid du Colombier if (code < 0)
6883ff48bf5SDavid du Colombier return code;
689*593dc095SDavid du Colombier code = pdf_finish_cie_space(pca, pcd, pciec);
6903ff48bf5SDavid du Colombier break;
691*593dc095SDavid du Colombier
6923ff48bf5SDavid du Colombier case gs_color_space_index_CIEABC: {
6933ff48bf5SDavid du Colombier /* Check that we can represent this as a CalRGB space. */
6943ff48bf5SDavid du Colombier const gs_cie_abc *pcie = pcs->params.abc;
695*593dc095SDavid du Colombier bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
6963ff48bf5SDavid du Colombier gs_vector3 expts;
697*593dc095SDavid du Colombier const gs_matrix3 *pmat = NULL;
698*593dc095SDavid du Colombier cie_cache_one_step_t one_step =
699*593dc095SDavid du Colombier cie_cached_abc_is_one_step(pcie, &pmat);
7003ff48bf5SDavid du Colombier
7013ff48bf5SDavid du Colombier pciec = (const gs_cie_common *)pcie;
702*593dc095SDavid du Colombier if (unitary) {
703*593dc095SDavid du Colombier switch (one_step) {
704*593dc095SDavid du Colombier case ONE_STEP_ABC:
705*593dc095SDavid du Colombier if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
706*593dc095SDavid du Colombier goto calrgb;
707*593dc095SDavid du Colombier break;
708*593dc095SDavid du Colombier case ONE_STEP_LMN:
709*593dc095SDavid du Colombier if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
710*593dc095SDavid du Colombier goto calrgb;
711*593dc095SDavid du Colombier default:
712*593dc095SDavid du Colombier break;
713*593dc095SDavid du Colombier }
714*593dc095SDavid du Colombier }
715*593dc095SDavid du Colombier if (cie_is_lab(pcie)) {
716*593dc095SDavid du Colombier /* Represent this as a Lab space. */
717*593dc095SDavid du Colombier pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
718*593dc095SDavid du Colombier if (pcd == 0)
719*593dc095SDavid du Colombier return_error(gs_error_VMerror);
720*593dc095SDavid du Colombier code = pdf_put_lab_color_space(pca, pcd, pcie->RangeABC.ranges);
721*593dc095SDavid du Colombier goto cal;
722*593dc095SDavid du Colombier } else {
723*593dc095SDavid du Colombier code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
724*593dc095SDavid du Colombier pcie->RangeABC.ranges,
725*593dc095SDavid du Colombier one_step, pmat, &ranges);
726*593dc095SDavid du Colombier break;
727*593dc095SDavid du Colombier }
728*593dc095SDavid du Colombier calrgb:
7293ff48bf5SDavid du Colombier code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
7303ff48bf5SDavid du Colombier if (code < 0)
7313ff48bf5SDavid du Colombier return code;
7323ff48bf5SDavid du Colombier pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
7333ff48bf5SDavid du Colombier if (pcd == 0)
7343ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
7353ff48bf5SDavid du Colombier if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
7363ff48bf5SDavid du Colombier code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
7373ff48bf5SDavid du Colombier if (code < 0)
7383ff48bf5SDavid du Colombier return code;
7393ff48bf5SDavid du Colombier }
7403ff48bf5SDavid du Colombier if (!pmat->is_identity) {
7413ff48bf5SDavid du Colombier cos_array_t *pcma =
7423ff48bf5SDavid du Colombier cos_array_alloc(pdev, "pdf_color_space(Matrix)");
7433ff48bf5SDavid du Colombier
7443ff48bf5SDavid du Colombier if (pcma == 0)
7453ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
7463ff48bf5SDavid du Colombier if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
7473ff48bf5SDavid du Colombier (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
7483ff48bf5SDavid du Colombier (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
7493ff48bf5SDavid du Colombier (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
7503ff48bf5SDavid du Colombier COS_OBJECT_VALUE(&v, pcma))) < 0
7513ff48bf5SDavid du Colombier )
7523ff48bf5SDavid du Colombier return code;
7533ff48bf5SDavid du Colombier }
7543ff48bf5SDavid du Colombier }
7553ff48bf5SDavid du Colombier goto cal;
756*593dc095SDavid du Colombier
7573ff48bf5SDavid du Colombier case gs_color_space_index_CIEDEF:
758*593dc095SDavid du Colombier code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
759*593dc095SDavid du Colombier (const gs_cie_common *)pcs->params.def,
760*593dc095SDavid du Colombier pcs->params.def->RangeDEF.ranges,
761*593dc095SDavid du Colombier ONE_STEP_NOT, NULL, &ranges);
762*593dc095SDavid du Colombier break;
763*593dc095SDavid du Colombier
7643ff48bf5SDavid du Colombier case gs_color_space_index_CIEDEFG:
765*593dc095SDavid du Colombier code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
766*593dc095SDavid du Colombier (const gs_cie_common *)pcs->params.defg,
767*593dc095SDavid du Colombier pcs->params.defg->RangeDEFG.ranges,
768*593dc095SDavid du Colombier ONE_STEP_NOT, NULL, &ranges);
7693ff48bf5SDavid du Colombier break;
770*593dc095SDavid du Colombier
771*593dc095SDavid du Colombier case gs_color_space_index_Indexed:
772*593dc095SDavid du Colombier code = pdf_indexed_color_space(pdev, pvalue, pcs, pca);
7733ff48bf5SDavid du Colombier break;
774*593dc095SDavid du Colombier
7753ff48bf5SDavid du Colombier case gs_color_space_index_DeviceN:
776*593dc095SDavid du Colombier if (pdev->CompatibilityLevel < 1.3)
777*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
7783ff48bf5SDavid du Colombier pfn = gs_cspace_get_devn_function(pcs);
7793ff48bf5SDavid du Colombier /****** CURRENTLY WE ONLY HANDLE Functions ******/
7803ff48bf5SDavid du Colombier if (pfn == 0)
7813ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
7823ff48bf5SDavid du Colombier {
7833ff48bf5SDavid du Colombier cos_array_t *psna =
7843ff48bf5SDavid du Colombier cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
7853ff48bf5SDavid du Colombier int i;
786*593dc095SDavid du Colombier byte *name_string;
787*593dc095SDavid du Colombier uint name_string_length;
7883ff48bf5SDavid du Colombier
7893ff48bf5SDavid du Colombier if (psna == 0)
7903ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
7913ff48bf5SDavid du Colombier for (i = 0; i < pcs->params.device_n.num_components; ++i) {
792*593dc095SDavid du Colombier if ((code = pcs->params.device_n.get_colorname_string(
793*593dc095SDavid du Colombier pdev->memory,
794*593dc095SDavid du Colombier pcs->params.device_n.names[i], &name_string,
795*593dc095SDavid du Colombier &name_string_length)) < 0 ||
796*593dc095SDavid du Colombier (code = pdf_string_to_cos_name(pdev, name_string,
797*593dc095SDavid du Colombier name_string_length, &v)) < 0 ||
7983ff48bf5SDavid du Colombier (code = cos_array_add_no_copy(psna, &v)) < 0)
7993ff48bf5SDavid du Colombier return code;
8003ff48bf5SDavid du Colombier }
8013ff48bf5SDavid du Colombier COS_OBJECT_VALUE(&v, psna);
8023ff48bf5SDavid du Colombier if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
8033ff48bf5SDavid du Colombier (const gs_color_space *)
8043ff48bf5SDavid du Colombier &pcs->params.device_n.alt_space,
8053ff48bf5SDavid du Colombier pfn, &pdf_color_space_names)) < 0)
8063ff48bf5SDavid du Colombier return code;
8073ff48bf5SDavid du Colombier }
8083ff48bf5SDavid du Colombier break;
809*593dc095SDavid du Colombier
8103ff48bf5SDavid du Colombier case gs_color_space_index_Separation:
8113ff48bf5SDavid du Colombier pfn = gs_cspace_get_sepr_function(pcs);
8123ff48bf5SDavid du Colombier /****** CURRENTLY WE ONLY HANDLE Functions ******/
8133ff48bf5SDavid du Colombier if (pfn == 0)
8143ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
815*593dc095SDavid du Colombier {
816*593dc095SDavid du Colombier byte *name_string;
817*593dc095SDavid du Colombier uint name_string_length;
818*593dc095SDavid du Colombier if ((code = pcs->params.separation.get_colorname_string(
819*593dc095SDavid du Colombier pdev->memory,
820*593dc095SDavid du Colombier pcs->params.separation.sep_name, &name_string,
821*593dc095SDavid du Colombier &name_string_length)) < 0 ||
822*593dc095SDavid du Colombier (code = pdf_string_to_cos_name(pdev, name_string,
823*593dc095SDavid du Colombier name_string_length, &v)) < 0 ||
8243ff48bf5SDavid du Colombier (code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
8253ff48bf5SDavid du Colombier (const gs_color_space *)
8263ff48bf5SDavid du Colombier &pcs->params.separation.alt_space,
8273ff48bf5SDavid du Colombier pfn, &pdf_color_space_names)) < 0)
8283ff48bf5SDavid du Colombier return code;
829*593dc095SDavid du Colombier }
8303ff48bf5SDavid du Colombier break;
831*593dc095SDavid du Colombier
8323ff48bf5SDavid du Colombier case gs_color_space_index_Pattern:
833*593dc095SDavid du Colombier if ((code = pdf_color_space(pdev, pvalue, ppranges,
8343ff48bf5SDavid du Colombier (const gs_color_space *)
8353ff48bf5SDavid du Colombier &pcs->params.pattern.base_space,
8363ff48bf5SDavid du Colombier &pdf_color_space_names, false)) < 0 ||
8373ff48bf5SDavid du Colombier (code = cos_array_add(pca,
8383ff48bf5SDavid du Colombier cos_c_string_value(&v, "/Pattern"))) < 0 ||
8393ff48bf5SDavid du Colombier (code = cos_array_add(pca, pvalue)) < 0
8403ff48bf5SDavid du Colombier )
8413ff48bf5SDavid du Colombier return code;
8423ff48bf5SDavid du Colombier break;
843*593dc095SDavid du Colombier
8443ff48bf5SDavid du Colombier default:
8453ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
8463ff48bf5SDavid du Colombier }
8473ff48bf5SDavid du Colombier /*
8483ff48bf5SDavid du Colombier * Register the color space as a resource, since it must be referenced
8493ff48bf5SDavid du Colombier * by name rather than directly.
8503ff48bf5SDavid du Colombier */
8513ff48bf5SDavid du Colombier {
852*593dc095SDavid du Colombier pdf_color_space_t *ppcs;
8533ff48bf5SDavid du Colombier
854*593dc095SDavid du Colombier if (code < 0 ||
855*593dc095SDavid du Colombier (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
856*593dc095SDavid du Colombier &pres, -1)) < 0
857*593dc095SDavid du Colombier ) {
8583ff48bf5SDavid du Colombier COS_FREE(pca, "pdf_color_space");
8593ff48bf5SDavid du Colombier return code;
8603ff48bf5SDavid du Colombier }
861*593dc095SDavid du Colombier pdf_reserve_object_id(pdev, pres, 0);
862*593dc095SDavid du Colombier if (res_name != NULL) {
863*593dc095SDavid du Colombier int l = min(name_length, sizeof(pres->rname) - 1);
864*593dc095SDavid du Colombier
865*593dc095SDavid du Colombier memcpy(pres->rname, res_name, l);
866*593dc095SDavid du Colombier pres->rname[l] = 0;
867*593dc095SDavid du Colombier }
868*593dc095SDavid du Colombier ppcs = (pdf_color_space_t *)pres;
869*593dc095SDavid du Colombier if (serialized == serialized0) {
870*593dc095SDavid du Colombier serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
871*593dc095SDavid du Colombier if (serialized == NULL)
872*593dc095SDavid du Colombier return_error(gs_error_VMerror);
873*593dc095SDavid du Colombier memcpy(serialized, serialized0, serialized_size);
874*593dc095SDavid du Colombier }
875*593dc095SDavid du Colombier ppcs->serialized = serialized;
876*593dc095SDavid du Colombier ppcs->serialized_size = serialized_size;
877*593dc095SDavid du Colombier if (ranges) {
878*593dc095SDavid du Colombier int num_comp = gs_color_space_num_components(pcs);
879*593dc095SDavid du Colombier gs_range_t *copy_ranges = (gs_range_t *)
880*593dc095SDavid du Colombier gs_alloc_byte_array(pdev->pdf_memory, num_comp,
881*593dc095SDavid du Colombier sizeof(gs_range_t), "pdf_color_space");
882*593dc095SDavid du Colombier
883*593dc095SDavid du Colombier if (copy_ranges == 0) {
884*593dc095SDavid du Colombier COS_FREE(pca, "pdf_color_space");
885*593dc095SDavid du Colombier return_error(gs_error_VMerror);
886*593dc095SDavid du Colombier }
887*593dc095SDavid du Colombier memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
888*593dc095SDavid du Colombier ppcs->ranges = copy_ranges;
889*593dc095SDavid du Colombier if (ppranges)
890*593dc095SDavid du Colombier *ppranges = copy_ranges;
891*593dc095SDavid du Colombier } else
892*593dc095SDavid du Colombier ppcs->ranges = 0;
8933ff48bf5SDavid du Colombier pca->id = pres->object->id;
8943ff48bf5SDavid du Colombier COS_FREE(pres->object, "pdf_color_space");
8953ff48bf5SDavid du Colombier pres->object = (cos_object_t *)pca;
8963ff48bf5SDavid du Colombier cos_write_object(COS_OBJECT(pca), pdev);
8973ff48bf5SDavid du Colombier }
898*593dc095SDavid du Colombier ret:
8993ff48bf5SDavid du Colombier if (by_name) {
9003ff48bf5SDavid du Colombier /* Return a resource name rather than an object reference. */
9013ff48bf5SDavid du Colombier discard(COS_RESOURCE_VALUE(pvalue, pca));
9023ff48bf5SDavid du Colombier } else
9033ff48bf5SDavid du Colombier discard(COS_OBJECT_VALUE(pvalue, pca));
904*593dc095SDavid du Colombier if (pres != NULL) {
905*593dc095SDavid du Colombier pres->where_used |= pdev->used_mask;
906*593dc095SDavid du Colombier code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
907*593dc095SDavid du Colombier if (code < 0)
908*593dc095SDavid du Colombier return code;
909*593dc095SDavid du Colombier }
9103ff48bf5SDavid du Colombier return 0;
9113ff48bf5SDavid du Colombier }
9123ff48bf5SDavid du Colombier
913*593dc095SDavid du Colombier 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*593dc095SDavid du Colombier pdf_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
915*593dc095SDavid du Colombier const gs_range_t **ppranges,
916*593dc095SDavid du Colombier const gs_color_space *pcs,
917*593dc095SDavid du Colombier const pdf_color_space_names_t *pcsn,
918*593dc095SDavid du Colombier bool by_name)
919*593dc095SDavid du Colombier {
920*593dc095SDavid du Colombier return pdf_color_space_named(pdev, pvalue, ppranges, pcs, pcsn, by_name, NULL, 0);
921*593dc095SDavid du Colombier }
922*593dc095SDavid du Colombier
923*593dc095SDavid du Colombier /* ---------------- Miscellaneous ---------------- */
924*593dc095SDavid du Colombier
9253ff48bf5SDavid du Colombier /* Create colored and uncolored Pattern color spaces. */
9263ff48bf5SDavid du Colombier private int
pdf_pattern_space(gx_device_pdf * pdev,cos_value_t * pvalue,pdf_resource_t ** ppres,const char * cs_name)9273ff48bf5SDavid du Colombier pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
9283ff48bf5SDavid du Colombier pdf_resource_t **ppres, const char *cs_name)
9293ff48bf5SDavid du Colombier {
930*593dc095SDavid du Colombier int code;
931*593dc095SDavid du Colombier
9323ff48bf5SDavid du Colombier if (!*ppres) {
9333ff48bf5SDavid du Colombier int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
9343ff48bf5SDavid du Colombier ppres);
9353ff48bf5SDavid du Colombier
9363ff48bf5SDavid du Colombier if (code < 0)
9373ff48bf5SDavid du Colombier return code;
9383ff48bf5SDavid du Colombier pprints1(pdev->strm, "%s\n", cs_name);
9393ff48bf5SDavid du Colombier pdf_end_resource(pdev);
9403ff48bf5SDavid du Colombier (*ppres)->object->written = true; /* don't write at end */
941*593dc095SDavid du Colombier ((pdf_color_space_t *)*ppres)->ranges = 0;
942*593dc095SDavid du Colombier ((pdf_color_space_t *)*ppres)->serialized = 0;
9433ff48bf5SDavid du Colombier }
944*593dc095SDavid du Colombier code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres);
945*593dc095SDavid du Colombier if (code < 0)
946*593dc095SDavid du Colombier return code;
9473ff48bf5SDavid du Colombier cos_resource_value(pvalue, (*ppres)->object);
9483ff48bf5SDavid du Colombier return 0;
9493ff48bf5SDavid du Colombier }
9503ff48bf5SDavid du Colombier int
pdf_cs_Pattern_colored(gx_device_pdf * pdev,cos_value_t * pvalue)9513ff48bf5SDavid du Colombier pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
9523ff48bf5SDavid du Colombier {
9533ff48bf5SDavid du Colombier return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
9543ff48bf5SDavid du Colombier "[/Pattern]");
9553ff48bf5SDavid du Colombier }
9563ff48bf5SDavid du Colombier int
pdf_cs_Pattern_uncolored(gx_device_pdf * pdev,cos_value_t * pvalue)9573ff48bf5SDavid du Colombier pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
9583ff48bf5SDavid du Colombier {
959*593dc095SDavid du Colombier /* Only for process colors. */
9603ff48bf5SDavid du Colombier int ncomp = pdev->color_info.num_components;
9613ff48bf5SDavid du Colombier static const char *const pcs_names[5] = {
9623ff48bf5SDavid du Colombier 0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
9633ff48bf5SDavid du Colombier "[/Pattern /DeviceCMYK]"
9643ff48bf5SDavid du Colombier };
9653ff48bf5SDavid du Colombier
9663ff48bf5SDavid du Colombier return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
9673ff48bf5SDavid du Colombier pcs_names[ncomp]);
9683ff48bf5SDavid du Colombier }
969*593dc095SDavid du Colombier int
pdf_cs_Pattern_uncolored_hl(gx_device_pdf * pdev,const gs_color_space * pcs,cos_value_t * pvalue)970*593dc095SDavid du Colombier pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev,
971*593dc095SDavid du Colombier const gs_color_space *pcs, cos_value_t *pvalue)
972*593dc095SDavid du Colombier {
973*593dc095SDavid du Colombier /* Only for high level colors. */
974*593dc095SDavid du Colombier return pdf_color_space(pdev, pvalue, NULL, pcs, &pdf_color_space_names, true);
975*593dc095SDavid du Colombier }
9763ff48bf5SDavid du Colombier
9773ff48bf5SDavid du Colombier /* Set the ProcSets bits corresponding to an image color space. */
9783ff48bf5SDavid du Colombier void
pdf_color_space_procsets(gx_device_pdf * pdev,const gs_color_space * pcs)9793ff48bf5SDavid du Colombier pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
9803ff48bf5SDavid du Colombier {
9813ff48bf5SDavid du Colombier const gs_color_space *pbcs = pcs;
9823ff48bf5SDavid du Colombier
9833ff48bf5SDavid du Colombier csw:
9843ff48bf5SDavid du Colombier switch (gs_color_space_get_index(pbcs)) {
9853ff48bf5SDavid du Colombier case gs_color_space_index_DeviceGray:
9863ff48bf5SDavid du Colombier case gs_color_space_index_CIEA:
9873ff48bf5SDavid du Colombier /* We only handle CIEBasedA spaces that map to CalGray. */
9883ff48bf5SDavid du Colombier pdev->procsets |= ImageB;
9893ff48bf5SDavid du Colombier break;
9903ff48bf5SDavid du Colombier case gs_color_space_index_Indexed:
9913ff48bf5SDavid du Colombier pdev->procsets |= ImageI;
9923ff48bf5SDavid du Colombier pbcs = (const gs_color_space *)&pcs->params.indexed.base_space;
9933ff48bf5SDavid du Colombier goto csw;
9943ff48bf5SDavid du Colombier default:
9953ff48bf5SDavid du Colombier pdev->procsets |= ImageC;
9963ff48bf5SDavid du Colombier break;
9973ff48bf5SDavid du Colombier }
9983ff48bf5SDavid du Colombier }
999