/src/ghostpdl/devices/vector/gdevpdfc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Color space management and writing for pdfwrite driver */ |
18 | | #include "math_.h" |
19 | | #include "memory_.h" |
20 | | #include "gx.h" |
21 | | #include "gscspace.h" /* for gscie.h */ |
22 | | #include "gscdevn.h" |
23 | | #include "gscie.h" |
24 | | #include "gscindex.h" |
25 | | #include "gscsepr.h" |
26 | | #include "stream.h" |
27 | | #include "gsicc.h" |
28 | | #include "gserrors.h" |
29 | | #include "gsfunc.h" /* required for colour space function evaluation */ |
30 | | #include "gsfunc3.h" /* Required to create a replacement linear interpolation function */ |
31 | | #include "gsfunc0.h" /* Required to create a sampled function for DeviceN alternate replacement */ |
32 | | #include "gdevpdfx.h" |
33 | | #include "gdevpdfg.h" |
34 | | #include "gdevpdfc.h" |
35 | | #include "gdevpdfo.h" |
36 | | #include "strimpl.h" |
37 | | #include "sstring.h" |
38 | | #include "gxcspace.h" |
39 | | #include "gxcdevn.h" |
40 | | #include "gscspace.h" |
41 | | #include "gsicc_manage.h" |
42 | | #include "gsicc_cache.h" |
43 | | |
44 | | /* |
45 | | * PDF doesn't have general CIEBased color spaces. However, it provides |
46 | | * two methods for handling general CIE spaces: |
47 | | * |
48 | | * - For PDF 1.2 and above, we note that the transformation from L*a*b* |
49 | | * space to XYZ space is invertible, so we can handle any PostScript |
50 | | * CIEBased space by transforming color values in that space to XYZ, |
51 | | * then inverse-transforming them to L*a*b* and using a PDF Lab space |
52 | | * with the same WhitePoint and BlackPoint and appropriate ranges for |
53 | | * a and b. This approach has the drawback that Y values outside the |
54 | | * range [0..1] can't be represented: we just clamp them. |
55 | | * |
56 | | * - For PDF 1.3 and above, we can create an ICCBased space. This is |
57 | | * actually necessary, not just an option, because for shadings (also |
58 | | * introduced in PDF 1.3), we want color interpolation to occur in the |
59 | | * original space. |
60 | | * |
61 | | * The Lab approach is not currently implemented, because it requires |
62 | | * transforming all the sample values of images. The ICCBased approach is |
63 | | * implemented for color spaces whose ranges lie within [0..1], which are |
64 | | * the only ranges supported by the ICC standard: we think that removing |
65 | | * this limitation would also require transforming image sample values. |
66 | | */ |
67 | | |
68 | | /* GC descriptors */ |
69 | | public_st_pdf_color_space(); |
70 | | |
71 | | /* ------ CIE space testing ------ */ |
72 | | |
73 | | /* Test whether a cached CIE procedure is the identity function. */ |
74 | | #define CIE_CACHE_IS_IDENTITY(pc)\ |
75 | 0 | ((pc)->floats.params.is_identity) |
76 | | #define CIE_CACHE3_IS_IDENTITY(pca)\ |
77 | 0 | (CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\ |
78 | 0 | CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\ |
79 | 0 | CIE_CACHE_IS_IDENTITY(&(pca)[2])) |
80 | | |
81 | | /* |
82 | | * Test whether a cached CIE procedure is an exponential. A cached |
83 | | * procedure is exponential iff f(x) = k*(x^p). We make a very cursory |
84 | | * check for this: we require that f(0) = 0, set k = f(1), set p = |
85 | | * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are |
86 | | * two arbitrarily chosen values between 0 and 1. Naturally all this is |
87 | | * done with some slop. |
88 | | */ |
89 | 0 | #define CC_INDEX_A (gx_cie_cache_size / 3) |
90 | 0 | #define CC_INDEX_B (gx_cie_cache_size * 2 / 3) |
91 | 0 | #define CC_INDEX_1 (gx_cie_cache_size - 1) |
92 | 0 | #define CC_KEY(i) ((i) / (double)CC_INDEX_1) |
93 | 0 | #define CC_KEY_A CC_KEY(CC_INDEX_A) |
94 | 0 | #define CC_KEY_B CC_KEY(CC_INDEX_B) |
95 | | |
96 | | static bool |
97 | | cie_values_are_exponential(double v0, double va, double vb, double k, |
98 | | float *pexpt) |
99 | 0 | { |
100 | 0 | double p; |
101 | |
|
102 | 0 | if (fabs(v0) >= 0.001 || fabs(k) < 0.001) |
103 | 0 | return false; |
104 | 0 | if (va == 0 || (va > 0) != (k > 0)) |
105 | 0 | return false; |
106 | 0 | p = log(va / k) / log(CC_KEY_A); |
107 | 0 | if (fabs(vb - k * pow(CC_KEY_B, p)) >= 0.001) |
108 | 0 | return false; |
109 | 0 | *pexpt = p; |
110 | 0 | return true; |
111 | 0 | } |
112 | | |
113 | | static bool |
114 | | cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt) |
115 | 0 | { |
116 | 0 | return cie_values_are_exponential(pc->floats.values[0], |
117 | 0 | pc->floats.values[CC_INDEX_A], |
118 | 0 | pc->floats.values[CC_INDEX_B], |
119 | 0 | pc->floats.values[CC_INDEX_1], |
120 | 0 | pexpt); |
121 | 0 | } |
122 | | #define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\ |
123 | 0 | (cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\ |
124 | 0 | cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\ |
125 | 0 | cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w)) |
126 | | |
127 | | static bool |
128 | | cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt) |
129 | 0 | { |
130 | 0 | return cie_values_are_exponential(pc->vecs.values[0].u, |
131 | 0 | pc->vecs.values[CC_INDEX_A].u, |
132 | 0 | pc->vecs.values[CC_INDEX_B].u, |
133 | 0 | pc->vecs.values[CC_INDEX_1].u, |
134 | 0 | pexpt); |
135 | 0 | } |
136 | | #define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\ |
137 | 0 | (cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\ |
138 | 0 | cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\ |
139 | 0 | cie_vector_cache_is_exponential(&(pca)[2], &(expts).w)) |
140 | | |
141 | | #undef CC_INDEX_A |
142 | | #undef CC_INDEX_B |
143 | | #undef CC_KEY_A |
144 | | #undef CC_KEY_B |
145 | | |
146 | | /* |
147 | | * Test whether a cached CIEBasedABC space consists only of a single |
148 | | * Decode step followed by a single Matrix step. |
149 | | */ |
150 | | static cie_cache_one_step_t |
151 | | cie_cached_abc_is_one_step(const gs_cie_abc *pcie, const gs_matrix3 **ppmat) |
152 | 0 | { |
153 | | /* The order of steps is, DecodeABC, MatrixABC, DecodeLMN, MatrixLMN. */ |
154 | |
|
155 | 0 | if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN)) { |
156 | 0 | if (pcie->MatrixABC.is_identity) { |
157 | 0 | *ppmat = &pcie->common.MatrixLMN; |
158 | 0 | return ONE_STEP_ABC; |
159 | 0 | } |
160 | 0 | if (pcie->common.MatrixLMN.is_identity) { |
161 | 0 | *ppmat = &pcie->MatrixABC; |
162 | 0 | return ONE_STEP_ABC; |
163 | 0 | } |
164 | 0 | } |
165 | 0 | if (CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC.caches)) { |
166 | 0 | if (pcie->MatrixABC.is_identity) { |
167 | 0 | *ppmat = &pcie->common.MatrixLMN; |
168 | 0 | return ONE_STEP_LMN; |
169 | 0 | } |
170 | 0 | } |
171 | 0 | return ONE_STEP_NOT; |
172 | 0 | } |
173 | | |
174 | | /* |
175 | | * Test whether a cached CIEBasedABC space is a L*a*b* space. |
176 | | */ |
177 | | static bool |
178 | | cie_scalar_cache_is_lab_lmn(const gs_cie_abc *pcie, int i) |
179 | 0 | { |
180 | 0 | double k = CC_KEY(i); |
181 | 0 | double g = (k >= 6.0 / 29 ? k * k * k : |
182 | 0 | (k - 4.0 / 29) * (108.0 / 841)); |
183 | |
|
184 | 0 | #define CC_V(j,i) (pcie->common.caches.DecodeLMN[j].floats.values[i]) |
185 | 0 | #define CC_WP(uvw) (pcie->common.points.WhitePoint.uvw) |
186 | |
|
187 | 0 | return (fabs(CC_V(0, i) - g * CC_WP(u)) < 0.001 && |
188 | 0 | fabs(CC_V(1, i) - g * CC_WP(v)) < 0.001 && |
189 | 0 | fabs(CC_V(2, i) - g * CC_WP(w)) < 0.001 |
190 | 0 | ); |
191 | |
|
192 | 0 | #undef CC_V |
193 | 0 | #undef CC_WP |
194 | 0 | } |
195 | | static bool |
196 | | cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t *pvc, int i) |
197 | 0 | { |
198 | 0 | const gx_cie_vector_cache *const pc3 = pvc->caches; |
199 | 0 | double k = CC_KEY(i); |
200 | 0 | double l0 = pc3[0].vecs.params.base, |
201 | 0 | l = l0 + k * (pc3[0].vecs.params.limit - l0); |
202 | 0 | double a0 = pc3[1].vecs.params.base, |
203 | 0 | a = a0 + k * (pc3[1].vecs.params.limit - a0); |
204 | 0 | double b0 = pc3[2].vecs.params.base, |
205 | 0 | b = b0 + k * (pc3[2].vecs.params.limit - b0); |
206 | |
|
207 | 0 | return (fabs(cie_cached2float(pc3[0].vecs.values[i].u) - |
208 | 0 | (l + 16) / 116) < 0.001 && |
209 | 0 | fabs(cie_cached2float(pc3[1].vecs.values[i].u) - |
210 | 0 | a / 500) < 0.001 && |
211 | 0 | fabs(cie_cached2float(pc3[2].vecs.values[i].w) - |
212 | 0 | b / -200) < 0.001 |
213 | 0 | ); |
214 | 0 | } |
215 | | |
216 | | static bool |
217 | | cie_is_lab(const gs_cie_abc *pcie) |
218 | 0 | { |
219 | 0 | int i; |
220 | | |
221 | | /* Check MatrixABC and MatrixLMN. */ |
222 | 0 | if (!(pcie->MatrixABC.cu.u == 1 && pcie->MatrixABC.cu.v == 1 && |
223 | 0 | pcie->MatrixABC.cu.w == 1 && |
224 | 0 | pcie->MatrixABC.cv.u == 1 && pcie->MatrixABC.cv.v == 0 && |
225 | 0 | pcie->MatrixABC.cv.w == 0 && |
226 | 0 | pcie->MatrixABC.cw.u == 0 && pcie->MatrixABC.cw.v == 0 && |
227 | 0 | pcie->MatrixABC.cw.w == -1 && |
228 | 0 | pcie->common.MatrixLMN.is_identity |
229 | 0 | )) |
230 | 0 | return false; |
231 | | |
232 | | /* Check DecodeABC and DecodeLMN. */ |
233 | 0 | for (i = 0; i <= CC_INDEX_1; ++i) |
234 | 0 | if (!(cie_vector_cache_is_lab_abc(&pcie->caches.DecodeABC, i) && |
235 | 0 | cie_scalar_cache_is_lab_lmn(pcie, i) |
236 | 0 | )) |
237 | 0 | return false; |
238 | | |
239 | 0 | return true; |
240 | 0 | } |
241 | | |
242 | | #undef CC_INDEX_1 |
243 | | #undef CC_KEY |
244 | | |
245 | | /* Test whether one or more CIE-based ranges are [0..1]. */ |
246 | | static bool |
247 | | cie_ranges_are_0_1(const gs_range *prange, int n) |
248 | 0 | { |
249 | 0 | int i; |
250 | |
|
251 | 0 | for (i = 0; i < n; ++i) |
252 | 0 | if (prange[i].rmin != 0 || prange[i].rmax != 1) |
253 | 0 | return false; |
254 | 0 | return true; |
255 | 0 | } |
256 | | |
257 | | /* ------ Utilities ------ */ |
258 | | |
259 | | /* Add a 3-element vector to a Cos array or dictionary. */ |
260 | | static int |
261 | | cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec) |
262 | 0 | { |
263 | 0 | int code = cos_array_add_real(pca, pvec->u); |
264 | |
|
265 | 0 | if (code >= 0) |
266 | 0 | code = cos_array_add_real(pca, pvec->v); |
267 | 0 | if (code >= 0) |
268 | 0 | code = cos_array_add_real(pca, pvec->w); |
269 | 0 | return code; |
270 | 0 | } |
271 | | static int |
272 | | cos_dict_put_c_key_vector3(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, |
273 | | const gs_vector3 *pvec) |
274 | 0 | { |
275 | 0 | cos_array_t *pca = cos_array_alloc(pdev, "cos_array_from_vector3"); |
276 | 0 | int code; |
277 | |
|
278 | 0 | if (pca == 0) |
279 | 0 | return_error(gs_error_VMerror); |
280 | 0 | code = cos_array_add_vector3(pca, pvec); |
281 | 0 | if (code < 0) { |
282 | 0 | COS_FREE(pca, "cos_array_from_vector3"); |
283 | 0 | return code; |
284 | 0 | } |
285 | 0 | return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca)); |
286 | 0 | } |
287 | | |
288 | | /* |
289 | | * Finish creating a CIE-based color space (Calxxx or Lab.) |
290 | | * This procedure is exported for gdevpdfk.c. |
291 | | */ |
292 | | int |
293 | | pdf_finish_cie_space(gx_device_pdf *pdev, cos_array_t *pca, cos_dict_t *pcd, |
294 | | const gs_cie_common *pciec) |
295 | 0 | { |
296 | 0 | int code = cos_dict_put_c_key_vector3(pdev, pcd, "/WhitePoint", |
297 | 0 | &pciec->points.WhitePoint); |
298 | |
|
299 | 0 | if (code < 0) |
300 | 0 | return code; |
301 | 0 | if (pciec->points.BlackPoint.u != 0 || |
302 | 0 | pciec->points.BlackPoint.v != 0 || |
303 | 0 | pciec->points.BlackPoint.w != 0 |
304 | 0 | ) { |
305 | 0 | code = cos_dict_put_c_key_vector3(pdev, pcd, "/BlackPoint", |
306 | 0 | &pciec->points.BlackPoint); |
307 | 0 | if (code < 0) |
308 | 0 | return code; |
309 | 0 | } |
310 | 0 | return cos_array_add_object(pca, COS_OBJECT(pcd)); |
311 | 0 | } |
312 | | |
313 | | /* ------ Color space writing ------ */ |
314 | | |
315 | | /* Define standard and short color space names. */ |
316 | | const pdf_color_space_names_t pdf_color_space_names = { |
317 | | PDF_COLOR_SPACE_NAMES |
318 | | }; |
319 | | const pdf_color_space_names_t pdf_color_space_names_short = { |
320 | | PDF_COLOR_SPACE_NAMES_SHORT |
321 | | }; |
322 | | |
323 | | /* |
324 | | * Create a local Device{Gray,RGB,CMYK} color space corresponding to the |
325 | | * given number of components. |
326 | | */ |
327 | | int |
328 | | pdf_cspace_init_Device(gs_memory_t *mem, gs_color_space **ppcs, |
329 | | int num_components) |
330 | 8.40k | { |
331 | 8.40k | switch (num_components) { |
332 | 0 | case 1: *ppcs = gs_cspace_new_DeviceGray(mem); break; |
333 | 8.40k | case 3: *ppcs = gs_cspace_new_DeviceRGB(mem); break; |
334 | 0 | case 4: *ppcs = gs_cspace_new_DeviceCMYK(mem); break; |
335 | 0 | default: return_error(gs_error_rangecheck); |
336 | 8.40k | } |
337 | | |
338 | 8.40k | if (*ppcs == NULL) |
339 | 0 | return_error(gs_error_VMerror); |
340 | | |
341 | 8.40k | return 0; |
342 | 8.40k | } |
343 | | |
344 | | int pdf_delete_sampled_base_space_function(gx_device_pdf *pdev, gs_function_t *pfn) |
345 | 0 | { |
346 | 0 | gs_function_Sd_params_t *params = (gs_function_Sd_params_t *)&pfn->params; |
347 | |
|
348 | 0 | gs_free_object(pdev->memory, (void *)params->Domain, "pdf_delete_function"); |
349 | 0 | gs_free_object(pdev->memory, (void *)params->Range, "pdf_delete_function"); |
350 | 0 | gs_free_string(pdev->memory, (void *)params->DataSource.data.str.data, params->DataSource.data.str.size, "pdf_dselete_function"); |
351 | 0 | gs_free_object(pdev->memory, (void *)pfn, "pdf_delete_function"); |
352 | 0 | return 0; |
353 | 0 | } |
354 | | |
355 | | int pdf_delete_base_space_function(gx_device_pdf *pdev, gs_function_t *pfn) |
356 | 0 | { |
357 | 0 | gs_function_ElIn_params_t *params = (gs_function_ElIn_params_t *)&pfn->params; |
358 | |
|
359 | 0 | gs_free_object(pdev->memory, (void *)params->Domain, "pdf_delete_function"); |
360 | 0 | gs_free_object(pdev->memory, (void *)params->Range, "pdf_delete_function"); |
361 | 0 | gs_free_object(pdev->memory, (void *)params->C0, "pdf_delete_function"); |
362 | 0 | gs_free_object(pdev->memory, (void *)params->C1, "pdf_delete_function"); |
363 | 0 | gs_free_object(pdev->memory, (void *)pfn, "pdf_delete_function"); |
364 | 0 | return 0; |
365 | 0 | } |
366 | | |
367 | | int pdf_make_sampled_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn, |
368 | | int nSrcComp, int nDstComp, byte *data) |
369 | 0 | { |
370 | 0 | gs_function_Sd_params_t params; |
371 | 0 | void *ptr1, *ptr2; |
372 | 0 | int i, code; |
373 | 0 | gs_const_string str; |
374 | |
|
375 | 0 | str.size = nDstComp * (uint)pow(2, nSrcComp); |
376 | 0 | str.data = gs_alloc_string(pdev->memory, str.size, "pdf_DeviceN"); |
377 | 0 | if (str.data == NULL) |
378 | 0 | return_error(gs_error_VMerror); |
379 | 0 | memcpy((void *)str.data, data, str.size); |
380 | |
|
381 | 0 | params.m = nSrcComp; |
382 | 0 | params.n = nDstComp; |
383 | 0 | params.Order = 1; |
384 | 0 | params.BitsPerSample = 8; |
385 | |
|
386 | 0 | ptr1 = gs_alloc_byte_array(pdev->memory, nSrcComp, sizeof(int), "pdf_make_function(Domain)"); |
387 | 0 | if (ptr1 == NULL) |
388 | 0 | return gs_note_error(gs_error_VMerror); |
389 | | |
390 | 0 | for (i=0;i<nSrcComp;i++) { |
391 | 0 | ((int *)ptr1)[i] = 2; |
392 | 0 | } |
393 | 0 | params.Size = (const int *)ptr1; |
394 | |
|
395 | 0 | ptr1 = (float *) |
396 | 0 | gs_alloc_byte_array(pdev->memory, 2 * nSrcComp, sizeof(float), "pdf_make_function(Domain)"); |
397 | 0 | if (ptr1 == 0) { |
398 | 0 | return gs_note_error(gs_error_VMerror); |
399 | 0 | } |
400 | 0 | ptr2 = (float *) |
401 | 0 | gs_alloc_byte_array(pdev->memory, 2 * nDstComp, sizeof(float), "pdf_make_function(Range)"); |
402 | 0 | if (ptr2 == 0) { |
403 | 0 | gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)"); |
404 | 0 | return gs_note_error(gs_error_VMerror); |
405 | 0 | } |
406 | 0 | for (i=0;i<nSrcComp;i++) { |
407 | 0 | ((float *)ptr1)[i*2] = 0.0f; |
408 | 0 | ((float *)ptr1)[(i*2) + 1] = 1.0f; |
409 | 0 | } |
410 | 0 | for (i=0;i<nDstComp;i++) { |
411 | 0 | ((float *)ptr2)[i*2] = 0.0f; |
412 | 0 | ((float *)ptr2)[(i*2) + 1] = 1.0f; |
413 | 0 | } |
414 | 0 | params.Domain = ptr1; |
415 | 0 | params.Range = ptr2; |
416 | 0 | params.Encode = params.Decode = NULL; |
417 | 0 | data_source_init_string(¶ms.DataSource, str); |
418 | |
|
419 | 0 | code = gs_function_Sd_init(pfn, ¶ms, pdev->memory); |
420 | 0 | return code; |
421 | 0 | } |
422 | | |
423 | | int pdf_make_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn, |
424 | | int ncomp, float *data_low, float *data_high) |
425 | 0 | { |
426 | 0 | gs_function_ElIn_params_t params; |
427 | 0 | float *ptr1, *ptr2; |
428 | 0 | int i, code; |
429 | |
|
430 | 0 | ptr1 = (float *) |
431 | 0 | gs_alloc_byte_array(pdev->memory, 2, sizeof(float), "pdf_make_function(Domain)"); |
432 | 0 | if (ptr1 == 0) { |
433 | 0 | return gs_note_error(gs_error_VMerror); |
434 | 0 | } |
435 | 0 | ptr2 = (float *) |
436 | 0 | gs_alloc_byte_array(pdev->memory, 2 * ncomp, sizeof(float), "pdf_make_function(Range)"); |
437 | 0 | if (ptr2 == 0) { |
438 | 0 | gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)"); |
439 | 0 | return gs_note_error(gs_error_VMerror); |
440 | 0 | } |
441 | 0 | params.m = 1; |
442 | 0 | params.n = ncomp; |
443 | 0 | params.N = 1.0f; |
444 | 0 | ptr1[0] = 0.0f; |
445 | 0 | ptr1[1] = 1.0f; |
446 | 0 | for (i=0;i<ncomp;i++) { |
447 | 0 | ptr2[i*2] = 0.0f; |
448 | 0 | ptr2[(i*2) + 1] = 1.0f; |
449 | 0 | } |
450 | 0 | params.Domain = ptr1; |
451 | 0 | params.Range = ptr2; |
452 | |
|
453 | 0 | ptr1 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C0)"); |
454 | 0 | if (ptr1 == 0) { |
455 | 0 | gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C0)"); |
456 | 0 | gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C0)"); |
457 | 0 | return gs_note_error(gs_error_VMerror); |
458 | 0 | } |
459 | 0 | ptr2 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C1)"); |
460 | 0 | if (ptr2 == 0) { |
461 | 0 | gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C1)"); |
462 | 0 | gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C1)"); |
463 | 0 | gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(C1)"); |
464 | 0 | return gs_note_error(gs_error_VMerror); |
465 | 0 | } |
466 | | |
467 | 0 | for (i=0;i<ncomp;i++) { |
468 | 0 | ptr1[i] = data_low[i]; |
469 | 0 | ptr2[i] = data_high[i]; |
470 | 0 | } |
471 | 0 | params.C0 = ptr1; |
472 | 0 | params.C1 = ptr2; |
473 | 0 | code = gs_function_ElIn_init(pfn, ¶ms, pdev->memory); |
474 | 0 | if (code < 0) { |
475 | 0 | gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function"); |
476 | 0 | gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function"); |
477 | 0 | gs_free_object(pdev->memory, (void *)params.C0, "pdf_make_function"); |
478 | 0 | gs_free_object(pdev->memory, (void *)params.C1, "pdf_make_function"); |
479 | 0 | } |
480 | 0 | return code; |
481 | 0 | } |
482 | | |
483 | | /* Create a Separation or DeviceN color space (internal). */ |
484 | | static int |
485 | | pdf_separation_color_space(gx_device_pdf *pdev, const gs_gstate * pgs, |
486 | | cos_array_t *pca, const char *csname, |
487 | | const cos_value_t *snames, |
488 | | const gs_color_space *alt_space, |
489 | | const gs_function_t *pfn, |
490 | | const pdf_color_space_names_t *pcsn, |
491 | | const cos_value_t *v_attributes) |
492 | 954 | { |
493 | 954 | cos_value_t v; |
494 | 954 | const gs_range_t *ranges; |
495 | 954 | int code, csi; |
496 | | |
497 | | /* We need to think about the alternate space. If we are producing |
498 | | * PDF/X or PDF/A we can't produce some device spaces, and the code in |
499 | | * pdf_color_space_named always allows device spaces. We could alter |
500 | | * that code, but by then we don't know its an Alternate space, and have |
501 | | * lost the tin transform procedure. So instead we check here. |
502 | | */ |
503 | 954 | csi = gs_color_space_get_index(alt_space); |
504 | | /* Note that if csi is ICC, check to see if this was one of |
505 | | the default substitutes that we introduced for DeviceGray, |
506 | | DeviceRGB or DeviceCMYK. If it is, then just write |
507 | | the default color. Depending upon the flavor of PDF, |
508 | | or other options, we may want to actually have all |
509 | | the colors defined by ICC profiles and not do the following |
510 | | substituion of the Device space. */ |
511 | 954 | if (csi == gs_color_space_index_ICC) { |
512 | 954 | csi = gsicc_get_default_type(alt_space->cmm_icc_profile_data); |
513 | 954 | } |
514 | 954 | if (csi == gs_color_space_index_DeviceRGB && ((pdev->PDFX > 0 && pdev->PDFX < 4) || |
515 | 112 | (pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceCMYK)))) { |
516 | | |
517 | | /* |
518 | | * We shouldn't get here. If someoone is using PDF/X or PDF/A then they should *also* |
519 | | * set ColorConversionStrategy, and any Separation or DeviceN space should have been |
520 | | * converted earlier. If we somehow do get here (eg user set PDFA but *ddin't* set |
521 | | * ColorConversionStrategy) then return a rangecheck error. Earlier code will then |
522 | | * fall back to writing a device space. |
523 | | */ |
524 | 0 | dmprintf(pdev->pdf_memory, "Attempting to write a DeviceN space with an inappropriate alternate,\nhave you set ColorConversionStrategy ?\n"); |
525 | 0 | return gs_error_rangecheck; |
526 | 0 | } |
527 | 954 | if (csi == gs_color_space_index_DeviceCMYK && |
528 | 954 | (pdev->PDFA != 0 && (pdev->pcm_color_info_index == gs_color_space_index_DeviceRGB))) { |
529 | |
|
530 | 0 | dmprintf(pdev->pdf_memory, "Attempting to write a DeviceN space with an inappropriate alternate,\nhave you set ColorConversionStrategy ?\n"); |
531 | 0 | return gs_error_rangecheck; |
532 | 0 | } |
533 | | |
534 | 954 | if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 || |
535 | 954 | (code = cos_array_add(pca, snames)) < 0 || |
536 | 954 | (code = pdf_color_space_named(pdev, pgs, &v, &ranges, alt_space, pcsn, false, NULL, 0, false)) < 0 || |
537 | 954 | (code = cos_array_add(pca, &v)) < 0 || |
538 | 954 | (code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 || |
539 | 954 | (code = cos_array_add(pca, &v)) < 0 || |
540 | 954 | (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0 |
541 | 954 | ) |
542 | 0 | return code; |
543 | 954 | return 0; |
544 | 954 | } |
545 | | |
546 | | /* |
547 | | * Create an Indexed color space. This is a single-use procedure, |
548 | | * broken out only for readability. |
549 | | */ |
550 | | int |
551 | | pdf_indexed_color_space(gx_device_pdf *pdev, const gs_gstate * pgs, cos_value_t *pvalue, |
552 | | const gs_color_space *pcs, cos_array_t *pca, cos_value_t *cos_base) |
553 | 724 | { |
554 | 724 | const gs_indexed_params *pip = &pcs->params.indexed; |
555 | 724 | const gs_color_space *base_space = pcs->base_space; |
556 | 724 | int num_entries = pip->hival + 1; |
557 | 724 | int num_components = gs_color_space_num_components(base_space); |
558 | 724 | uint table_size = num_entries * num_components; |
559 | | /* Guess at the extra space needed for PS string encoding. */ |
560 | 724 | uint string_size = 2 + table_size * 4; |
561 | 724 | uint string_used; |
562 | 724 | byte buf[100]; /* arbitrary */ |
563 | 724 | stream_AXE_state st; |
564 | 724 | stream s, es; |
565 | 724 | gs_memory_t *mem = pdev->pdf_memory; |
566 | 724 | byte *table; |
567 | 724 | byte *palette; |
568 | 724 | cos_value_t v; |
569 | 724 | int code; |
570 | | |
571 | | /* PDF doesn't support Indexed color spaces with more than 256 entries. */ |
572 | 724 | if (num_entries > 256) |
573 | 0 | return_error(gs_error_rangecheck); |
574 | 724 | if (pdev->CompatibilityLevel < 1.3 && !pdev->ForOPDFRead) { |
575 | 0 | switch (gs_color_space_get_index(pcs)) { |
576 | 0 | case gs_color_space_index_Pattern: |
577 | 0 | case gs_color_space_index_Separation: |
578 | 0 | case gs_color_space_index_Indexed: |
579 | 0 | case gs_color_space_index_DeviceN: |
580 | 0 | return_error(gs_error_rangecheck); |
581 | 0 | default: DO_NOTHING; |
582 | 0 | } |
583 | |
|
584 | 0 | } |
585 | 724 | table = gs_alloc_string(mem, string_size, "pdf_color_space(table)"); |
586 | 724 | palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)"); |
587 | 724 | if (table == 0 || palette == 0) { |
588 | 0 | gs_free_string(mem, palette, table_size, |
589 | 0 | "pdf_color_space(palette)"); |
590 | 0 | gs_free_string(mem, table, string_size, |
591 | 0 | "pdf_color_space(table)"); |
592 | 0 | return_error(gs_error_VMerror); |
593 | 0 | } |
594 | 724 | s_init(&s, mem); |
595 | 724 | swrite_string(&s, table, string_size); |
596 | 724 | s_init(&es, mem); |
597 | 724 | s_init_state((stream_state *)&st, &s_PSSE_template, NULL); |
598 | 724 | s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s); |
599 | 724 | sputc(&s, '('); |
600 | 724 | if (pcs->params.indexed.use_proc) { |
601 | 0 | gs_client_color cmin, cmax; |
602 | 0 | byte *pnext = palette; |
603 | 0 | int i, j; |
604 | | |
605 | | /* Find the legal range for the color components. */ |
606 | 0 | for (j = 0; j < num_components; ++j) |
607 | 0 | cmin.paint.values[j] = (float)min_long, |
608 | 0 | cmax.paint.values[j] = (float)max_long; |
609 | 0 | gs_color_space_restrict_color(&cmin, base_space); |
610 | 0 | gs_color_space_restrict_color(&cmax, base_space); |
611 | | /* |
612 | | * Compute the palette values, with the legal range for each |
613 | | * one mapped to [0 .. 255]. |
614 | | */ |
615 | 0 | for (i = 0; i < num_entries; ++i) { |
616 | 0 | gs_client_color cc; |
617 | |
|
618 | 0 | gs_cspace_indexed_lookup(pcs, i, &cc); |
619 | 0 | for (j = 0; j < num_components; ++j) { |
620 | 0 | float v = (cc.paint.values[j] - cmin.paint.values[j]) |
621 | 0 | * 255 / (cmax.paint.values[j] - cmin.paint.values[j]); |
622 | |
|
623 | 0 | *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v); |
624 | 0 | } |
625 | 0 | } |
626 | 0 | } else |
627 | 724 | memcpy(palette, pip->lookup.table.data, table_size); |
628 | 724 | if (gs_color_space_get_index(base_space) == |
629 | 724 | gs_color_space_index_DeviceRGB |
630 | 724 | ) { |
631 | | /* Check for an all-gray palette3. */ |
632 | 0 | int i; |
633 | |
|
634 | 0 | for (i = table_size; (i -= 3) >= 0; ) |
635 | 0 | if (palette[i] != palette[i + 1] || |
636 | 0 | palette[i] != palette[i + 2] |
637 | 0 | ) |
638 | 0 | break; |
639 | 0 | if (i < 0) { |
640 | | /* Change the color space to DeviceGray. */ |
641 | 0 | for (i = 0; i < num_entries; ++i) |
642 | 0 | palette[i] = palette[i * 3]; |
643 | 0 | table_size = num_entries; |
644 | 0 | base_space = gs_cspace_new_DeviceGray(mem); |
645 | 0 | if (base_space == NULL) |
646 | 0 | return_error(gs_error_VMerror); |
647 | 0 | } |
648 | 0 | } |
649 | 724 | stream_write(&es, palette, table_size); |
650 | 724 | gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); |
651 | | /* Another case where we use sclose() and not sclose_filters(), because the |
652 | | * buffer we supplied to s_init_filter is a heap based C object, so we |
653 | | * must not free it. |
654 | | */ |
655 | 724 | sclose(&es); |
656 | 724 | sflush(&s); |
657 | 724 | string_used = (uint)stell(&s); |
658 | 724 | table = gs_resize_string(mem, table, string_size, string_used, |
659 | 724 | "pdf_color_space(table)"); |
660 | | /* |
661 | | * Since the array is always referenced by name as a resource |
662 | | * rather than being written as a value, even for in-line images, |
663 | | * always use the full name for the color space. |
664 | | * |
665 | | * We don't have to worry about the range of the base space: |
666 | | * in PDF, unlike PostScript, the values from the lookup table are |
667 | | * scaled automatically. |
668 | | */ |
669 | 724 | if (cos_base == NULL) { |
670 | 724 | if ((code = pdf_color_space_named(pdev, pgs, pvalue, NULL, base_space, |
671 | 724 | &pdf_color_space_names, false, NULL, 0, false)) < 0 || |
672 | 724 | (code = cos_array_add(pca, |
673 | 724 | cos_c_string_value(&v, |
674 | 724 | pdf_color_space_names.Indexed |
675 | 724 | /*pcsn->Indexed*/))) < 0 || |
676 | 724 | (code = cos_array_add(pca, pvalue)) < 0 || |
677 | 724 | (code = cos_array_add_int(pca, pip->hival)) < 0 || |
678 | 724 | (code = cos_array_add_no_copy(pca, |
679 | 724 | cos_string_value(&v, table, |
680 | 724 | string_used))) < 0 |
681 | 724 | ) |
682 | 0 | return code; |
683 | 724 | } else { |
684 | 0 | code = cos_array_add(pca, cos_c_string_value(&v, pdf_color_space_names.Indexed)); |
685 | 0 | if (code < 0) |
686 | 0 | return code; |
687 | 0 | code = cos_array_add(pca, cos_base); |
688 | 0 | if (code < 0) |
689 | 0 | return code; |
690 | 0 | code = cos_array_add_int(pca, pip->hival); |
691 | 0 | if (code < 0) |
692 | 0 | return code; |
693 | 0 | code = cos_array_add_no_copy(pca, cos_string_value(&v, table, string_used)); |
694 | 0 | if (code < 0) |
695 | 0 | return code; |
696 | 0 | } |
697 | 724 | return 0; |
698 | 724 | } |
699 | | |
700 | | /* |
701 | | * Find a color space resource by seriialized data. |
702 | | */ |
703 | | static pdf_resource_t * |
704 | | pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size) |
705 | 35.9k | { |
706 | 35.9k | pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains; |
707 | 35.9k | pdf_resource_t *pres; |
708 | 35.9k | int i; |
709 | | |
710 | 309k | for (i = 0; i < NUM_RESOURCE_CHAINS; i++) { |
711 | 336k | for (pres = pchain[i]; pres != 0; pres = pres->next) { |
712 | 62.5k | const pdf_color_space_t *const ppcs = |
713 | 62.5k | (const pdf_color_space_t *)pres; |
714 | 62.5k | if (ppcs->serialized_size != serialized_size) |
715 | 25.0k | continue; |
716 | 37.5k | if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size)) |
717 | 32.6k | return pres; |
718 | 37.5k | } |
719 | 306k | } |
720 | 3.22k | return NULL; |
721 | 35.9k | } |
722 | | |
723 | | int pdf_convert_ICC(gx_device_pdf *pdev, |
724 | | const gs_color_space *pcs, cos_value_t *pvalue, |
725 | | const pdf_color_space_names_t *pcsn) |
726 | 0 | { |
727 | 0 | gs_color_space_index csi; |
728 | 0 | int code; |
729 | |
|
730 | 0 | csi = gs_color_space_get_index(pcs); |
731 | 0 | if (csi == gs_color_space_index_ICC) { |
732 | 0 | csi = gsicc_get_default_type(pcs->cmm_icc_profile_data); |
733 | 0 | } |
734 | 0 | if (csi == gs_color_space_index_Indexed) { |
735 | 0 | pcs = pcs->base_space; |
736 | 0 | csi = gs_color_space_get_index(pcs); |
737 | 0 | } |
738 | 0 | if (csi == gs_color_space_index_ICC) { |
739 | 0 | if (pcs->cmm_icc_profile_data == NULL || |
740 | 0 | pdev->CompatibilityLevel < 1.3 |
741 | 0 | ) { |
742 | 0 | if (pcs->base_space != NULL) { |
743 | 0 | return 0; |
744 | 0 | } else { |
745 | 0 | int num_des_comps; |
746 | 0 | cmm_dev_profile_t *dev_profile; |
747 | | |
748 | | /* determine number of components in device space */ |
749 | 0 | code = dev_proc((gx_device *)pdev, get_profile)((gx_device *)pdev, &dev_profile); |
750 | 0 | if (code < 0) |
751 | 0 | return code; |
752 | | |
753 | 0 | num_des_comps = gsicc_get_device_profile_comps(dev_profile); |
754 | | /* Set image color space to be device space */ |
755 | 0 | switch( num_des_comps ) { |
756 | 0 | case 1: |
757 | 0 | cos_c_string_value(pvalue, pcsn->DeviceGray); |
758 | | /* negative return means we do conversion */ |
759 | 0 | return -1; |
760 | 0 | case 3: |
761 | 0 | cos_c_string_value(pvalue, pcsn->DeviceRGB); |
762 | 0 | return -1; |
763 | 0 | case 4: |
764 | 0 | cos_c_string_value(pvalue, pcsn->DeviceCMYK); |
765 | 0 | return -1; |
766 | 0 | default: |
767 | 0 | break; |
768 | 0 | } |
769 | 0 | } |
770 | 0 | } |
771 | 0 | } |
772 | 0 | return 0; |
773 | 0 | } |
774 | | |
775 | | /* |
776 | | * Create a PDF color space corresponding to a PostScript color space. |
777 | | * For parameterless color spaces, set *pvalue to a (literal) string with |
778 | | * the color space name; for other color spaces, create a cos_array_t if |
779 | | * necessary and set *pvalue to refer to it. In the latter case, if |
780 | | * by_name is true, return a string /Rxxxx rather than a reference to |
781 | | * the actual object. |
782 | | * |
783 | | * If ppranges is not NULL, then if the domain of the color space had |
784 | | * to be scaled (to convert a CIEBased space to ICCBased), store a pointer |
785 | | * to the ranges in *ppranges, otherwise set *ppranges to 0. |
786 | | */ |
787 | | int |
788 | | pdf_color_space_named(gx_device_pdf *pdev, const gs_gstate * pgs, |
789 | | cos_value_t *pvalue, |
790 | | const gs_range_t **ppranges, |
791 | | const gs_color_space *pcs_in, |
792 | | const pdf_color_space_names_t *pcsn, |
793 | | bool by_name, const byte *res_name, int name_length, bool keepICC) |
794 | 64.7k | { |
795 | 64.7k | const gs_color_space *pcs = pcs_in; |
796 | 64.7k | gs_color_space_index csi; |
797 | 64.7k | cos_array_t *pca; |
798 | 64.7k | cos_dict_t *pcd; |
799 | 64.7k | cos_value_t v; |
800 | 64.7k | const gs_cie_common *pciec; |
801 | 64.7k | gs_function_t *pfn; |
802 | 64.7k | const gs_range_t *ranges = 0; |
803 | 64.7k | uint serialized_size = 0; |
804 | 64.7k | byte *serialized = NULL, serialized0[100]; |
805 | 64.7k | pdf_resource_t *pres = NULL; |
806 | 64.7k | int code; |
807 | 64.7k | bool is_lab = false; |
808 | | |
809 | 64.7k | csi = gs_color_space_get_index(pcs); |
810 | | /* Note that if csi is ICC, check to see if this was one of |
811 | | the default substitutes that we introduced for DeviceGray, |
812 | | DeviceRGB or DeviceCMYK. If it is, then just write |
813 | | the default color. Depending upon the flavor of PDF, |
814 | | or other options, we may want to actually have all |
815 | | the colors defined by ICC profiles and not do the following |
816 | | substituion of the Device space. */ |
817 | 64.7k | if (csi == gs_color_space_index_ICC && !keepICC) { |
818 | 22.2k | csi = gsicc_get_default_type(pcs->cmm_icc_profile_data); |
819 | 22.2k | } |
820 | 64.7k | if (ppranges) |
821 | 54.8k | *ppranges = 0; /* default */ |
822 | 64.7k | switch (csi) { |
823 | 4.01k | case gs_color_space_index_DeviceGray: |
824 | 4.01k | cos_c_string_value(pvalue, pcsn->DeviceGray); |
825 | 4.01k | return 0; |
826 | 19.2k | case gs_color_space_index_DeviceRGB: |
827 | 19.2k | cos_c_string_value(pvalue, pcsn->DeviceRGB); |
828 | 19.2k | return 0; |
829 | 1.11k | case gs_color_space_index_DeviceCMYK: |
830 | 1.11k | cos_c_string_value(pvalue, pcsn->DeviceCMYK); |
831 | 1.11k | return 0; |
832 | 92 | case gs_color_space_index_Pattern: |
833 | 92 | if (!pcs->params.pattern.has_base_space) { |
834 | 0 | cos_c_string_value(pvalue, "/Pattern"); |
835 | 0 | return 0; |
836 | 0 | } |
837 | 92 | break; |
838 | 10.9k | case gs_color_space_index_ICC: |
839 | | /* |
840 | | * Take a special early exit for unrecognized ICCBased color spaces, |
841 | | * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3). |
842 | | */ |
843 | | |
844 | 10.9k | if (pcs->cmm_icc_profile_data == NULL || |
845 | 10.9k | pdev->CompatibilityLevel < 1.3 |
846 | 10.9k | ) { |
847 | 104 | if (res_name != NULL) |
848 | 0 | return 0; /* Ignore .includecolorspace */ |
849 | 104 | if (pcs->base_space != NULL) { |
850 | 0 | return pdf_color_space_named( pdev, pgs, pvalue, ppranges, |
851 | 0 | pcs->base_space, |
852 | 0 | pcsn, by_name, NULL, 0, keepICC); |
853 | 104 | } else { |
854 | 104 | switch( cs_num_components(pcs) ) { |
855 | 0 | case 1: |
856 | 0 | cos_c_string_value(pvalue, pcsn->DeviceGray); |
857 | 0 | return 0; |
858 | 104 | case 3: |
859 | 104 | cos_c_string_value(pvalue, pcsn->DeviceRGB); |
860 | 104 | return 0; |
861 | 0 | case 4: |
862 | 0 | cos_c_string_value(pvalue, pcsn->DeviceCMYK); |
863 | 0 | return 0; |
864 | 0 | default: |
865 | 0 | break; |
866 | 104 | } |
867 | 104 | } |
868 | 104 | } |
869 | | |
870 | 10.7k | break; |
871 | 29.3k | default: |
872 | 29.3k | break; |
873 | 64.7k | } |
874 | | /* Check whether we already have a PDF object for this color space. */ |
875 | 40.1k | if (pcs->id != gs_no_id) |
876 | 40.1k | pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id); |
877 | 40.1k | if (pres == NULL) { |
878 | 35.9k | stream s; |
879 | | |
880 | 35.9k | s_init(&s, pdev->memory); |
881 | 35.9k | swrite_position_only(&s); |
882 | 35.9k | code = cs_serialize(pcs, &s); |
883 | 35.9k | if (code < 0) |
884 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
885 | 35.9k | serialized_size = stell(&s); |
886 | | /* I think this is another case where we use sclose() and not sclose_filters(). |
887 | | * It seems like we don't actually write anything, but it allows us to find the |
888 | | * length of the serialised data. No buffer hre, so we must no call |
889 | | * s_close_filters() as that will try to free it. |
890 | | */ |
891 | 35.9k | sclose(&s); |
892 | 35.9k | if (serialized_size <= sizeof(serialized0)) |
893 | 0 | serialized = serialized0; |
894 | 35.9k | else { |
895 | 35.9k | serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space"); |
896 | 35.9k | if (serialized == NULL) |
897 | 0 | return_error(gs_error_VMerror); |
898 | 35.9k | } |
899 | 35.9k | swrite_string(&s, serialized, serialized_size); |
900 | 35.9k | code = cs_serialize(pcs, &s); |
901 | 35.9k | if (code < 0) |
902 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
903 | 35.9k | if (stell(&s) != serialized_size) |
904 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
905 | 35.9k | sclose(&s); |
906 | 35.9k | pres = pdf_find_cspace_resource(pdev, serialized, serialized_size); |
907 | 35.9k | if (pres != NULL) { |
908 | 32.6k | if (serialized != serialized0) |
909 | 32.6k | gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space"); |
910 | 32.6k | serialized = NULL; |
911 | 32.6k | } |
912 | 35.9k | } |
913 | 40.1k | if (pres) { |
914 | 36.9k | const pdf_color_space_t *const ppcs = |
915 | 36.9k | (const pdf_color_space_t *)pres; |
916 | | |
917 | 36.9k | if (ppranges != 0 && ppcs->ranges != 0) |
918 | 0 | *ppranges = ppcs->ranges; |
919 | 36.9k | pca = (cos_array_t *)pres->object; |
920 | 36.9k | goto ret; |
921 | 36.9k | } |
922 | | |
923 | | /* Space has parameters -- create an array. */ |
924 | 3.22k | pca = cos_array_alloc(pdev, "pdf_color_space"); |
925 | 3.22k | if (pca == 0) |
926 | 0 | return_error(gs_error_VMerror); |
927 | | |
928 | 3.22k | switch (csi) { |
929 | | |
930 | 1.47k | case gs_color_space_index_ICC: |
931 | 1.47k | code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs, pca); |
932 | 1.47k | break; |
933 | | |
934 | 0 | case gs_color_space_index_CIEA: { |
935 | | /* Check that we can represent this as a CalGray space. */ |
936 | 0 | const gs_cie_a *pcie = pcs->params.a; |
937 | 0 | bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1); |
938 | 0 | bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 && |
939 | 0 | pcie->MatrixA.w == 1); |
940 | 0 | gs_vector3 expts; |
941 | |
|
942 | 0 | pciec = (const gs_cie_common *)pcie; |
943 | 0 | if (!pcie->common.MatrixLMN.is_identity) { |
944 | 0 | if (!pdev->ForOPDFRead) { |
945 | 0 | if (pcs->icc_equivalent == 0) { |
946 | 0 | code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory); |
947 | 0 | if (code < 0) |
948 | 0 | return code; |
949 | 0 | } |
950 | 0 | code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca); |
951 | 0 | if (pcs->params.a->RangeA.rmin < 0.0 || pcs->params.a->RangeA.rmax > 1.0) |
952 | 0 | ranges = &pcs->params.a->RangeA; |
953 | 0 | } else { |
954 | 0 | code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec, |
955 | 0 | &pcie->RangeA, ONE_STEP_NOT, NULL, |
956 | 0 | &ranges); |
957 | 0 | } |
958 | 0 | break; |
959 | 0 | } |
960 | 0 | if (unitary && identityA && |
961 | 0 | CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) && |
962 | 0 | CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) && |
963 | 0 | expts.v == expts.u && expts.w == expts.u |
964 | 0 | ) { |
965 | 0 | DO_NOTHING; |
966 | 0 | } else if (unitary && identityA && |
967 | 0 | CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) && |
968 | 0 | cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u) |
969 | 0 | ) { |
970 | 0 | DO_NOTHING; |
971 | 0 | } else { |
972 | 0 | if (!pdev->ForOPDFRead) { |
973 | 0 | if (pcs->icc_equivalent == 0) { |
974 | 0 | code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory); |
975 | 0 | if (code < 0) |
976 | 0 | return code; |
977 | 0 | } |
978 | 0 | code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca); |
979 | 0 | if (pcs->params.a->RangeA.rmin < 0.0 || pcs->params.a->RangeA.rmax > 1.0) |
980 | 0 | ranges = &pcs->params.a->RangeA; |
981 | 0 | } else { |
982 | 0 | code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec, |
983 | 0 | &pcie->RangeA, ONE_STEP_NOT, NULL, |
984 | 0 | &ranges); |
985 | 0 | } |
986 | 0 | break; |
987 | 0 | } |
988 | 0 | code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray")); |
989 | 0 | if (code < 0) |
990 | 0 | return code; |
991 | 0 | pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)"); |
992 | 0 | if (pcd == 0) |
993 | 0 | return_error(gs_error_VMerror); |
994 | 0 | if (expts.u != 1) { |
995 | 0 | code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u); |
996 | 0 | if (code < 0) |
997 | 0 | return code; |
998 | 0 | } |
999 | 0 | } |
1000 | 0 | cal: |
1001 | | /* Finish handling a CIE-based color space (Calxxx or Lab). */ |
1002 | 0 | if (code < 0) |
1003 | 0 | return code; |
1004 | 0 | code = pdf_finish_cie_space(pdev, pca, pcd, pciec); |
1005 | 0 | break; |
1006 | | |
1007 | 0 | case gs_color_space_index_CIEABC: { |
1008 | | /* Check that we can represent this as a CalRGB space. */ |
1009 | 0 | const gs_cie_abc *pcie = pcs->params.abc; |
1010 | 0 | bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3); |
1011 | 0 | gs_vector3 expts; |
1012 | 0 | const gs_matrix3 *pmat = NULL; |
1013 | 0 | cie_cache_one_step_t one_step = |
1014 | 0 | cie_cached_abc_is_one_step(pcie, &pmat); |
1015 | |
|
1016 | 0 | pciec = (const gs_cie_common *)pcie; |
1017 | 0 | if (unitary) { |
1018 | 0 | switch (one_step) { |
1019 | 0 | case ONE_STEP_ABC: |
1020 | 0 | if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts)) |
1021 | 0 | goto calrgb; |
1022 | 0 | break; |
1023 | 0 | case ONE_STEP_LMN: |
1024 | 0 | if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts)) |
1025 | 0 | goto calrgb; |
1026 | 0 | default: |
1027 | 0 | break; |
1028 | 0 | } |
1029 | 0 | } |
1030 | 0 | if (cie_is_lab(pcie)) { |
1031 | | /* Represent this as a Lab space. */ |
1032 | 0 | pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)"); |
1033 | 0 | if (pcd == 0) |
1034 | 0 | return_error(gs_error_VMerror); |
1035 | 0 | code = pdf_put_lab_color_space(pdev, pca, pcd, pcie->RangeABC.ranges); |
1036 | 0 | goto cal; |
1037 | 0 | } else { |
1038 | 0 | if (!pdev->ForOPDFRead) { |
1039 | 0 | int i; |
1040 | |
|
1041 | 0 | if (pcs->icc_equivalent == 0) { |
1042 | 0 | code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory); |
1043 | 0 | if (code < 0) |
1044 | 0 | return code; |
1045 | 0 | } |
1046 | 0 | code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca); |
1047 | 0 | for (i = 0; i < 3; ++i) { |
1048 | 0 | double rmin = pcs->params.abc->RangeABC.ranges[i].rmin, rmax = pcs->params.abc->RangeABC.ranges[i].rmax; |
1049 | |
|
1050 | 0 | if (rmin < 0.0 || rmax > 1.0) |
1051 | 0 | ranges = pcs->params.abc->RangeABC.ranges; |
1052 | 0 | } |
1053 | 0 | } else { |
1054 | 0 | code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec, |
1055 | 0 | pcie->RangeABC.ranges, |
1056 | 0 | one_step, pmat, &ranges); |
1057 | 0 | } |
1058 | 0 | break; |
1059 | 0 | } |
1060 | 0 | calrgb: |
1061 | 0 | code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB")); |
1062 | 0 | if (code < 0) |
1063 | 0 | return code; |
1064 | 0 | pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)"); |
1065 | 0 | if (pcd == 0) |
1066 | 0 | return_error(gs_error_VMerror); |
1067 | 0 | if (expts.u != 1 || expts.v != 1 || expts.w != 1) { |
1068 | 0 | code = cos_dict_put_c_key_vector3(pdev, pcd, "/Gamma", &expts); |
1069 | 0 | if (code < 0) |
1070 | 0 | return code; |
1071 | 0 | } |
1072 | 0 | if (!pmat->is_identity) { |
1073 | 0 | cos_array_t *pcma = |
1074 | 0 | cos_array_alloc(pdev, "pdf_color_space(Matrix)"); |
1075 | |
|
1076 | 0 | if (pcma == 0) |
1077 | 0 | return_error(gs_error_VMerror); |
1078 | 0 | if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 || |
1079 | 0 | (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 || |
1080 | 0 | (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 || |
1081 | 0 | (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7, |
1082 | 0 | COS_OBJECT_VALUE(&v, pcma))) < 0 |
1083 | 0 | ) |
1084 | 0 | return code; |
1085 | 0 | } |
1086 | 0 | } |
1087 | 0 | goto cal; |
1088 | | |
1089 | 0 | case gs_color_space_index_CIEDEF: |
1090 | 0 | if (!pdev->ForOPDFRead) { |
1091 | 0 | int i; |
1092 | 0 | if (pcs->icc_equivalent == 0) { |
1093 | 0 | code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory); |
1094 | 0 | if (code < 0) |
1095 | 0 | return code; |
1096 | 0 | } |
1097 | 0 | code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca); |
1098 | 0 | for (i = 0; i < 3; ++i) { |
1099 | 0 | double rmin = pcs->params.def->RangeDEF.ranges[i].rmin, rmax = pcs->params.def->RangeDEF.ranges[i].rmax; |
1100 | |
|
1101 | 0 | if (rmin < 0.0 || rmax > 1.0) |
1102 | 0 | ranges = pcs->params.def->RangeDEF.ranges; |
1103 | 0 | } |
1104 | 0 | } else { |
1105 | 0 | code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", |
1106 | 0 | (const gs_cie_common *)pcs->params.def, |
1107 | 0 | pcs->params.def->RangeDEF.ranges, |
1108 | 0 | ONE_STEP_NOT, NULL, &ranges); |
1109 | 0 | } |
1110 | 0 | break; |
1111 | | |
1112 | 0 | case gs_color_space_index_CIEDEFG: |
1113 | 0 | if (!pdev->ForOPDFRead) { |
1114 | 0 | int i; |
1115 | 0 | if (pcs->icc_equivalent == 0) { |
1116 | 0 | code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &is_lab, pdev->memory); |
1117 | 0 | if (code < 0) |
1118 | 0 | return code; |
1119 | 0 | } |
1120 | 0 | code = pdf_iccbased_color_space(pdev, pgs, pvalue, pcs->icc_equivalent, pca); |
1121 | 0 | for (i = 0; i < 4; ++i) { |
1122 | 0 | double rmin = pcs->params.defg->RangeDEFG.ranges[i].rmin, rmax = pcs->params.defg->RangeDEFG.ranges[i].rmax; |
1123 | |
|
1124 | 0 | if (rmin < 0.0 || rmax > 1.0) |
1125 | 0 | ranges = pcs->params.defg->RangeDEFG.ranges; |
1126 | 0 | } |
1127 | 0 | } else { |
1128 | 0 | code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK", |
1129 | 0 | (const gs_cie_common *)pcs->params.defg, |
1130 | 0 | pcs->params.defg->RangeDEFG.ranges, |
1131 | 0 | ONE_STEP_NOT, NULL, &ranges); |
1132 | 0 | } |
1133 | 0 | break; |
1134 | | |
1135 | 724 | case gs_color_space_index_Indexed: |
1136 | 724 | code = pdf_indexed_color_space(pdev, pgs, pvalue, pcs, pca, NULL); |
1137 | 724 | break; |
1138 | | |
1139 | 56 | case gs_color_space_index_DeviceN: |
1140 | 56 | if (!pdev->PreserveDeviceN) |
1141 | 0 | return_error(gs_error_rangecheck); |
1142 | 56 | if (pdev->CompatibilityLevel < 1.3) |
1143 | 54 | return_error(gs_error_rangecheck); |
1144 | 2 | pfn = gs_cspace_get_devn_function(pcs); |
1145 | | /****** CURRENTLY WE ONLY HANDLE Functions ******/ |
1146 | 2 | if (pfn == 0) |
1147 | 0 | return_error(gs_error_rangecheck); |
1148 | 2 | { |
1149 | 2 | cos_array_t *psna = |
1150 | 2 | cos_array_alloc(pdev, "pdf_color_space(DeviceN)"); |
1151 | 2 | int i; |
1152 | 2 | byte *name_string; |
1153 | 2 | uint name_string_length; |
1154 | 2 | cos_value_t v_attributes, *va = NULL; |
1155 | 2 | pdf_resource_t *pres_attributes = NULL; |
1156 | | |
1157 | 2 | if (psna == 0) |
1158 | 0 | return_error(gs_error_VMerror); |
1159 | 9 | for (i = 0; i < pcs->params.device_n.num_components; ++i) { |
1160 | 7 | name_string = (byte *)pcs->params.device_n.names[i]; |
1161 | 7 | name_string_length = strlen(pcs->params.device_n.names[i]); |
1162 | | |
1163 | 7 | code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v); |
1164 | 7 | if (code < 0) |
1165 | 0 | return code; |
1166 | 7 | code = cos_array_add(psna, &v); |
1167 | 7 | cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(DeviceN component)"); |
1168 | 7 | if (code < 0) |
1169 | 0 | return code; |
1170 | 7 | } |
1171 | 2 | COS_OBJECT_VALUE(&v, psna); |
1172 | | |
1173 | | /* If we have either /Process or /Colorants (or both) then we need to create an |
1174 | | * attributes dictionary. |
1175 | | */ |
1176 | 2 | if (pcs->params.device_n.devn_process_space != NULL || pcs->params.device_n.colorants != NULL) { |
1177 | 0 | cos_value_t v_Subtype_name; |
1178 | |
|
1179 | 0 | code = pdf_alloc_resource(pdev, resourceOther, 0, &pres_attributes, -1); |
1180 | 0 | if (code < 0) |
1181 | 0 | return code; |
1182 | 0 | cos_become(pres_attributes->object, cos_type_dict); |
1183 | |
|
1184 | 0 | if (pcs->params.device_n.subtype == gs_devicen_DeviceN) { |
1185 | 0 | code = pdf_string_to_cos_name(pdev, (const byte *)"DeviceN", 7, &v_Subtype_name); |
1186 | 0 | if (code < 0) |
1187 | 0 | return code; |
1188 | 0 | } else { |
1189 | 0 | if (pcs->params.device_n.subtype == gs_devicen_NChannel) { |
1190 | 0 | code = pdf_string_to_cos_name(pdev, (const byte *)"NChannel", 8, &v_Subtype_name); |
1191 | 0 | if (code < 0) |
1192 | 0 | return code; |
1193 | 0 | } else |
1194 | 0 | return gs_note_error(gs_error_typecheck); |
1195 | 0 | } |
1196 | 0 | code = cos_dict_put((cos_dict_t *)pres_attributes->object, (const byte *)"/Subtype", 8, &v_Subtype_name); |
1197 | 0 | cos_value_free((const cos_value_t *)&v_Subtype_name, pdev->pdf_memory, "pdf_color_space(Subtype)"); |
1198 | 0 | if (code < 0) |
1199 | 0 | return code; |
1200 | 0 | } |
1201 | 2 | if (pcs->params.device_n.devn_process_space != NULL) { |
1202 | 0 | cos_dict_t *process; |
1203 | 0 | cos_array_t *components; |
1204 | 0 | cos_value_t v_process, v_components, v_process_space, v_process_name; |
1205 | 0 | int m; |
1206 | |
|
1207 | 0 | process = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)"); |
1208 | 0 | if (process == NULL) |
1209 | 0 | return_error(gs_error_VMerror); |
1210 | | |
1211 | 0 | COS_OBJECT_VALUE(&v_process, process); |
1212 | 0 | code = cos_dict_put((cos_dict_t *)pres_attributes->object, |
1213 | 0 | (const byte *)"/Process", 8, &v_process); |
1214 | 0 | if (code < 0) |
1215 | 0 | return code; |
1216 | | |
1217 | 0 | code = pdf_color_space_named(pdev, pgs, &v_process_space, NULL, pcs->params.device_n.devn_process_space, pcsn, false, NULL, 0, keepICC); |
1218 | 0 | if (code < 0) |
1219 | 0 | return code; |
1220 | 0 | code = pdf_string_to_cos_name(pdev, (const byte *)"ColorSpace", 10, &v_process_name); |
1221 | 0 | if (code < 0) |
1222 | 0 | return code; |
1223 | 0 | code = cos_dict_put(process, v_process_name.contents.chars.data, |
1224 | 0 | v_process_name.contents.chars.size, &v_process_space); |
1225 | 0 | cos_value_free((const cos_value_t *)&v_process_name, pdev->pdf_memory, "pdf_color_space(ColorSpace)"); |
1226 | 0 | if (code < 0) |
1227 | 0 | return code; |
1228 | | |
1229 | 0 | components = cos_array_alloc(pdev, "pdf_color_space(DeviceN)"); |
1230 | 0 | if (components == NULL) { |
1231 | 0 | return_error(gs_error_VMerror); |
1232 | 0 | } |
1233 | 0 | COS_OBJECT_VALUE(&v_components, components); |
1234 | 0 | code = cos_dict_put((cos_dict_t *)process, |
1235 | 0 | (const byte *)"/Components", 11, &v_components); |
1236 | 0 | if (code < 0) |
1237 | 0 | return code; |
1238 | 0 | for (m=0;m < pcs->params.device_n.num_process_names;m++) { |
1239 | 0 | code = pdf_string_to_cos_name(pdev, (const byte *)pcs->params.device_n.process_names[m], strlen(pcs->params.device_n.process_names[m]), &v_process_name); |
1240 | 0 | if (code < 0) |
1241 | 0 | return code; |
1242 | 0 | code = cos_array_put(components, m, &v_process_name); |
1243 | 0 | cos_value_free((const cos_value_t *)&v_process_name, pdev->pdf_memory, "pdf_color_space(process_name)"); |
1244 | 0 | if (code < 0) |
1245 | 0 | return code; |
1246 | 0 | } |
1247 | |
|
1248 | 0 | } |
1249 | 2 | if (pcs->params.device_n.colorants != NULL) { |
1250 | 0 | cos_dict_t *colorants = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)"); |
1251 | 0 | cos_value_t v_colorants, v_separation, v_colorant_name; |
1252 | 0 | const gs_device_n_colorant *csa; |
1253 | |
|
1254 | 0 | if (colorants == NULL) |
1255 | 0 | return_error(gs_error_VMerror); |
1256 | | |
1257 | 0 | COS_OBJECT_VALUE(&v_colorants, colorants); |
1258 | 0 | code = cos_dict_put((cos_dict_t *)pres_attributes->object, |
1259 | 0 | (const byte *)"/Colorants", 10, &v_colorants); |
1260 | 0 | if (code < 0) |
1261 | 0 | return code; |
1262 | 0 | for (csa = pcs->params.device_n.colorants; csa != NULL; csa = csa->next) { |
1263 | 0 | name_string = (byte *)csa->colorant_name; |
1264 | 0 | name_string_length = strlen((const char *)name_string); |
1265 | 0 | code = pdf_color_space_named(pdev, pgs, &v_separation, NULL, csa->cspace, pcsn, false, NULL, 0, keepICC); |
1266 | 0 | if (code < 0) |
1267 | 0 | return code; |
1268 | 0 | code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v_colorant_name); |
1269 | 0 | if (code < 0) |
1270 | 0 | return code; |
1271 | 0 | code = cos_dict_put(colorants, v_colorant_name.contents.chars.data, |
1272 | 0 | v_colorant_name.contents.chars.size, &v_separation); |
1273 | 0 | cos_value_free((const cos_value_t *)&v_colorant_name, pdev->pdf_memory, "pdf_color_space(Subtype)"); |
1274 | 0 | if (code < 0) |
1275 | 0 | return code; |
1276 | 0 | } |
1277 | 0 | } |
1278 | 2 | if (pres_attributes != NULL) { |
1279 | 0 | code = pdf_substitute_resource(pdev, &pres_attributes, resourceOther, NULL, true); |
1280 | 0 | if (code < 0) |
1281 | 0 | return code; |
1282 | 0 | pres_attributes->where_used |= pdev->used_mask; |
1283 | 0 | va = &v_attributes; |
1284 | 0 | COS_OBJECT_VALUE(va, pres_attributes->object); |
1285 | 0 | } |
1286 | 2 | code = pdf_separation_color_space(pdev, pgs, pca, "/DeviceN", &v, |
1287 | 2 | pcs->base_space, |
1288 | 2 | pfn, &pdf_color_space_names, va); |
1289 | 2 | if (v.value_type == COS_VALUE_SCALAR) |
1290 | 0 | cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(Devicen)"); |
1291 | 2 | if (va != NULL && va->value_type == COS_VALUE_SCALAR) |
1292 | 0 | cos_value_free((const cos_value_t *)&va, pdev->pdf_memory, "pdf_color_space(Devicen)"); |
1293 | 2 | if (code < 0) |
1294 | 0 | return code; |
1295 | 2 | } |
1296 | 2 | break; |
1297 | | |
1298 | 952 | case gs_color_space_index_Separation: |
1299 | 952 | if (!pdev->PreserveSeparation) |
1300 | 0 | return_error(gs_error_rangecheck); |
1301 | 952 | pfn = gs_cspace_get_sepr_function(pcs); |
1302 | | /****** CURRENTLY WE ONLY HANDLE Functions ******/ |
1303 | 952 | if (pfn == 0) |
1304 | 0 | return_error(gs_error_rangecheck); |
1305 | 952 | { |
1306 | 952 | code = pdf_string_to_cos_name(pdev, (const byte *)pcs->params.separation.sep_name, |
1307 | 952 | strlen(pcs->params.separation.sep_name), &v); |
1308 | 952 | if (code < 0) |
1309 | 0 | return code; |
1310 | | |
1311 | 952 | code = pdf_separation_color_space(pdev, pgs, pca, "/Separation", &v, |
1312 | 952 | pcs->base_space, |
1313 | 952 | pfn, &pdf_color_space_names, NULL); |
1314 | 952 | if (v.value_type == COS_VALUE_SCALAR) |
1315 | 952 | cos_value_free((const cos_value_t *)&v, pdev->pdf_memory, "pdf_color_space(Separation name)"); |
1316 | 952 | if (code < 0) |
1317 | 0 | return code; |
1318 | 952 | } |
1319 | 952 | break; |
1320 | | |
1321 | 952 | case gs_color_space_index_Pattern: |
1322 | 15 | if ((code = pdf_color_space_named(pdev, pgs, pvalue, ppranges, |
1323 | 15 | pcs->base_space, |
1324 | 15 | &pdf_color_space_names, false, NULL, 0, false)) < 0 || |
1325 | 15 | (code = cos_array_add(pca, |
1326 | 15 | cos_c_string_value(&v, "/Pattern"))) < 0 || |
1327 | 15 | (code = cos_array_add(pca, pvalue)) < 0 |
1328 | 15 | ) |
1329 | 0 | return code; |
1330 | 15 | break; |
1331 | | |
1332 | 15 | default: |
1333 | 0 | return_error(gs_error_rangecheck); |
1334 | 3.22k | } |
1335 | | |
1336 | | /* |
1337 | | * Register the color space as a resource, since it must be referenced |
1338 | | * by name rather than directly. |
1339 | | */ |
1340 | 3.16k | { |
1341 | 3.16k | pdf_color_space_t *ppcs; |
1342 | | |
1343 | 3.16k | if (code < 0 || |
1344 | 3.16k | (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id, |
1345 | 3.16k | &pres, -1)) < 0 |
1346 | 3.16k | ) { |
1347 | 0 | COS_FREE(pca, "pdf_color_space"); |
1348 | 0 | return code; |
1349 | 0 | } |
1350 | 3.16k | pdf_reserve_object_id(pdev, pres, 0); |
1351 | 3.16k | if (res_name != NULL) { |
1352 | 0 | int l = min(name_length, sizeof(pres->rname) - 1); |
1353 | |
|
1354 | 0 | memcpy(pres->rname, res_name, l); |
1355 | 0 | pres->rname[l] = 0; |
1356 | 0 | } |
1357 | 3.16k | ppcs = (pdf_color_space_t *)pres; |
1358 | 3.16k | if (serialized == serialized0) { |
1359 | 0 | serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space"); |
1360 | 0 | if (serialized == NULL) |
1361 | 0 | return_error(gs_error_VMerror); |
1362 | 0 | memcpy(serialized, serialized0, serialized_size); |
1363 | 0 | } |
1364 | 3.16k | ppcs->serialized = serialized; |
1365 | 3.16k | ppcs->serialized_size = serialized_size; |
1366 | 3.16k | if (ranges) { |
1367 | 0 | int num_comp = gs_color_space_num_components(pcs); |
1368 | 0 | gs_range_t *copy_ranges = (gs_range_t *) |
1369 | 0 | gs_alloc_byte_array(pdev->pdf_memory, num_comp, |
1370 | 0 | sizeof(gs_range_t), "pdf_color_space"); |
1371 | |
|
1372 | 0 | if (copy_ranges == 0) { |
1373 | 0 | COS_FREE(pca, "pdf_color_space"); |
1374 | 0 | return_error(gs_error_VMerror); |
1375 | 0 | } |
1376 | 0 | memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t)); |
1377 | 0 | ppcs->ranges = copy_ranges; |
1378 | 0 | if (ppranges) |
1379 | 0 | *ppranges = copy_ranges; |
1380 | 0 | } else |
1381 | 3.16k | ppcs->ranges = 0; |
1382 | 3.16k | pca->id = pres->object->id; |
1383 | 3.16k | COS_FREE(pres->object, "pdf_color_space"); |
1384 | 3.16k | pres->object = (cos_object_t *)pca; |
1385 | 3.16k | cos_write_object(COS_OBJECT(pca), pdev, resourceColorSpace); |
1386 | 3.16k | } |
1387 | 40.1k | ret: |
1388 | 40.1k | if (by_name) { |
1389 | | /* Return a resource name rather than an object reference. */ |
1390 | 27.7k | discard(COS_RESOURCE_VALUE(pvalue, pca)); |
1391 | 27.7k | } else |
1392 | 40.1k | discard(COS_OBJECT_VALUE(pvalue, pca)); |
1393 | 40.1k | if (pres != NULL) { |
1394 | 40.1k | pres->where_used |= pdev->used_mask; |
1395 | 40.1k | code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres); |
1396 | 40.1k | if (code < 0) |
1397 | 0 | return code; |
1398 | 40.1k | } |
1399 | 40.1k | return 0; |
1400 | 40.1k | } |
1401 | | |
1402 | | int free_color_space(gx_device_pdf *pdev, pdf_resource_t *pres) |
1403 | 3.48k | { |
1404 | 3.48k | pdf_color_space_t *ppcs = (pdf_color_space_t *)pres; |
1405 | | |
1406 | 3.48k | if (ppcs->serialized) |
1407 | 3.16k | gs_free_object(pdev->pdf_memory, ppcs->serialized, "free serialized colour space"); |
1408 | 3.48k | if (pres->object) { |
1409 | 3.48k | cos_release(pres->object, "release ColorSpace object"); |
1410 | 3.48k | gs_free_object(pdev->pdf_memory, pres->object, "free ColorSpace object"); |
1411 | 3.48k | pres->object = 0; |
1412 | 3.48k | } |
1413 | 3.48k | return 0; |
1414 | 3.48k | } |
1415 | | |
1416 | | /* ---------------- Miscellaneous ---------------- */ |
1417 | | |
1418 | | /* Create colored and uncolored Pattern color spaces. */ |
1419 | | static int |
1420 | | pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue, |
1421 | | pdf_resource_t **ppres, const char *cs_name) |
1422 | 14.6k | { |
1423 | 14.6k | int code; |
1424 | | |
1425 | 14.6k | if (!*ppres) { |
1426 | 317 | int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id, |
1427 | 317 | ppres); |
1428 | | |
1429 | 317 | if (code < 0) |
1430 | 0 | return code; |
1431 | 317 | pprints1(pdev->strm, "%s\n", cs_name); |
1432 | 317 | pdf_end_resource(pdev, resourceColorSpace); |
1433 | 317 | (*ppres)->object->written = true; /* don't write at end */ |
1434 | 317 | ((pdf_color_space_t *)*ppres)->ranges = 0; |
1435 | 317 | ((pdf_color_space_t *)*ppres)->serialized = 0; |
1436 | 317 | } |
1437 | 14.6k | code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres); |
1438 | 14.6k | if (code < 0) |
1439 | 0 | return code; |
1440 | 14.6k | cos_resource_value(pvalue, (*ppres)->object); |
1441 | 14.6k | return 0; |
1442 | 14.6k | } |
1443 | | int |
1444 | | pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue) |
1445 | 14.6k | { |
1446 | 14.6k | return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0], |
1447 | 14.6k | "[/Pattern]"); |
1448 | 14.6k | } |
1449 | | int |
1450 | | pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue) |
1451 | 0 | { |
1452 | | /* Only for process colors. */ |
1453 | 0 | int ncomp = pdev->color_info.num_components; |
1454 | 0 | static const char *const pcs_names[5] = { |
1455 | 0 | 0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]", |
1456 | 0 | "[/Pattern /DeviceCMYK]" |
1457 | 0 | }; |
1458 | |
|
1459 | 0 | return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp], |
1460 | 0 | pcs_names[ncomp]); |
1461 | 0 | } |
1462 | | int |
1463 | | pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev, |
1464 | | const gs_color_space *pcs, cos_value_t *pvalue, const gs_gstate * pgs) |
1465 | 92 | { |
1466 | | /* Only for high level colors. */ |
1467 | 92 | return pdf_color_space_named(pdev, pgs, pvalue, NULL, pcs, &pdf_color_space_names, true, NULL, 0, false); |
1468 | 92 | } |
1469 | | |
1470 | | /* Set the ProcSets bits corresponding to an image color space. */ |
1471 | | void |
1472 | | pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs) |
1473 | 27.8k | { |
1474 | 27.8k | const gs_color_space *pbcs = pcs; |
1475 | | |
1476 | 29.7k | csw: |
1477 | 29.7k | switch (gs_color_space_get_index(pbcs)) { |
1478 | 0 | case gs_color_space_index_DeviceGray: |
1479 | 0 | case gs_color_space_index_CIEA: |
1480 | | /* We only handle CIEBasedA spaces that map to CalGray. */ |
1481 | 0 | pdev->procsets |= ImageB; |
1482 | 0 | break; |
1483 | 1.89k | case gs_color_space_index_Indexed: |
1484 | 1.89k | pdev->procsets |= ImageI; |
1485 | 1.89k | pbcs = pcs->base_space; |
1486 | 1.89k | goto csw; |
1487 | 27.8k | default: |
1488 | 27.8k | pdev->procsets |= ImageC; |
1489 | 27.8k | break; |
1490 | 29.7k | } |
1491 | 29.7k | } |