/src/ghostpdl/devices/vector/gdevpdfv.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 value writing for pdfwrite driver */ |
18 | | #include "math_.h" |
19 | | #include "string_.h" |
20 | | #include "gx.h" |
21 | | #include "gscindex.h" |
22 | | #include "gserrors.h" |
23 | | #include "gsiparm3.h" /* for pattern colors */ |
24 | | #include "gsmatrix.h" /* for gspcolor.h */ |
25 | | #include "gscoord.h" /* for gs_currentmatrix, requires gsmatrix.h */ |
26 | | #include "gsptype2.h" |
27 | | #include "gxcolor2.h" /* for gxpcolor.h */ |
28 | | #include "gxdcolor.h" /* for gxpcolor.h */ |
29 | | #include "gxpcolor.h" /* for pattern device color types */ |
30 | | #include "gxshade.h" |
31 | | #include "gdevpdfx.h" |
32 | | #include "gdevpdfg.h" |
33 | | #include "gdevpdfo.h" |
34 | | |
35 | | /* Import the PatternType 2 Pattern device color type. */ |
36 | | extern const gx_device_color_type_t gx_dc_pattern2; |
37 | | |
38 | | /* |
39 | | * Define the scaling and range of values written for mesh shadings. |
40 | | * BitsPerCoordinate is always 24; BitsPerComponent (for colors) is |
41 | | * always 16. |
42 | | */ |
43 | | #define ENCODE_VALUE(v, emax, vmin, vmax)\ |
44 | 0 | ( ((v) - (vmin)) * ((double)(emax) / ((vmax) - (vmin))) ) |
45 | 0 | #define PDFA_MIN_MESH_COORDINATE (-0x400000 / 128.0) |
46 | 0 | #define PDFA_MAX_MESH_COORDINATE ( 0x3fffff / 128.0) |
47 | | #define PDFA_ENCODE_MESH_COORDINATE(v)\ |
48 | 0 | ENCODE_VALUE(v, 0xffffff, PDFA_MIN_MESH_COORDINATE, PDFA_MAX_MESH_COORDINATE) |
49 | 0 | #define MIN_MESH_COORDINATE (-0x800000 ) |
50 | 0 | #define MAX_MESH_COORDINATE ( 0x7fffff ) |
51 | | #define ENCODE_MESH_COORDINATE(v)\ |
52 | 0 | ENCODE_VALUE(v, 0xffffff, MIN_MESH_COORDINATE, MAX_MESH_COORDINATE) |
53 | | |
54 | 0 | #define MIN_MESH_COLOR_INDEX 0 |
55 | 0 | #define MAX_MESH_COLOR_INDEX 0xffff |
56 | 0 | #define ENCODE_MESH_COLOR_INDEX(v) ((v) + MIN_MESH_COLOR_INDEX) |
57 | | |
58 | | #define ENCODE_MESH_COMPONENT(v, vmin, vmax)\ |
59 | 0 | ENCODE_VALUE(v, 0xffff, vmin, vmax) |
60 | | |
61 | | /* ---------------- Utilities ---------------- */ |
62 | | |
63 | | /* Write a matrix parameter. */ |
64 | | static int |
65 | | cos_dict_put_matrix(gx_device_pdf *pdev, cos_dict_t *pscd, const char *key, const gs_matrix *pmat) |
66 | 12.4k | { |
67 | 12.4k | float matrix[6]; |
68 | | |
69 | 12.4k | matrix[0] = pmat->xx; |
70 | 12.4k | matrix[1] = pmat->xy; |
71 | 12.4k | matrix[2] = pmat->yx; |
72 | 12.4k | matrix[3] = pmat->yy; |
73 | 12.4k | matrix[4] = pmat->tx; |
74 | 12.4k | matrix[5] = pmat->ty; |
75 | 12.4k | return cos_dict_put_c_key_floats(pdev, pscd, key, matrix, 6); |
76 | 12.4k | } |
77 | | |
78 | | /* ---------------- PatternType 1 colors ---------------- */ |
79 | | |
80 | | /* |
81 | | * Create a Pattern resource referencing an image (currently only an XObject). |
82 | | * p_tile is NULL for uncolored patterns or the NULL pattern. |
83 | | * m_tile is NULL for colored patterns that fill their bounding box, |
84 | | * including the NULL pattern. |
85 | | ****** WE DON'T HANDLE NULL PATTERNS YET ****** |
86 | | */ |
87 | | static uint |
88 | | tile_size(const gx_strip_bitmap *tile, int depth) |
89 | 0 | { |
90 | 0 | return (tile->rep_width * depth + 7) / 8 * tile->rep_height; |
91 | 0 | } |
92 | | static bool |
93 | | tile_size_ok(const gx_device_pdf *pdev, const gx_color_tile *p_tile, |
94 | | const gx_color_tile *m_tile) |
95 | 92 | { |
96 | | /* |
97 | | * Acrobat Reader can't handle image Patterns with more than |
98 | | * 64K of data. :-( |
99 | | */ |
100 | 92 | uint p_size = |
101 | 92 | (p_tile == 0 ? 0 : tile_size(&p_tile->tbits, p_tile->depth)); |
102 | 92 | uint m_size = |
103 | 92 | (m_tile == 0 ? 0 : tile_size(&m_tile->tmask, 1)); |
104 | | /* The image limit only applies to Acrobat versions less than 5 |
105 | | * (PDF 1.4). |
106 | | */ |
107 | 92 | if (pdev->CompatibilityLevel < 1.4) |
108 | 92 | return (max(p_size, m_size) <= 65500); |
109 | 0 | else |
110 | 0 | return 1; |
111 | 92 | } |
112 | | |
113 | | static int |
114 | | pdf_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, |
115 | | const gx_color_tile *p_tile, const gx_color_tile *m_tile, |
116 | | cos_stream_t *pcs_image, pdf_resource_t **ppres) |
117 | 0 | { |
118 | 0 | pdf_resource_t *pres; |
119 | 0 | int code = pdf_alloc_resource(pdev, resourcePattern, pdc->mask.id, ppres, |
120 | 0 | 0L); |
121 | 0 | cos_stream_t *pcos; |
122 | 0 | cos_dict_t *pcd; |
123 | 0 | cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)"); |
124 | 0 | const gx_color_tile *tile = (p_tile ? p_tile : m_tile); |
125 | 0 | const gx_strip_bitmap *btile = (p_tile ? &p_tile->tbits : &m_tile->tmask); |
126 | 0 | bool mask = p_tile == 0; |
127 | 0 | gs_point step; |
128 | 0 | gs_matrix smat; |
129 | |
|
130 | 0 | if (code < 0) |
131 | 0 | return code; |
132 | 0 | if (!tile_size_ok(pdev, p_tile, m_tile)) |
133 | 0 | return_error(gs_error_limitcheck); |
134 | | /* |
135 | | * We currently can't handle Patterns whose X/Y step isn't parallel |
136 | | * to the coordinate axes. |
137 | | */ |
138 | 0 | if (is_xxyy(&tile->step_matrix)) |
139 | 0 | step.x = tile->step_matrix.xx, step.y = tile->step_matrix.yy; |
140 | 0 | else if (is_xyyx(&tile->step_matrix)) |
141 | 0 | step.x = tile->step_matrix.yx, step.y = tile->step_matrix.xy; |
142 | 0 | else |
143 | 0 | return_error(gs_error_rangecheck); |
144 | 0 | if (pcd_Resources == 0) |
145 | 0 | return_error(gs_error_VMerror); |
146 | 0 | gs_make_identity(&smat); |
147 | 0 | smat.xx = btile->rep_width / (pdev->HWResolution[0] / 72.0); |
148 | 0 | smat.yy = btile->rep_height / (pdev->HWResolution[1] / 72.0); |
149 | 0 | smat.tx = tile->step_matrix.tx / (pdev->HWResolution[0] / 72.0); |
150 | 0 | smat.ty = tile->step_matrix.ty / (pdev->HWResolution[1] / 72.0); |
151 | 0 | pres = *ppres; |
152 | 0 | { |
153 | 0 | cos_dict_t *pcd_XObject = cos_dict_alloc(pdev, "pdf_pattern(XObject)"); |
154 | 0 | char key[MAX_REF_CHARS + 3]; |
155 | 0 | cos_value_t v; |
156 | 0 | cos_object_t *object; |
157 | |
|
158 | 0 | if (pcd_XObject == 0) |
159 | 0 | return_error(gs_error_VMerror); |
160 | 0 | gs_snprintf(key, sizeof(key), "/R%"PRId64"", pcs_image->id); |
161 | | /* This is non-obvious code. Previously we would put the image object (pcs_image) |
162 | | * into the Resources dit. When we come to write out the Resources dict |
163 | | * that code writes a reference (index 0 R) using the ID from the object. |
164 | | * However that means we have two pointers to the XObject. One in the chain |
165 | | * of resoruces (which we need in order to write teh XObject) and one from |
166 | | * the pattern here. That seriously messes up memory handling. So instead |
167 | | * we now make a new object, and copy the id from the pcs_image. Since that's |
168 | | * all that the writing code will use, we cna avoid the double pointers. |
169 | | */ |
170 | 0 | object = cos_reference_alloc(pdev, "pdf_pattern(reference copy of XObject)"); |
171 | 0 | if (object == NULL) |
172 | 0 | return_error(gs_error_VMerror); |
173 | | |
174 | 0 | object->id = pcs_image->id; |
175 | 0 | COS_OBJECT_VALUE(&v, object); |
176 | 0 | if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 || |
177 | 0 | (code = cos_dict_put_c_key_object(pcd_Resources, "/XObject", |
178 | 0 | COS_OBJECT(pcd_XObject))) < 0 |
179 | 0 | ) |
180 | 0 | return code; |
181 | 0 | } |
182 | 0 | if (pdev->CompatibilityLevel <= 1.7) { |
183 | 0 | if ((code = cos_dict_put_c_strings(pcd_Resources, "/ProcSet", |
184 | 0 | (mask ? "[/PDF/ImageB]" : |
185 | 0 | "[/PDF/ImageC]"))) < 0) |
186 | 0 | return code; |
187 | 0 | } |
188 | 0 | cos_become(pres->object, cos_type_stream); |
189 | 0 | pcos = (cos_stream_t *)pres->object; |
190 | 0 | pcd = cos_stream_dict(pcos); |
191 | 0 | if ((code = cos_dict_put_c_key_int(pcd, "/PatternType", 1)) < 0 || |
192 | 0 | (code = cos_dict_put_c_key_int(pcd, "/PaintType", |
193 | 0 | (mask ? 2 : 1))) < 0 || |
194 | 0 | (code = cos_dict_put_c_key_int(pcd, "/TilingType", |
195 | 0 | tile->tiling_type)) < 0 || |
196 | 0 | (code = cos_dict_put_c_key_object(pcd, "/Resources", |
197 | 0 | COS_OBJECT(pcd_Resources))) < 0 || |
198 | 0 | (code = cos_dict_put_c_strings(pcd, "/BBox", "[0 0 1 1]")) < 0 || |
199 | 0 | (code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat)) < 0 || |
200 | 0 | (code = cos_dict_put_c_key_real(pcd, "/XStep", step.x / btile->rep_width)) < 0 || |
201 | 0 | (code = cos_dict_put_c_key_real(pcd, "/YStep", step.y / btile->rep_height)) < 0 |
202 | 0 | ) { |
203 | 0 | return code; |
204 | 0 | } |
205 | | |
206 | 0 | { |
207 | 0 | char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */ |
208 | |
|
209 | 0 | gs_snprintf(buf, sizeof(buf), "/R%"PRId64" Do\n", pcs_image->id); |
210 | 0 | cos_stream_add_bytes(pdev, pcos, (const byte *)buf, strlen(buf)); |
211 | 0 | } |
212 | |
|
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | | /* Store pattern 1 parameters to cos dictionary. */ |
217 | | int |
218 | | pdf_store_pattern1_params(gx_device_pdf *pdev, pdf_resource_t *pres, |
219 | | gs_pattern1_instance_t *pinst) |
220 | 3.69k | { |
221 | 3.69k | gs_pattern1_template_t *t = &pinst->templat; |
222 | 3.69k | gs_matrix smat2 = ctm_only((gs_gstate *)pinst->saved), smat; |
223 | 3.69k | double scale_x = pdev->HWResolution[0] / 72.0; |
224 | 3.69k | double scale_y = pdev->HWResolution[1] / 72.0; |
225 | 3.69k | cos_dict_t *pcd = cos_stream_dict((cos_stream_t *)pres->object); |
226 | 3.69k | cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)"); |
227 | 3.69k | float bbox[4]; |
228 | 3.69k | int code; |
229 | | |
230 | 3.69k | if (pcd == NULL || pcd_Resources == NULL) |
231 | 0 | return_error(gs_error_VMerror); |
232 | 3.69k | pdev->substream_Resources = pcd_Resources; |
233 | 3.69k | bbox[0] = t->BBox.p.x; |
234 | 3.69k | bbox[1] = t->BBox.p.y; |
235 | 3.69k | bbox[2] = t->BBox.q.x; |
236 | 3.69k | bbox[3] = t->BBox.q.y; |
237 | 3.69k | if (pdev->accumulating_charproc) { |
238 | | /* Assume here we can only be installing a pattern while acumulating a |
239 | | * charproc if the font is a coloured type 3 font. In this case we will |
240 | | * have set the CTM to be the identity scaled by 100 (!). See gdevpdtt.c |
241 | | * install_PS_charproc_accumulator() for details. |
242 | | */ |
243 | 10 | gs_make_identity(&smat2); |
244 | 10 | } |
245 | | /* The graphics library assumes a shifted origin to provide |
246 | | positive bitmap pixel indices. Compensate it now. */ |
247 | 3.69k | smat2.tx += pinst->step_matrix.tx; |
248 | 3.69k | smat2.ty += pinst->step_matrix.ty; |
249 | | /* |
250 | | * In PDF, the Matrix is the transformation from the pattern space to |
251 | | * the *default* user coordinate space, not the current space. |
252 | | * NB. For a form the default space is the parent. This means that when a |
253 | | * form is nested inside a form, the default space is the space of the |
254 | | * first form, and therefore we do *not* remove the resolution scaling. |
255 | | */ |
256 | 3.69k | if ((pdev->FormDepth == 0 || (pdev->FormDepth > 0 && pdev->PatternsSinceForm > 0)) && !pdev->accumulating_charproc) { |
257 | 3.68k | gs_matrix scaled; |
258 | | |
259 | 3.68k | gs_make_scaling(1 / scale_x, 1 / scale_y, &scaled); |
260 | 3.68k | gs_matrix_multiply(&smat2, &scaled, &smat); |
261 | 3.68k | } else { |
262 | 10 | smat = smat2; |
263 | 10 | } |
264 | 3.69k | if ((smat.xx == 0.0 && smat.yy == 0.0) && (smat.xy == 0.0 && smat.yx == 0.0)) |
265 | 0 | return_error(gs_error_undefinedresult); |
266 | | |
267 | 3.69k | if (pdev->ForOPDFRead) { |
268 | 1.66k | if (pdev->PatternDepth) { |
269 | 5 | gs_matrix_multiply(&smat, &pdev->AccumulatedPatternMatrix, &smat2); |
270 | 5 | gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix); |
271 | 5 | smat = smat2; |
272 | 1.65k | } else { |
273 | 1.65k | gs_make_identity(&pdev->AccumulatedPatternMatrix); |
274 | 1.65k | gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix); |
275 | 1.65k | } |
276 | 1.66k | } |
277 | 3.69k | if (any_abs(smat.tx) < 0.0001) /* Noise. */ |
278 | 1.54k | smat.tx = 0; |
279 | 3.69k | if (any_abs(smat.ty) < 0.0001) |
280 | 1.56k | smat.ty = 0; |
281 | 3.69k | code = cos_dict_put_c_strings(pcd, "/Type", "/Pattern"); |
282 | 3.69k | if (code >= 0) |
283 | 3.69k | code = cos_dict_put_c_key_int(pcd, "/PatternType", 1); |
284 | 3.69k | if (code >= 0) |
285 | 3.69k | code = cos_dict_put_c_key_int(pcd, "/PaintType", t->PaintType); |
286 | 3.69k | if (code >= 0) |
287 | 3.69k | code = cos_dict_put_c_key_int(pcd, "/TilingType", t->TilingType); |
288 | 3.69k | if (code >= 0) |
289 | 3.69k | code = cos_dict_put_c_key_floats(pdev, pcd, "/BBox", bbox, 4); |
290 | 3.69k | if (code >= 0) |
291 | 3.69k | code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat); |
292 | 3.69k | if (code >= 0) |
293 | 3.69k | code = cos_dict_put_c_key_real(pcd, "/XStep", t->XStep); |
294 | 3.69k | if (code >= 0) |
295 | 3.69k | code = cos_dict_put_c_key_real(pcd, "/YStep", t->YStep); |
296 | 3.69k | if (code >= 0) |
297 | 3.69k | code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources)); |
298 | 3.69k | pdev->skip_colors = (t->PaintType == 2); |
299 | 3.69k | return code; |
300 | 3.69k | } |
301 | | |
302 | | /* Set the ImageMatrix, Width, and Height for a Pattern image. */ |
303 | | static void |
304 | | pdf_set_pattern_image(gs_data_image_t *pic, const gx_strip_bitmap *tile) |
305 | 0 | { |
306 | 0 | pic->ImageMatrix.xx = (float)(pic->Width = tile->rep_width); |
307 | 0 | pic->ImageMatrix.yy = (float)(pic->Height = tile->rep_height); |
308 | 0 | } |
309 | | |
310 | | /* Write the mask for a Pattern (colored or uncolored). */ |
311 | | static int |
312 | | pdf_put_pattern_mask(gx_device_pdf *pdev, const gx_color_tile *m_tile, |
313 | | cos_stream_t **ppcs_mask) |
314 | 0 | { |
315 | 0 | int w = m_tile->tmask.rep_width, h = m_tile->tmask.rep_height; |
316 | 0 | gs_image1_t image; |
317 | 0 | pdf_image_writer writer; |
318 | 0 | int code; |
319 | |
|
320 | 0 | gs_image_t_init_mask_adjust(&image, true, false); |
321 | 0 | pdf_set_pattern_image((gs_data_image_t *)&image, &m_tile->tmask); |
322 | 0 | pdf_image_writer_init(&writer); |
323 | 0 | if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 || |
324 | 0 | (pdev->params.MonoImage.Encode && |
325 | 0 | (code = psdf_CFE_binary(&writer.binary[0], w, h, true)) < 0) || |
326 | 0 | (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, NULL, 0)) < 0 |
327 | 0 | ) |
328 | 0 | return code; |
329 | | /* Pattern masks are specified in device coordinates, so invert Y. */ |
330 | 0 | if ((code = pdf_copy_mask_bits(writer.binary[0].strm, m_tile->tmask.data + (h - 1) * m_tile->tmask.raster, 0, -m_tile->tmask.raster, w, h, 0)) < 0 || |
331 | 0 | (code = pdf_end_image_binary(pdev, &writer, h)) < 0 || |
332 | 0 | (code = pdf_end_write_image(pdev, &writer)) < 0 |
333 | 0 | ) |
334 | 0 | return code; |
335 | 0 | *ppcs_mask = (cos_stream_t *)writer.pres->object; |
336 | 0 | return 0; |
337 | 0 | } |
338 | | |
339 | | /* Write an uncolored Pattern color. */ |
340 | | int |
341 | | pdf_put_uncolored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, |
342 | | const gs_color_space *pcs, |
343 | | const psdf_set_color_commands_t *ppscc, |
344 | | const gs_gstate * pgs, pdf_resource_t **ppres) |
345 | 92 | { |
346 | 92 | const gx_color_tile *m_tile = pdc->mask.m_tile; |
347 | 92 | gx_drawing_color dc_pure; |
348 | | |
349 | 92 | if (!pgs->have_pattern_streams && m_tile == 0) { |
350 | | /* |
351 | | * If m_tile == 0, this uncolored Pattern is all 1's, |
352 | | * equivalent to a pure color. |
353 | | */ |
354 | 0 | *ppres = 0; |
355 | 0 | set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc)); |
356 | 0 | return psdf_set_color((gx_device_vector *)pdev, &dc_pure, ppscc); |
357 | 92 | } else { |
358 | 92 | cos_value_t v; |
359 | 92 | stream *s = pdev->strm; |
360 | 92 | int code; |
361 | 92 | cos_stream_t *pcs_image; |
362 | 92 | static const psdf_set_color_commands_t no_scc = {0, 0, 0}; |
363 | | |
364 | 92 | if (!tile_size_ok(pdev, NULL, m_tile)) |
365 | 0 | return_error(gs_error_limitcheck); |
366 | 92 | if (!pgs->have_pattern_streams) { |
367 | 0 | if ((code = pdf_cs_Pattern_uncolored(pdev, &v)) < 0 || |
368 | 0 | (code = pdf_put_pattern_mask(pdev, m_tile, &pcs_image)) < 0 || |
369 | 0 | (code = pdf_pattern(pdev, pdc, NULL, m_tile, pcs_image, ppres)) < 0 |
370 | 0 | ) |
371 | 0 | return code; |
372 | 92 | } else { |
373 | 92 | code = pdf_cs_Pattern_uncolored_hl(pdev, pcs, &v, pgs); |
374 | 92 | if (code < 0) |
375 | 0 | return code; |
376 | 92 | *ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, pdc->mask.id); |
377 | 92 | if (*ppres == NULL) |
378 | 0 | return_error(gs_error_undefined); |
379 | | |
380 | 92 | *ppres = pdf_substitute_pattern(*ppres); |
381 | 92 | if (!pdev->AR4_save_bug && pdev->CompatibilityLevel <= 1.3) { |
382 | | /* We reconnized AR4 behavior as reserving "q Q" stack elements |
383 | | * on demand. It looks as processing a pattern stream |
384 | | * with PaintType 1 AR4 replaces the topmost stack element |
385 | | * instead allocating a new one, if it was not previousely allocated. |
386 | | * AR 5 doesn't have this bug. Working around the AR4 bug here. |
387 | | */ |
388 | 15 | stream_puts(pdev->strm, "q q Q Q\n"); |
389 | 15 | pdev->AR4_save_bug = true; |
390 | 15 | } |
391 | 92 | (*ppres)->where_used |= pdev->used_mask; |
392 | 92 | } |
393 | 92 | cos_value_write(&v, pdev); |
394 | 92 | pprints1(s, " %s ", ppscc->setcolorspace); |
395 | 92 | if (pgs->have_pattern_streams) |
396 | 92 | return 0; |
397 | 92 | set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc)); |
398 | 0 | return psdf_set_color((gx_device_vector *)pdev, &dc_pure, &no_scc); |
399 | 92 | } |
400 | 92 | } |
401 | | |
402 | | int |
403 | | pdf_put_colored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, |
404 | | const gs_color_space *pcs, |
405 | | const psdf_set_color_commands_t *ppscc, |
406 | | const gs_gstate * pgs, pdf_resource_t **ppres) |
407 | 5.86k | { |
408 | 5.86k | const gx_color_tile *p_tile = pdc->colors.pattern.p_tile; |
409 | 5.86k | gs_color_space *pcs_Device; |
410 | 5.86k | cos_value_t cs_value; |
411 | 5.86k | cos_value_t v; |
412 | 5.86k | int code; |
413 | 5.86k | gs_image1_t image; |
414 | 5.86k | const gx_color_tile *m_tile = NULL; |
415 | 5.86k | pdf_image_writer writer; |
416 | 5.86k | int w = 0, h = 0; |
417 | | |
418 | 5.86k | if (p_tile) { |
419 | 5.86k | w = p_tile->tbits.rep_width; |
420 | 5.86k | h = p_tile->tbits.rep_height; |
421 | 5.86k | } |
422 | | |
423 | 5.86k | if (!pgs->have_pattern_streams) { |
424 | | /* |
425 | | * NOTE: We assume here that the color space of the cached Pattern |
426 | | * is the same as the native color space of the device. This will |
427 | | * have to change in the future! |
428 | | */ |
429 | | /* |
430 | | * Check whether this colored pattern is actually a masked pure color, |
431 | | * by testing whether all the colored pixels have the same color. |
432 | | */ |
433 | 0 | m_tile = pdc->mask.m_tile; |
434 | 0 | if (m_tile) { |
435 | 0 | if (p_tile && !(p_tile->depth & 7) && p_tile->depth <= ARCH_SIZEOF_COLOR_INDEX * 8) { |
436 | 0 | int depth_bytes = p_tile->depth >> 3; |
437 | 0 | int width = p_tile->tbits.rep_width; |
438 | 0 | int skip = p_tile->tbits.raster - |
439 | 0 | p_tile->tbits.rep_width * depth_bytes; |
440 | 0 | const byte *bp; |
441 | 0 | const byte *mp; |
442 | 0 | int i, j, k; |
443 | 0 | gx_color_index color = 0; /* init is arbitrary if not empty */ |
444 | 0 | bool first = true; |
445 | |
|
446 | 0 | for (i = 0, bp = p_tile->tbits.data, mp = p_tile->tmask.data; |
447 | 0 | i < p_tile->tbits.rep_height; |
448 | 0 | ++i, bp += skip, mp += p_tile->tmask.raster) { |
449 | |
|
450 | 0 | for (j = 0; j < width; ++j) { |
451 | 0 | if (mp[j >> 3] & (0x80 >> (j & 7))) { |
452 | 0 | gx_color_index ci = 0; |
453 | |
|
454 | 0 | for (k = 0; k < depth_bytes; ++k) |
455 | 0 | ci = (ci << 8) + *bp++; |
456 | 0 | if (first) |
457 | 0 | color = ci, first = false; |
458 | 0 | else if (ci != color) |
459 | 0 | goto not_pure; |
460 | 0 | } else |
461 | 0 | bp += depth_bytes; |
462 | 0 | } |
463 | 0 | } |
464 | 0 | { |
465 | | /* Set the color, then handle as an uncolored pattern. */ |
466 | 0 | gx_drawing_color dcolor; |
467 | |
|
468 | 0 | dcolor = *pdc; |
469 | 0 | dcolor.colors.pure = color; |
470 | 0 | return pdf_put_uncolored_pattern(pdev, &dcolor, pcs, ppscc, |
471 | 0 | pgs, ppres); |
472 | 0 | } |
473 | 0 | not_pure: |
474 | 0 | DO_NOTHING; /* required by MSVC */ |
475 | 0 | } |
476 | 0 | if (pdev->CompatibilityLevel < 1.3) { |
477 | | /* Masked images are only supported starting in PDF 1.3. */ |
478 | 0 | return_error(gs_error_rangecheck); |
479 | 0 | } |
480 | 0 | } |
481 | | /* Acrobat Reader has a size limit for image Patterns. */ |
482 | 0 | if (!tile_size_ok(pdev, p_tile, m_tile)) |
483 | 0 | return_error(gs_error_limitcheck); |
484 | 0 | } |
485 | 5.86k | code = pdf_cs_Pattern_colored(pdev, &v); |
486 | 5.86k | if (code < 0) |
487 | 0 | return code; |
488 | 5.86k | pdf_cspace_init_Device(pdev->memory, &pcs_Device, pdev->color_info.num_components); |
489 | | /* |
490 | | * We don't have to worry about color space scaling: the color |
491 | | * space is always a Device space. |
492 | | */ |
493 | 5.86k | code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs_Device, |
494 | 5.86k | &pdf_color_space_names, true, NULL, 0, false); |
495 | 5.86k | if (code < 0) |
496 | 0 | return code; |
497 | 5.86k | if (!pgs->have_pattern_streams) { |
498 | 0 | cos_stream_t *pcs_mask = 0; |
499 | 0 | cos_stream_t *pcs_image; |
500 | |
|
501 | 0 | gs_image_t_init_adjust(&image, pcs_Device, false); |
502 | 0 | image.BitsPerComponent = 8; |
503 | 0 | if (!p_tile) |
504 | 0 | return_error(gs_error_unknownerror); |
505 | | |
506 | 0 | pdf_set_pattern_image((gs_data_image_t *)&image, &p_tile->tbits); |
507 | 0 | if (m_tile) { |
508 | 0 | if ((code = pdf_put_pattern_mask(pdev, m_tile, &pcs_mask)) < 0) |
509 | 0 | return code; |
510 | 0 | } |
511 | 0 | pdf_image_writer_init(&writer); |
512 | 0 | pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel; |
513 | 0 | if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 || |
514 | 0 | (code = psdf_setup_lossless_filters((gx_device_psdf *)pdev, |
515 | 0 | &writer.binary[0], |
516 | 0 | (gs_pixel_image_t *)&image, false)) < 0 || |
517 | 0 | (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, &cs_value, 0)) < 0 |
518 | 0 | ) |
519 | 0 | return code; |
520 | | /* Pattern masks are specified in device coordinates, so invert Y. */ |
521 | 0 | if ((code = pdf_copy_color_bits(writer.binary[0].strm, p_tile->tbits.data + (h - 1) * p_tile->tbits.raster, 0, -p_tile->tbits.raster, w, h, pdev->color_info.depth >> 3)) < 0 || |
522 | 0 | (code = pdf_end_image_binary(pdev, &writer, h)) < 0 |
523 | 0 | ) |
524 | 0 | return code; |
525 | 0 | pcs_image = (cos_stream_t *)writer.pres->object; |
526 | 0 | if ((pcs_mask != 0 && |
527 | 0 | (code = cos_dict_put_c_key_object(cos_stream_dict(pcs_image), "/Mask", |
528 | 0 | COS_OBJECT(pcs_mask))) < 0) || |
529 | 0 | (code = pdf_end_write_image(pdev, &writer)) < 0 |
530 | 0 | ) |
531 | 0 | return code; |
532 | 0 | pcs_image = (cos_stream_t *)writer.pres->object; /* pdf_end_write_image may change it. */ |
533 | 0 | code = pdf_pattern(pdev, pdc, p_tile, m_tile, pcs_image, ppres); |
534 | 0 | if (code < 0) |
535 | 0 | return code; |
536 | 5.86k | } else { |
537 | 5.86k | if (!p_tile) |
538 | 0 | return_error(gs_error_unknownerror); |
539 | 5.86k | *ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, p_tile->id); |
540 | 5.86k | *ppres = pdf_substitute_pattern(*ppres); |
541 | 5.86k | (*ppres)->where_used |= pdev->used_mask; |
542 | 5.86k | } |
543 | | /* pcs_Device will leak (picked up by GC in PS) on error, but we'll |
544 | | tolerate that for now. */ |
545 | 5.86k | rc_decrement_cs(pcs_Device, "pdf_put_colored_pattern"); |
546 | 5.86k | cos_value_write(&v, pdev); |
547 | 5.86k | pprints1(pdev->strm, " %s", ppscc->setcolorspace); |
548 | 5.86k | return 0; |
549 | 5.86k | } |
550 | | |
551 | | /* ---------------- PatternType 2 colors ---------------- */ |
552 | | |
553 | | /* Write parameters common to all Shadings. */ |
554 | | static int |
555 | | pdf_put_shading_common(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_gstate * pgs, const gs_shading_t *psh, |
556 | | bool shfill, const gs_range_t **ppranges) |
557 | 8.76k | { |
558 | 8.76k | gs_shading_type_t type = ShadingType(psh); |
559 | 8.76k | const gs_color_space *pcs = psh->params.ColorSpace; |
560 | 8.76k | int code = cos_dict_put_c_key_int(pscd, "/ShadingType", (int)type); |
561 | 8.76k | cos_value_t cs_value; |
562 | | |
563 | 8.76k | if (code < 0 || |
564 | 8.76k | (psh->params.AntiAlias && |
565 | 8.76k | (code = cos_dict_put_c_strings(pscd, "/AntiAlias", "true")) < 0) || |
566 | 8.76k | (code = pdf_color_space_named(pdev, pgs, &cs_value, ppranges, pcs, |
567 | 8.76k | &pdf_color_space_names, false, NULL, 0, false)) < 0 || |
568 | 8.76k | (code = cos_dict_put_c_key(pscd, "/ColorSpace", &cs_value)) < 0 |
569 | 8.76k | ) |
570 | 0 | return code; |
571 | 8.76k | if (psh->params.Background && !shfill) { |
572 | | /****** SCALE Background ******/ |
573 | 1 | code = cos_dict_put_c_key_floats(pdev, pscd, "/Background", |
574 | 1 | psh->params.Background->paint.values, |
575 | 1 | gs_color_space_num_components(pcs)); |
576 | 1 | if (code < 0) |
577 | 0 | return code; |
578 | 1 | } |
579 | 8.76k | if (psh->params.have_BBox) { |
580 | 0 | float bbox[4]; |
581 | |
|
582 | 0 | bbox[0] = psh->params.BBox.p.x; |
583 | 0 | bbox[1] = psh->params.BBox.p.y; |
584 | 0 | bbox[2] = psh->params.BBox.q.x; |
585 | 0 | bbox[3] = psh->params.BBox.q.y; |
586 | 0 | code = cos_dict_put_c_key_floats(pdev, pscd, "/BBox", bbox, 4); |
587 | 0 | if (code < 0) |
588 | 0 | return code; |
589 | 0 | } |
590 | 8.76k | return 0; |
591 | 8.76k | } |
592 | | |
593 | | /* Write an optional Function parameter. */ |
594 | | static int |
595 | | pdf_put_shading_Function(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_function_t *pfn, |
596 | | const gs_range_t *pranges) |
597 | 8.76k | { |
598 | 8.76k | int code = 0; |
599 | | |
600 | 8.76k | if (pfn != 0) { |
601 | 8.76k | cos_value_t fn_value; |
602 | | |
603 | 8.76k | if ((code = pdf_function_scaled(pdev, pfn, pranges, &fn_value)) >= 0) |
604 | 8.76k | code = cos_dict_put_c_key(pscd, "/Function", &fn_value); |
605 | 8.76k | } |
606 | 8.76k | return code; |
607 | 8.76k | } |
608 | | |
609 | | /* Write a linear (Axial / Radial) Shading. */ |
610 | | static int |
611 | | pdf_put_linear_shading(gx_device_pdf *pdev, cos_dict_t *pscd, const float *Coords, |
612 | | int num_coords, const float *Domain /*[2]*/, |
613 | | const gs_function_t *Function, |
614 | | const bool *Extend /*[2]*/, |
615 | | const gs_range_t *pranges) |
616 | 8.75k | { |
617 | 8.75k | int code = cos_dict_put_c_key_floats(pdev, pscd, "/Coords", Coords, num_coords); |
618 | | |
619 | 8.75k | if (code < 0 || |
620 | 8.75k | ((Domain[0] != 0 || Domain[1] != 1) && |
621 | 8.75k | (code = cos_dict_put_c_key_floats(pdev, pscd, "/Domain", Domain, 2)) < 0) || |
622 | 8.75k | (code = pdf_put_shading_Function(pdev, pscd, Function, pranges)) < 0 |
623 | 8.75k | ) |
624 | 0 | return code; |
625 | 8.75k | if (Extend[0] | Extend[1]) { |
626 | 8.75k | char extend_str[1 + 5 + 1 + 5 + 1 + 1]; /* [bool bool] */ |
627 | | |
628 | 8.75k | gs_snprintf(extend_str, sizeof(extend_str), "[%s %s]", |
629 | 8.75k | (Extend[0] ? "true" : "false"), |
630 | 8.75k | (Extend[1] ? "true" : "false")); |
631 | 8.75k | code = cos_dict_put_c_key_string(pscd, "/Extend", |
632 | 8.75k | (const byte *)extend_str, |
633 | 8.75k | strlen(extend_str)); |
634 | 8.75k | } |
635 | 8.75k | return code; |
636 | 8.75k | } |
637 | | |
638 | | /* Write a scalar (non-mesh) Shading. */ |
639 | | /* (Single-use procedure for readability.) */ |
640 | | static int |
641 | | pdf_put_scalar_shading(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_shading_t *psh, |
642 | | const gs_range_t *pranges) |
643 | 8.75k | { |
644 | 8.75k | int code; |
645 | | |
646 | 8.75k | switch (ShadingType(psh)) { |
647 | 0 | case shading_type_Function_based: { |
648 | 0 | const gs_shading_Fb_params_t *const params = |
649 | 0 | (const gs_shading_Fb_params_t *)&psh->params; |
650 | |
|
651 | 0 | if ((code = cos_dict_put_c_key_floats(pdev, pscd, "/Domain", params->Domain, 4)) < 0 || |
652 | 0 | (code = pdf_put_shading_Function(pdev, pscd, params->Function, pranges)) < 0 || |
653 | 0 | (code = cos_dict_put_matrix(pdev, pscd, "/Matrix", ¶ms->Matrix)) < 0 |
654 | 0 | ) |
655 | 0 | return code; |
656 | 0 | return 0; |
657 | 0 | } |
658 | 8.75k | case shading_type_Axial: { |
659 | 8.75k | const gs_shading_A_params_t *const params = |
660 | 8.75k | (const gs_shading_A_params_t *)&psh->params; |
661 | | |
662 | 8.75k | return pdf_put_linear_shading(pdev, pscd, params->Coords, 4, |
663 | 8.75k | params->Domain, params->Function, |
664 | 8.75k | params->Extend, pranges); |
665 | 0 | } |
666 | 0 | case shading_type_Radial: { |
667 | 0 | const gs_shading_R_params_t *const params = |
668 | 0 | (const gs_shading_R_params_t *)&psh->params; |
669 | |
|
670 | 0 | return pdf_put_linear_shading(pdev, pscd, params->Coords, 6, |
671 | 0 | params->Domain, params->Function, |
672 | 0 | params->Extend, pranges); |
673 | 0 | } |
674 | 0 | default: |
675 | 0 | return_error(gs_error_rangecheck); |
676 | 8.75k | } |
677 | 8.75k | } |
678 | | |
679 | | /* Add a floating point range to an array. */ |
680 | | static int |
681 | | pdf_array_add_real2(cos_array_t *pca, double lower, double upper) |
682 | 0 | { |
683 | 0 | int code = cos_array_add_real(pca, lower); |
684 | |
|
685 | 0 | if (code >= 0) |
686 | 0 | code = cos_array_add_real(pca, upper); |
687 | 0 | return code; |
688 | 0 | } |
689 | | |
690 | | /* Define a parameter structure for mesh data. */ |
691 | | typedef struct pdf_mesh_data_params_s { |
692 | | int num_points; |
693 | | int num_components; |
694 | | bool is_indexed; |
695 | | int rescale; /* If the co-ordinates won't fit into crappy Acrobat values, scale them here and in the pattern Matrix */ |
696 | | bool old_pdf; |
697 | | const float *Domain; /* iff Function */ |
698 | | const gs_range_t *ranges; |
699 | | } pdf_mesh_data_params_t; |
700 | | |
701 | | /* Put a clamped value into a data stream. num_bytes < sizeof(int). */ |
702 | | static void |
703 | | put_clamped(byte *p, double v, int num_bytes) |
704 | 0 | { |
705 | 0 | int limit = 1 << (num_bytes * 8); |
706 | 0 | int i, shift; |
707 | |
|
708 | 0 | if (v <= -limit) |
709 | 0 | i = -limit + 1; |
710 | 0 | else if (v >= limit) |
711 | 0 | i = limit - 1; |
712 | 0 | else |
713 | 0 | i = (int)v; |
714 | 0 | for (shift = (num_bytes - 1) * 8; shift >= 0; shift -= 8) |
715 | 0 | *p++ = (byte)(i >> shift); |
716 | 0 | } |
717 | | static inline void |
718 | | put_clamped_coord(byte *p, double v, int num_bytes, const pdf_mesh_data_params_t *pmdp) |
719 | 0 | { |
720 | 0 | if (pmdp->rescale != 1.0 || pmdp->old_pdf) { |
721 | 0 | v = v / pmdp->rescale; |
722 | 0 | put_clamped(p, PDFA_ENCODE_MESH_COORDINATE(v), num_bytes); |
723 | 0 | } else |
724 | 0 | put_clamped(p, ENCODE_MESH_COORDINATE(v), num_bytes); |
725 | 0 | } |
726 | | |
727 | | /* Convert floating-point mesh data to packed binary. */ |
728 | | /* BitsPerFlag = 8, BitsPerCoordinate = 24, BitsPerComponent = 16, */ |
729 | | /* scaling is as defined below. */ |
730 | | static int |
731 | | put_float_mesh_data(gx_device_pdf *pdev, cos_stream_t *pscs, shade_coord_stream_t *cs, |
732 | | int flag, int num_comps, const pdf_mesh_data_params_t *pmdp) |
733 | 0 | { |
734 | 0 | int num_points = pmdp->num_points; |
735 | 0 | byte b[1 + (3 + 3) * 16]; /* flag + x + y or c */ |
736 | 0 | gs_fixed_point pts[16]; |
737 | 0 | const float *domain = pmdp->Domain; |
738 | 0 | const gs_range_t *pranges = pmdp->ranges; |
739 | 0 | int i, code; |
740 | |
|
741 | 0 | b[0] = (byte)flag; /* may be -1 */ |
742 | 0 | if ((code = shade_next_coords(cs, pts, num_points)) < 0) |
743 | 0 | return code; |
744 | 0 | for (i = 0; i < num_points; ++i) { |
745 | 0 | put_clamped_coord(b + 1 + i * 6, fixed2float(pts[i].x), 3, pmdp); |
746 | 0 | put_clamped_coord(b + 4 + i * 6, fixed2float(pts[i].y), 3, pmdp); |
747 | 0 | } |
748 | 0 | if ((code = cos_stream_add_bytes(pdev, pscs, b + (flag < 0), |
749 | 0 | (flag >= 0) + num_points * 6)) < 0) |
750 | 0 | return code; |
751 | 0 | for (i = 0; i < pmdp->num_components; ++i) { |
752 | 0 | float c = 0; |
753 | 0 | double v; |
754 | |
|
755 | 0 | code = cs->get_decoded(cs, 0, NULL, &c); |
756 | 0 | if (code < 0) |
757 | 0 | return code; |
758 | | |
759 | 0 | if (pmdp->is_indexed) |
760 | 0 | v = ENCODE_MESH_COLOR_INDEX(c); |
761 | 0 | else { |
762 | | /* |
763 | | * We don't rescale stream data values, only the Decode ranges. |
764 | | * (We do have to rescale data values from an array, unless |
765 | | * they are the input parameter for a Function.) |
766 | | * This makes everything come out as it should. |
767 | | */ |
768 | 0 | double vmin, vmax; |
769 | |
|
770 | 0 | if (domain) |
771 | 0 | vmin = domain[2 * i], vmax = domain[2 * i + 1]; |
772 | 0 | else |
773 | 0 | vmin = 0.0, vmax = 1.0; |
774 | 0 | if (pranges) { |
775 | 0 | double base = pranges[i % num_comps].rmin, factor = pranges[i % num_comps].rmax - base; |
776 | |
|
777 | 0 | vmin = vmin * factor + base; |
778 | 0 | vmax = vmax * factor + base; |
779 | 0 | } |
780 | 0 | v = ENCODE_MESH_COMPONENT(c, vmin, vmax); |
781 | 0 | } |
782 | 0 | put_clamped(b, v, 2); |
783 | 0 | if ((code = cos_stream_add_bytes(pdev, pscs, b, 2)) < 0) |
784 | 0 | return code; |
785 | 0 | } |
786 | 0 | return 0; |
787 | 0 | } |
788 | | |
789 | | /* Write a mesh Shading. */ |
790 | | static int |
791 | | pdf_put_mesh_shading(gx_device_pdf *pdev, cos_stream_t *pscs, const gs_shading_t *psh, |
792 | | const gs_range_t *pranges, int *rescale) |
793 | 11 | { |
794 | 11 | cos_dict_t *const pscd = cos_stream_dict(pscs); |
795 | 11 | gs_color_space *pcs = psh->params.ColorSpace; |
796 | 11 | const gs_shading_mesh_params_t *const pmp = |
797 | 11 | (const gs_shading_mesh_params_t *)&psh->params; |
798 | 11 | int code, code1; |
799 | 11 | int bits_per_coordinate, bits_per_component, bits_per_flag; |
800 | 11 | int num_comp; |
801 | 11 | bool from_array = data_source_is_array(pmp->DataSource); |
802 | 11 | pdf_mesh_data_params_t data_params; |
803 | 11 | shade_coord_stream_t cs; |
804 | 11 | gs_matrix_fixed ctm_ident; |
805 | 11 | int flag; |
806 | | |
807 | 11 | if (pmp->Function) { |
808 | 6 | data_params.Domain = 0; |
809 | 6 | num_comp = 1; |
810 | 6 | } else { |
811 | 5 | data_params.Domain = (pmp->Decode != 0 ? pmp->Decode + 4 : NULL); |
812 | 5 | num_comp = gs_color_space_num_components(pcs); |
813 | 5 | } |
814 | 11 | data_params.ranges = pranges; |
815 | 11 | data_params.rescale = 1; |
816 | | |
817 | | |
818 | | /* Write parameters common to all mesh Shadings. */ |
819 | 11 | shade_next_init(&cs, pmp, NULL); |
820 | 11 | if (from_array) { |
821 | 0 | cos_array_t *pca = cos_array_alloc(pdev, "pdf_put_mesh_shading"); |
822 | 0 | int i; |
823 | |
|
824 | 0 | if (pca == 0) |
825 | 0 | return_error(gs_error_VMerror); |
826 | 0 | for (i = 0; i < 2; ++i) { |
827 | 0 | if (pdev->CompatibilityLevel < 1.5) { |
828 | 0 | if ((code = pdf_array_add_real2(pca, PDFA_MIN_MESH_COORDINATE, |
829 | 0 | PDFA_MAX_MESH_COORDINATE)) < 0) |
830 | 0 | return code; |
831 | 0 | } |
832 | 0 | else { |
833 | 0 | if ((code = pdf_array_add_real2(pca, MIN_MESH_COORDINATE, |
834 | 0 | MAX_MESH_COORDINATE)) < 0) |
835 | 0 | return code; |
836 | 0 | } |
837 | 0 | } |
838 | 0 | data_params.is_indexed = false; |
839 | 0 | if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) { |
840 | 0 | data_params.is_indexed = true; |
841 | 0 | if ((code = pdf_array_add_real2(pca, MIN_MESH_COLOR_INDEX, |
842 | 0 | MAX_MESH_COLOR_INDEX)) < 0) |
843 | 0 | return code; |
844 | 0 | } else { |
845 | 0 | for (i = 0; i < num_comp; ++i) { |
846 | 0 | double rmin, rmax; |
847 | |
|
848 | 0 | if (pmp->Function || pranges || data_params.Domain == 0) { |
849 | 0 | if (pmp->Function && pmp->Function->params.Domain != 0) { |
850 | 0 | rmin = pmp->Function->params.Domain[0], rmax = pmp->Function->params.Domain[1]; |
851 | 0 | } else { |
852 | 0 | rmin = 0.0, rmax = 1.0; |
853 | 0 | } |
854 | 0 | } |
855 | 0 | else |
856 | 0 | rmin = data_params.Domain[2 * i], |
857 | 0 | rmax = data_params.Domain[2 * i + 1]; |
858 | 0 | if ((code = |
859 | 0 | pdf_array_add_real2(pca, rmin, rmax)) < 0) |
860 | 0 | return code; |
861 | 0 | } |
862 | 0 | } |
863 | 0 | code = cos_dict_put_c_key_object(pscd, "/Decode", COS_OBJECT(pca)); |
864 | 0 | if (code < 0) |
865 | 0 | return code; |
866 | 0 | bits_per_coordinate = 24; |
867 | 0 | bits_per_component = 16; |
868 | 0 | bits_per_flag = 8; |
869 | 0 | gs_make_identity((gs_matrix *)&ctm_ident); |
870 | 0 | ctm_ident.tx_fixed = ctm_ident.ty_fixed = 0; |
871 | 0 | ctm_ident.txy_fixed_valid = true; |
872 | 0 | cs.pctm = &ctm_ident; |
873 | 0 | if (pmp->Function) |
874 | 0 | data_params.ranges = 0; /* don't scale function parameter */ |
875 | 11 | } else { |
876 | | /****** SCALE Decode ******/ |
877 | 11 | code = cos_dict_put_c_key_floats(pdev, pscd, "/Decode", pmp->Decode, |
878 | 11 | 4 + num_comp * 2); |
879 | 11 | if (code >= 0) |
880 | 11 | code = cos_stream_add_stream_contents(pdev, pscs, cs.s); |
881 | 11 | bits_per_coordinate = pmp->BitsPerCoordinate; |
882 | 11 | bits_per_component = pmp->BitsPerComponent; |
883 | 11 | bits_per_flag = -1; |
884 | 11 | } |
885 | 11 | if (code < 0 || |
886 | 11 | (code = pdf_put_shading_Function(pdev, pscd, pmp->Function, pranges)) < 0 || |
887 | 11 | (code = cos_dict_put_c_key_int(pscd, "/BitsPerCoordinate", |
888 | 11 | bits_per_coordinate)) < 0 || |
889 | 11 | (code = cos_dict_put_c_key_int(pscd, "/BitsPerComponent", |
890 | 11 | bits_per_component)) < 0 |
891 | 11 | ) |
892 | 0 | return code; |
893 | | |
894 | 11 | if (from_array && pdev->CompatibilityLevel < 1.5 ) { |
895 | 0 | float min_x, max_x, min_y, max_y, z; |
896 | 0 | int i = 0, j, num_points = 1, num_components = 1; |
897 | 0 | float c = 0; |
898 | 0 | float x, y; |
899 | | |
900 | | /* |
901 | | * Because of the Acrobat Reader limitation noted in gdevpdfx.h, |
902 | | * we must limit coordinate values to 16 bits. We no longer |
903 | | * attempt to support Acrobat 1.3 and below (which only permit 14 bits). |
904 | | */ |
905 | 0 | min_x = min_y = PDFA_MIN_MESH_COORDINATE; |
906 | 0 | max_x = max_y = PDFA_MAX_MESH_COORDINATE; |
907 | |
|
908 | 0 | switch(ShadingType(psh)){ |
909 | 0 | case shading_type_Tensor_product_patch: |
910 | 0 | while ((flag = shade_next_flag(&cs, 0)) >= 0){ |
911 | 0 | num_points = (flag == 0 ? 16 : 12); |
912 | 0 | num_components = num_comp * (flag == 0 ? 4 : 2); |
913 | |
|
914 | 0 | for (j = 0; j < num_points;j++) { |
915 | 0 | code = cs.get_decoded(&cs, 0, NULL, &x); |
916 | 0 | if (code < 0) |
917 | 0 | break; |
918 | 0 | code = cs.get_decoded(&cs, 0, NULL, &y); |
919 | 0 | if (code < 0) |
920 | 0 | break; |
921 | 0 | for (i = 0; i < num_components; ++i) { |
922 | 0 | code = cs.get_decoded(&cs, 0, NULL, &c); |
923 | 0 | if (code < 0) |
924 | 0 | break; |
925 | 0 | } |
926 | 0 | if (x < min_x) |
927 | 0 | min_x = x; |
928 | 0 | if (y < min_y) |
929 | 0 | min_y = y; |
930 | 0 | if (x > max_x) |
931 | 0 | max_x = x; |
932 | 0 | if (y > max_y) |
933 | 0 | max_y = y; |
934 | 0 | } |
935 | 0 | } |
936 | 0 | break; |
937 | 0 | case shading_type_Coons_patch: |
938 | 0 | while ((flag = shade_next_flag(&cs, 0)) >= 0){ |
939 | 0 | num_points = (flag == 0 ? 12 : 8); |
940 | 0 | num_components = num_comp * (flag == 0 ? 4 : 2); |
941 | |
|
942 | 0 | for (j = 0; j < num_points;j++) { |
943 | 0 | code = cs.get_decoded(&cs, 0, NULL, &x); |
944 | 0 | if (code < 0) |
945 | 0 | break; |
946 | 0 | code = cs.get_decoded(&cs, 0, NULL, &y); |
947 | 0 | if (code < 0) |
948 | 0 | break; |
949 | 0 | for (i = 0; i < num_components; ++i) { |
950 | 0 | code = cs.get_decoded(&cs, 0, NULL, &c); |
951 | 0 | if (code < 0) |
952 | 0 | break; |
953 | 0 | } |
954 | 0 | if (x < min_x) |
955 | 0 | min_x = x; |
956 | 0 | if (y < min_y) |
957 | 0 | min_y = y; |
958 | 0 | if (x > max_x) |
959 | 0 | max_x = x; |
960 | 0 | if (y > max_y) |
961 | 0 | max_y = y; |
962 | 0 | } |
963 | 0 | } |
964 | 0 | break; |
965 | 0 | case shading_type_Free_form_Gouraud_triangle: |
966 | 0 | { |
967 | 0 | while ((flag = shade_next_flag(&cs, 0)) >= 0){ |
968 | 0 | code = cs.get_decoded(&cs, 0, NULL, &x); |
969 | 0 | if (code < 0) |
970 | 0 | break; |
971 | 0 | code = cs.get_decoded(&cs, 0, NULL, &y); |
972 | 0 | if (code < 0) |
973 | 0 | break; |
974 | 0 | for (i = 0; i < num_comp; ++i) { |
975 | 0 | code = cs.get_decoded(&cs, 0, NULL, &c); |
976 | 0 | if (code < 0) |
977 | 0 | break; |
978 | 0 | } |
979 | 0 | if (x < min_x) |
980 | 0 | min_x = x; |
981 | 0 | if (y < min_y) |
982 | 0 | min_y = y; |
983 | 0 | if (x > max_x) |
984 | 0 | max_x = x; |
985 | 0 | if (y > max_y) |
986 | 0 | max_y = y; |
987 | 0 | } |
988 | 0 | } |
989 | 0 | break; |
990 | 0 | case shading_type_Lattice_form_Gouraud_triangle: |
991 | 0 | { |
992 | 0 | while (!seofp(cs.s)) { |
993 | 0 | code = cs.get_decoded(&cs, 0, NULL, &x); |
994 | 0 | if (code < 0) |
995 | 0 | break; |
996 | 0 | code = cs.get_decoded(&cs, 0, NULL, &y); |
997 | 0 | if (code < 0) |
998 | 0 | break; |
999 | 0 | for (i = 0; i < num_comp; ++i) { |
1000 | 0 | code = cs.get_decoded(&cs, 0, NULL, &c); |
1001 | 0 | if (code < 0) |
1002 | 0 | break; |
1003 | 0 | } |
1004 | 0 | if (x < min_x) |
1005 | 0 | min_x = x; |
1006 | 0 | if (y < min_y) |
1007 | 0 | min_y = y; |
1008 | 0 | if (x > max_x) |
1009 | 0 | max_x = x; |
1010 | 0 | if (y > max_y) |
1011 | 0 | max_y = y; |
1012 | 0 | } |
1013 | 0 | } |
1014 | 0 | break; |
1015 | 0 | default: |
1016 | 0 | break; |
1017 | 0 | } |
1018 | 0 | s_init(&cs.ds, NULL); |
1019 | 0 | sread_string(&cs.ds, pmp->DataSource.data.str.data, |
1020 | 0 | pmp->DataSource.data.str.size); |
1021 | 0 | cs.s = &cs.ds; |
1022 | |
|
1023 | 0 | *rescale = (int)ceil(min_x / PDFA_MIN_MESH_COORDINATE); |
1024 | 0 | z = ceil(min_y / PDFA_MIN_MESH_COORDINATE); |
1025 | 0 | if (z > *rescale) |
1026 | 0 | *rescale = (int)z; |
1027 | 0 | z = ceil(max_x / PDFA_MAX_MESH_COORDINATE); |
1028 | 0 | if (z > *rescale) |
1029 | 0 | *rescale = (int)z; |
1030 | 0 | z = ceil(max_y / PDFA_MAX_MESH_COORDINATE); |
1031 | 0 | if (z > *rescale) |
1032 | 0 | *rescale = (int)z; |
1033 | 0 | data_params.rescale = *rescale; |
1034 | 0 | data_params.old_pdf = 1; |
1035 | 0 | } else |
1036 | 11 | data_params.old_pdf = 0; |
1037 | | |
1038 | 11 | switch (ShadingType(psh)) { |
1039 | 3 | case shading_type_Free_form_Gouraud_triangle: { |
1040 | 3 | const gs_shading_FfGt_params_t *const params = |
1041 | 3 | (const gs_shading_FfGt_params_t *)pmp; |
1042 | | |
1043 | 3 | data_params.num_points = 1; |
1044 | 3 | data_params.num_components = num_comp; |
1045 | 3 | if (from_array) { |
1046 | 0 | while ((flag = shade_next_flag(&cs, 0)) >= 0) |
1047 | 0 | if ((code = put_float_mesh_data(pdev, pscs, &cs, flag, |
1048 | 0 | num_comp, &data_params)) < 0) |
1049 | 0 | return code; |
1050 | 0 | if (!seofp(cs.s)) |
1051 | 0 | code = gs_note_error(gs_error_rangecheck); |
1052 | 0 | } |
1053 | 3 | if (bits_per_flag < 0) |
1054 | 3 | bits_per_flag = params->BitsPerFlag; |
1055 | 3 | break; |
1056 | 3 | } |
1057 | 6 | case shading_type_Lattice_form_Gouraud_triangle: { |
1058 | 6 | const gs_shading_LfGt_params_t *const params = |
1059 | 6 | (const gs_shading_LfGt_params_t *)pmp; |
1060 | | |
1061 | 6 | data_params.num_points = 1; |
1062 | 6 | data_params.num_components = num_comp; |
1063 | 6 | if (from_array) |
1064 | 0 | while (!seofp(cs.s)) |
1065 | 0 | if ((code = put_float_mesh_data(pdev, pscs, &cs, -1, |
1066 | 0 | num_comp, &data_params)) < 0) |
1067 | 0 | return code; |
1068 | 6 | code = cos_dict_put_c_key_int(pscd, "/VerticesPerRow", |
1069 | 6 | params->VerticesPerRow); |
1070 | 6 | return code; |
1071 | 6 | } |
1072 | 0 | case shading_type_Coons_patch: { |
1073 | 0 | const gs_shading_Cp_params_t *const params = |
1074 | 0 | (const gs_shading_Cp_params_t *)pmp; |
1075 | |
|
1076 | 0 | if (from_array) { |
1077 | 0 | while ((flag = shade_next_flag(&cs, 0)) >= 0) { |
1078 | 0 | data_params.num_points = (flag == 0 ? 12 : 8); |
1079 | 0 | data_params.num_components = num_comp * (flag == 0 ? 4 : 2); |
1080 | 0 | if ((code = put_float_mesh_data(pdev, pscs, &cs, flag, |
1081 | 0 | num_comp, &data_params)) < 0) |
1082 | 0 | return code; |
1083 | 0 | } |
1084 | 0 | if (!seofp(cs.s)) |
1085 | 0 | code = gs_note_error(gs_error_rangecheck); |
1086 | 0 | } |
1087 | 0 | if (bits_per_flag < 0) |
1088 | 0 | bits_per_flag = params->BitsPerFlag; |
1089 | 0 | break; |
1090 | 0 | } |
1091 | 2 | case shading_type_Tensor_product_patch: { |
1092 | 2 | const gs_shading_Tpp_params_t *const params = |
1093 | 2 | (const gs_shading_Tpp_params_t *)pmp; |
1094 | | |
1095 | 2 | if (from_array) { |
1096 | 0 | while ((flag = shade_next_flag(&cs, 0)) >= 0) { |
1097 | 0 | data_params.num_points = (flag == 0 ? 16 : 12); |
1098 | 0 | data_params.num_components = num_comp * (flag == 0 ? 4 : 2); |
1099 | 0 | if ((code = put_float_mesh_data(pdev, pscs, &cs, flag, num_comp, |
1100 | 0 | &data_params)) < 0) |
1101 | 0 | return code; |
1102 | 0 | } |
1103 | 0 | if (!seofp(cs.s)) |
1104 | 0 | code = gs_note_error(gs_error_rangecheck); |
1105 | 0 | } |
1106 | 2 | if (bits_per_flag < 0) |
1107 | 2 | bits_per_flag = params->BitsPerFlag; |
1108 | 2 | break; |
1109 | 2 | } |
1110 | 0 | default: |
1111 | 0 | return_error(gs_error_rangecheck); |
1112 | 11 | } |
1113 | 5 | code1 = cos_dict_put_c_key_int(pscd, "/BitsPerFlag", bits_per_flag); |
1114 | 5 | if (code1 < 0) |
1115 | 0 | return code1; |
1116 | 5 | return code; |
1117 | 5 | } |
1118 | | |
1119 | | /* Write a PatternType 2 (shading pattern) color. */ |
1120 | | int |
1121 | | pdf_put_pattern2(gx_device_pdf *pdev, const gs_gstate * pgs, const gx_drawing_color *pdc, |
1122 | | const psdf_set_color_commands_t *ppscc, |
1123 | | pdf_resource_t **ppres) |
1124 | 8.76k | { |
1125 | 8.76k | const gs_pattern2_instance_t *pinst = |
1126 | 8.76k | (gs_pattern2_instance_t *)pdc->ccolor.pattern; |
1127 | 8.76k | const gs_shading_t *psh = pinst->templat.Shading; |
1128 | 8.76k | cos_value_t v; |
1129 | 8.76k | pdf_resource_t *pres; |
1130 | 8.76k | pdf_resource_t *psres; |
1131 | 8.76k | cos_dict_t *pcd; |
1132 | 8.76k | cos_object_t *psco; |
1133 | 8.76k | const gs_range_t *pranges; |
1134 | 8.76k | int code = pdf_cs_Pattern_colored(pdev, &v); |
1135 | 8.76k | int code1 = 0, rescale = 1; |
1136 | 8.76k | gs_matrix smat; |
1137 | 8.76k | gs_point dist; |
1138 | | |
1139 | 8.76k | if (code < 0) |
1140 | 0 | return code; |
1141 | 8.76k | code = pdf_alloc_resource(pdev, resourcePattern, gs_no_id, ppres, -1); |
1142 | 8.76k | if (code < 0) |
1143 | 0 | return code; |
1144 | 8.76k | pres = *ppres; |
1145 | 8.76k | cos_become(pres->object, cos_type_dict); |
1146 | 8.76k | pcd = (cos_dict_t *)pres->object; |
1147 | 8.76k | code = pdf_alloc_resource(pdev, resourceShading, gs_no_id, &psres, -1); |
1148 | 8.76k | if (code < 0) |
1149 | 0 | return code; |
1150 | 8.76k | psco = psres->object; |
1151 | 8.76k | if (ShadingType(psh) >= 4) { |
1152 | | /* Shading has an associated data stream. */ |
1153 | 11 | cos_become(psco, cos_type_stream); |
1154 | 11 | code = pdf_put_shading_common(pdev, cos_stream_dict((cos_stream_t *)psco), pgs, |
1155 | 11 | psh, pinst->shfill, &pranges); |
1156 | 11 | if (code >= 0) |
1157 | 11 | code1 = pdf_put_mesh_shading(pdev, (cos_stream_t *)psco, psh, pranges, &rescale); |
1158 | 0 | else |
1159 | | /* We won't use this shading, we fall back because we couldn't write it */ |
1160 | 0 | psres->where_used = 0; |
1161 | 8.75k | } else { |
1162 | 8.75k | cos_become(psco, cos_type_dict); |
1163 | 8.75k | code = pdf_put_shading_common(pdev, (cos_dict_t *)psco, pgs, psh, pinst->shfill, &pranges); |
1164 | 8.75k | if (code >= 0) |
1165 | 8.75k | code1 = pdf_put_scalar_shading(pdev, (cos_dict_t *)psco, psh, pranges); |
1166 | 0 | else |
1167 | | /* We won't use this shading, we fall back because we couldn't write it */ |
1168 | 0 | psres->where_used = 0; |
1169 | 8.75k | } |
1170 | 8.76k | if (psres->where_used) { |
1171 | 8.76k | code = pdf_substitute_resource(pdev, &psres, resourceShading, NULL, false); |
1172 | 8.76k | if (code < 0) |
1173 | 0 | return code; |
1174 | 8.76k | psco = psres->object; |
1175 | 8.76k | psres->where_used |= pdev->used_mask; |
1176 | 8.76k | } |
1177 | | /* |
1178 | | * In PDF, the Matrix is the transformation from the pattern space to |
1179 | | * the *default* user coordinate space, not the current space. |
1180 | | * NB. For a form the default space is the parent. This means that when a |
1181 | | * form is nested inside a form, the default space is the space of the |
1182 | | * first form, and therefore we do *not* remove the resolution scaling. |
1183 | | */ |
1184 | 8.76k | gs_currentmatrix(pinst->saved, &smat); |
1185 | 8.76k | { |
1186 | 8.76k | double xscale = 1.0, yscale = 1.0; |
1187 | 8.76k | if (pdev->FormDepth == 0) { |
1188 | 637 | xscale = 72.0 / pdev->HWResolution[0]; |
1189 | 637 | yscale = 72.0 / pdev->HWResolution[1]; |
1190 | 637 | } |
1191 | | |
1192 | 8.76k | smat.xx *= xscale, smat.yx *= xscale, smat.tx *= xscale; |
1193 | 8.76k | smat.xy *= yscale, smat.yy *= yscale, smat.ty *= yscale; |
1194 | | |
1195 | 8.76k | if (rescale != 1) { |
1196 | 0 | smat.xx *= rescale, smat.yx *= rescale; |
1197 | 0 | smat.xy *= rescale, smat.yy *= rescale; |
1198 | 0 | } |
1199 | 8.76k | } |
1200 | | |
1201 | | /* Bug #697451, if we emit a PDF with a type 2 Pattern where the |
1202 | | * Matrix is degenerate, Acrobat throws an error and aborts the |
1203 | | * page content stream. Distiller refuses to embed the shfill, |
1204 | | * it silently (!) ignores the problem. So here we test to see |
1205 | | * if the CTM is degenerate, if it is, replace it with the |
1206 | | * smallest Matrix we can. |
1207 | | */ |
1208 | 8.76k | code = gs_distance_transform_inverse(1, 1, &smat, &dist); |
1209 | 8.76k | if (code == gs_error_undefinedresult) { |
1210 | 28 | smat.xx = smat.yy = 0.00000001f; |
1211 | 28 | smat.xy = smat.yx = smat.tx = smat.ty = 0; |
1212 | 28 | code = 0; |
1213 | 28 | } |
1214 | | |
1215 | 8.76k | if (code < 0 || |
1216 | 8.76k | (code = cos_dict_put_c_key_int(pcd, "/PatternType", 2)) < 0 || |
1217 | 8.76k | (code = cos_dict_put_c_key_object(pcd, "/Shading", psco)) < 0 || |
1218 | 8.76k | (code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat)) < 0 |
1219 | | /****** ExtGState ******/ |
1220 | 8.76k | ) |
1221 | 0 | return code; |
1222 | 8.76k | code = pdf_substitute_resource(pdev, &pres, resourcePattern, NULL, false); |
1223 | 8.76k | if (code < 0) |
1224 | 0 | return code; |
1225 | 8.76k | pres->where_used |= pdev->used_mask; |
1226 | 8.76k | *ppres = pres; |
1227 | | |
1228 | 8.76k | cos_value_write(&v, pdev); |
1229 | 8.76k | pprints1(pdev->strm, " %s\n", ppscc->setcolorspace); |
1230 | 8.76k | return code1; |
1231 | 8.76k | } |
1232 | | |
1233 | | /* |
1234 | | Include color space. |
1235 | | */ |
1236 | | int |
1237 | | gdev_pdf_include_color_space(gx_device *dev, gs_color_space *cspace, const byte *res_name, int name_length) |
1238 | 0 | { |
1239 | 0 | gx_device_pdf * pdev = (gx_device_pdf *)dev; |
1240 | 0 | cos_value_t cs_value; |
1241 | |
|
1242 | 0 | return pdf_color_space_named(pdev, NULL, &cs_value, NULL, cspace, |
1243 | 0 | &pdf_color_space_names, true, res_name, name_length, false); |
1244 | 0 | } |