/src/ghostpdl/devices/vector/gdevpdfb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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 | | /* Low-level bitmap image handling for PDF-writing driver */ |
18 | | #include "string_.h" |
19 | | #include "gx.h" |
20 | | #include "gserrors.h" |
21 | | #include "gdevpdfx.h" |
22 | | #include "gdevpdfg.h" |
23 | | #include "gdevpdfo.h" /* for data stream */ |
24 | | #include "gxcspace.h" |
25 | | #include "gxdcolor.h" |
26 | | #include "gxpcolor.h" |
27 | | #include "gxhldevc.h" |
28 | | #include "gxchar.h" |
29 | | #include "gdevpdtf.h" /* Required to include gdevpdti.h */ |
30 | | #include "gdevpdti.h" /* For pdf_charproc_x_offset */ |
31 | | #include "gsptype1.h" |
32 | | #include "gdevpdtt.h" |
33 | | |
34 | | /* We need this color space type for constructing temporary color spaces. */ |
35 | | extern const gs_color_space_type gs_color_space_type_Indexed; |
36 | | |
37 | | /* ---------------- Utilities ---------------- */ |
38 | | |
39 | | /* Fill in the image parameters for a bitmap image. */ |
40 | | static void |
41 | | pdf_make_bitmap_image(gs_image_t * pim, int x, int y, int w, int h) |
42 | 1.81M | { |
43 | 1.81M | pim->Width = w; |
44 | 1.81M | pim->Height = h; |
45 | 1.81M | pdf_make_bitmap_matrix(&pim->ImageMatrix, x, y, w, h, h); |
46 | 1.81M | } |
47 | | |
48 | | /* ---------------- Driver procedures ---------------- */ |
49 | | |
50 | | /* Copy a mask bitmap. for_pattern = -1 means put the image in-line, */ |
51 | | /* 1 means put the image in a resource. */ |
52 | | static int |
53 | | pdf_copy_mask_data(gx_device_pdf * pdev, const byte * base, int sourcex, |
54 | | int raster, gx_bitmap_id id, int x, int y, int w, int h, |
55 | | gs_image_t *pim, pdf_image_writer *piw, |
56 | | int for_pattern) |
57 | 0 | { |
58 | 0 | uint64_t nbytes; |
59 | 0 | int code; |
60 | 0 | const byte *row_base; |
61 | 0 | int row_step; |
62 | 0 | bool in_line; |
63 | |
|
64 | 0 | gs_image_t_init_mask(pim, true); |
65 | 0 | pdf_make_bitmap_image(pim, x, y, w, h); |
66 | 0 | nbytes = ((uint64_t)w * h + 7) / 8; |
67 | |
|
68 | 0 | if (for_pattern) { |
69 | | /* |
70 | | * Patterns must be emitted in order of increasing user Y, i.e., |
71 | | * the opposite of PDF's standard image order. |
72 | | */ |
73 | 0 | row_base = base + (h - 1) * raster; |
74 | 0 | row_step = -raster; |
75 | 0 | in_line = for_pattern < 0; |
76 | 0 | } else { |
77 | 0 | row_base = base; |
78 | 0 | row_step = raster; |
79 | 0 | in_line = nbytes < pdev->MaxInlineImageSize; |
80 | 0 | pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0); |
81 | | /* |
82 | | * Check whether we've already made an XObject resource for this |
83 | | * image. |
84 | | */ |
85 | 0 | if (id != gx_no_bitmap_id) { |
86 | 0 | piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id); |
87 | 0 | if (piw->pres) |
88 | 0 | return 0; |
89 | 0 | } |
90 | 0 | } |
91 | | /* |
92 | | * We have to be able to control whether to put Pattern images in line, |
93 | | * to avoid trying to create an XObject resource while we're in the |
94 | | * middle of writing a Pattern resource. |
95 | | */ |
96 | 0 | if (for_pattern < 0) |
97 | 0 | stream_puts(pdev->strm, "q "); |
98 | 0 | pdf_image_writer_init(piw); |
99 | 0 | pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel; |
100 | 0 | if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 || |
101 | 0 | (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev, |
102 | 0 | &piw->binary[0], |
103 | 0 | (gs_pixel_image_t *)pim, in_line)) < 0 || |
104 | 0 | (code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim, |
105 | 0 | NULL, 0)) < 0 |
106 | 0 | ) |
107 | 0 | return code; |
108 | 0 | pdf_copy_mask_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h, 0); |
109 | 0 | pdf_end_image_binary(pdev, piw, piw->height); |
110 | 0 | return pdf_end_write_image(pdev, piw); |
111 | 0 | } |
112 | | |
113 | | static void |
114 | | set_image_color(gx_device_pdf *pdev, gx_color_index c) |
115 | 0 | { |
116 | 0 | pdf_set_pure_color(pdev, c, &pdev->saved_fill_color, |
117 | 0 | &pdev->fill_used_process_color, |
118 | 0 | &psdf_set_fill_color_commands); |
119 | 0 | if (!pdev->HaveStrokeColor) |
120 | 0 | pdf_set_pure_color(pdev, c, &pdev->saved_stroke_color, |
121 | 0 | &pdev->stroke_used_process_color, |
122 | 0 | &psdf_set_stroke_color_commands); |
123 | 0 | } |
124 | | |
125 | | static int |
126 | | pdf_copy_mono(gx_device_pdf *pdev, |
127 | | const byte *base, int sourcex, int raster, gx_bitmap_id id, |
128 | | int x, int y, int w, int h, gx_color_index zero, |
129 | | gx_color_index one, const gx_clip_path *pcpath) |
130 | 1.81M | { |
131 | 1.81M | int code; |
132 | 1.81M | gs_color_space *pcs = NULL; |
133 | 1.81M | cos_value_t cs_value; |
134 | 1.81M | cos_value_t *pcsvalue; |
135 | 1.81M | byte palette[ARCH_SIZEOF_COLOR_INDEX * 2]; |
136 | 1.81M | gs_image_t image; |
137 | 1.81M | pdf_image_writer writer; |
138 | 1.81M | pdf_stream_position_t ipos; |
139 | 1.81M | pdf_resource_t *pres = 0; |
140 | 1.81M | byte invert = 0; |
141 | 1.81M | bool in_line = false, char_proc_begun = false; |
142 | 1.81M | gs_show_enum *show_enum = (gs_show_enum *)pdev->pte; |
143 | 1.81M | int x_offset, y_offset; |
144 | 1.81M | double width; |
145 | | |
146 | | /* Update clipping. */ |
147 | 1.81M | if (pdf_must_put_clip_path(pdev, pcpath)) { |
148 | 30 | code = pdf_open_page(pdev, PDF_IN_STREAM); |
149 | 30 | if (code < 0) |
150 | 0 | return code; |
151 | 30 | code = pdf_put_clip_path(pdev, pcpath); |
152 | 30 | if (code < 0) |
153 | 0 | return code; |
154 | 30 | } |
155 | | /* We have 3 cases: mask, inverse mask, and solid. */ |
156 | 1.81M | if (zero == gx_no_color_index) { |
157 | 1.81M | if (one == gx_no_color_index) |
158 | 0 | return 0; |
159 | | /* If a mask has an id, assume it's a character. */ |
160 | 1.81M | if (id != gx_no_bitmap_id && sourcex == 0 && show_enum) { |
161 | 1.81M | pdf_char_proc_t *pcp; |
162 | | |
163 | 1.81M | if (show_enum->use_wxy_float) |
164 | 0 | pdev->char_width.x = show_enum->wxy_float.x; |
165 | 1.81M | else |
166 | 1.81M | pdev->char_width.x = fixed2float(show_enum->wxy.x); |
167 | 1.81M | pres = pdf_find_resource_by_gs_id(pdev, resourceCharProc, id); |
168 | 1.81M | if (pres == 0) { /* Define the character in an embedded font. */ |
169 | 134k | gs_image_t_init_mask(&image, false); |
170 | 134k | invert = 0xff; |
171 | 134k | x_offset = x - (int)show_enum->pgs->current_point.x; |
172 | 134k | y_offset = y - (int)show_enum->pgs->current_point.y; |
173 | 134k | x -= x_offset; |
174 | 134k | y -= y_offset; |
175 | 134k | y -= h; |
176 | 134k | pdf_make_bitmap_image(&image, x, y, w, h); |
177 | | /* |
178 | | * The Y axis of the text matrix is inverted, |
179 | | * so we need to negate the Y offset appropriately. |
180 | | */ |
181 | 134k | code = pdf_begin_char_proc(pdev, w, h, 0, y_offset, x_offset, id, |
182 | 134k | &pcp, &ipos); |
183 | 134k | if (code < 0) |
184 | 0 | return code; |
185 | 134k | char_proc_begun = true; |
186 | 134k | y_offset = -y_offset; |
187 | 134k | width = psdf_round(pdev->char_width.x, 100, 10); /* See |
188 | | pdf_write_Widths about rounding. We need to provide |
189 | | a compatible data for Tj. */ |
190 | 134k | pprintg1(pdev->strm, "%g ", width); |
191 | 134k | pprintd4(pdev->strm, "0 %d %d %d %d d1\n", x_offset, -h + y_offset, w + x_offset, y_offset); |
192 | 134k | pprintd4(pdev->strm, "%d 0 0 %d %d %d cm\n", w, h, x_offset, |
193 | 134k | -h + y_offset); |
194 | 134k | pdf_image_writer_init(&writer); |
195 | 134k | code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, true); |
196 | 134k | if (code < 0) |
197 | 0 | goto fail; |
198 | 134k | pres = (pdf_resource_t *) pcp; |
199 | 134k | goto wr; |
200 | 1.67M | } else if (pdev->pte != NULL) { |
201 | | /* We're under pdf_text_process. It set a high level color. */ |
202 | 1.67M | } else |
203 | 0 | set_image_color(pdev, one); |
204 | 1.67M | pcp = (pdf_char_proc_t *) pres; |
205 | 1.67M | x -= pdf_charproc_x_offset(pcp); |
206 | 1.67M | y -= pdf_charproc_y_offset(pcp); |
207 | 1.67M | y -= h; |
208 | 1.67M | pdf_make_bitmap_image(&image, x, y, w, h); |
209 | 1.67M | goto rx; |
210 | 1.81M | } |
211 | 3.15k | if (pdev->pte == NULL) |
212 | 0 | set_image_color(pdev, one); |
213 | 3.15k | gs_image_t_init_mask(&image, false); |
214 | 3.15k | invert = 0xff; |
215 | 3.15k | } else if (one == gx_no_color_index) { |
216 | 0 | gs_image_t_init_mask(&image, false); |
217 | 0 | if (pdev->pte == NULL) |
218 | 0 | set_image_color(pdev, zero); |
219 | 0 | } else if (zero == pdev->black && one == pdev->white) { |
220 | 0 | pcs = gs_cspace_new_DeviceGray(pdev->memory); |
221 | 0 | if (pcs == NULL) { |
222 | 0 | code = gs_note_error(gs_error_VMerror); |
223 | 0 | goto fail; |
224 | 0 | } |
225 | 0 | gs_image_t_init(&image, pcs); |
226 | 0 | } else if (zero == pdev->white && one == pdev->black) { |
227 | 0 | pcs = gs_cspace_new_DeviceGray(pdev->memory); |
228 | 0 | if (pcs == NULL) { |
229 | 0 | code = gs_note_error(gs_error_VMerror); |
230 | 0 | goto fail; |
231 | 0 | } |
232 | 0 | gs_image_t_init(&image, pcs); |
233 | 0 | invert = 0xff; |
234 | 0 | } else { |
235 | | /* |
236 | | * We think this code is never executed when interpreting PostScript |
237 | | * or PDF: the library never uses monobit non-mask images |
238 | | * internally, and high-level images don't go through this code. |
239 | | * However, we still want the code to work. |
240 | | */ |
241 | 0 | gs_color_space *pcs_base; |
242 | 0 | gx_color_index c[2]; |
243 | 0 | int i, j; |
244 | 0 | int ncomp = pdev->color_info.num_components; |
245 | 0 | byte *p; |
246 | |
|
247 | 0 | code = pdf_cspace_init_Device(pdev->memory, &pcs_base, ncomp); |
248 | 0 | if (code < 0) |
249 | 0 | goto fail; |
250 | 0 | c[0] = psdf_adjust_color_index((gx_device_vector *)pdev, zero); |
251 | 0 | c[1] = psdf_adjust_color_index((gx_device_vector *)pdev, one); |
252 | 0 | pcs = gs_cspace_alloc(pdev->memory, &gs_color_space_type_Indexed); |
253 | 0 | if (pcs == NULL) { |
254 | 0 | rc_decrement_cs(pcs_base, "pdf_copy_mono"); |
255 | 0 | code = gs_note_error(gs_error_VMerror); |
256 | 0 | goto fail; |
257 | 0 | } |
258 | 0 | pcs->base_space = pcs_base; |
259 | 0 | pcs->params.indexed.hival = 1; |
260 | 0 | pcs->params.indexed.n_comps = ncomp; |
261 | 0 | p = palette; |
262 | 0 | for (i = 0; i < 2; ++i) |
263 | 0 | for (j = ncomp - 1; j >= 0; --j) |
264 | 0 | *p++ = (byte)(c[i] >> (j * 8)); |
265 | 0 | pcs->params.indexed.lookup.table.data = palette; |
266 | 0 | pcs->params.indexed.lookup.table.size = p - palette; |
267 | 0 | pcs->params.indexed.use_proc = false; |
268 | 0 | gs_image_t_init(&image, pcs); |
269 | 0 | image.BitsPerComponent = 1; |
270 | 0 | } |
271 | 3.15k | pdf_make_bitmap_image(&image, x, y, w, h); |
272 | 3.15k | { |
273 | 3.15k | uint64_t nbytes = (uint64_t) ((w + 7) >> 3) * h; |
274 | | |
275 | 3.15k | code = pdf_open_page(pdev, PDF_IN_STREAM); |
276 | 3.15k | if (code < 0) |
277 | 0 | goto fail; |
278 | 3.15k | in_line = nbytes < pdev->MaxInlineImageSize; |
279 | 3.15k | if (in_line) |
280 | 3.15k | pdf_put_image_matrix(pdev, &image.ImageMatrix, 1.0); |
281 | 3.15k | pdf_image_writer_init(&writer); |
282 | 3.15k | code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, in_line); |
283 | 3.15k | if (code < 0) |
284 | 0 | goto fail; |
285 | 3.15k | } |
286 | 137k | wr: |
287 | 137k | if (image.ImageMask) |
288 | 137k | pcsvalue = NULL; |
289 | 0 | else { |
290 | | /* |
291 | | * We don't have to worry about color space scaling: the color |
292 | | * space is always a Device space. |
293 | | */ |
294 | 0 | code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs, |
295 | 0 | &writer.pin->color_spaces, in_line, NULL, 0, false); |
296 | 0 | if (code < 0) |
297 | 0 | goto fail; |
298 | 0 | pcsvalue = &cs_value; |
299 | 0 | } |
300 | | /* |
301 | | * There are 3 different cases at this point: |
302 | | * - Writing an in-line image (pres == 0, writer.pres == 0); |
303 | | * - Writing an XObject image (pres == 0, writer.pres != 0); |
304 | | * - Writing the image for a CharProc (pres != 0). |
305 | | * We handle them with in-line code followed by a switch, |
306 | | * rather than making the shared code into a procedure, |
307 | | * simply because there would be an awful lot of parameters |
308 | | * that would need to be passed. |
309 | | */ |
310 | 137k | if (pres) { |
311 | 134k | if (!pdev->NoT3CCITT) { |
312 | | /* |
313 | | * Always use CCITTFax 2-D for character bitmaps. It takes less |
314 | | * space to invert the data with Decode than to set BlackIs1. |
315 | | */ |
316 | 134k | float d0 = image.Decode[0]; |
317 | | |
318 | 134k | image.Decode[0] = image.Decode[1]; |
319 | 134k | image.Decode[1] = d0; |
320 | 134k | psdf_CFE_binary(&writer.binary[0], image.Width, image.Height, true); |
321 | 134k | invert ^= 0xff; |
322 | 134k | } |
323 | 134k | } else { |
324 | | /* Use the Distiller compression parameters. */ |
325 | 3.15k | pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel; |
326 | 3.15k | psdf_setup_image_filters((gx_device_psdf *) pdev, &writer.binary[0], |
327 | 3.15k | (gs_pixel_image_t *)&image, NULL, NULL, true, in_line); |
328 | 3.15k | } |
329 | 137k | code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, |
330 | 137k | pcsvalue, 0); |
331 | 137k | if (code < 0) |
332 | 0 | goto fail; |
333 | | |
334 | 137k | code = pdf_copy_mask_bits(writer.binary[0].strm, base, sourcex, raster, |
335 | 137k | w, h, invert); |
336 | 137k | if (code < 0) |
337 | 0 | goto fail; |
338 | 137k | code = pdf_end_image_binary(pdev, &writer, writer.height); |
339 | 137k | if (code < 0) |
340 | 0 | goto fail; |
341 | | |
342 | 137k | if (!pres) { |
343 | 3.15k | switch ((code = pdf_end_write_image(pdev, &writer))) { |
344 | 0 | default: /* error */ |
345 | 0 | goto fail; |
346 | 3.15k | case 1: |
347 | 3.15k | code = 0; |
348 | 3.15k | goto fail; |
349 | 0 | case 0: |
350 | 0 | code = pdf_do_image(pdev, writer.pres, &image.ImageMatrix, |
351 | 0 | true); |
352 | 0 | goto fail; |
353 | 3.15k | } |
354 | 3.15k | } |
355 | 134k | writer.end_string = ""; /* no Q */ |
356 | 134k | switch ((code = pdf_end_write_image(pdev, &writer))) { |
357 | 0 | default: /* error */ |
358 | 0 | goto fail; |
359 | 0 | return code; |
360 | 0 | case 0: /* not possible */ |
361 | 0 | code = gs_note_error(gs_error_Fatal); |
362 | 0 | goto fail; |
363 | 134k | case 1: |
364 | 134k | break; |
365 | 134k | } |
366 | 134k | code = pdf_end_char_proc(pdev, &ipos); |
367 | 134k | if (code < 0) |
368 | 0 | return code; |
369 | 1.81M | rx:{ |
370 | 1.81M | gs_matrix imat; |
371 | | |
372 | 1.81M | imat = image.ImageMatrix; |
373 | 1.81M | imat.xx /= w; |
374 | 1.81M | imat.xy /= h; |
375 | 1.81M | imat.yx /= w; |
376 | 1.81M | imat.yy /= h; |
377 | 1.81M | return pdf_do_char_image(pdev, (const pdf_char_proc_t *)pres, &imat); |
378 | 134k | } |
379 | | |
380 | 3.15k | fail: |
381 | 3.15k | if (char_proc_begun) |
382 | 0 | (void)pdf_end_char_proc(pdev, &ipos); |
383 | 3.15k | return code; |
384 | 134k | } |
385 | | int |
386 | | gdev_pdf_copy_mono(gx_device * dev, |
387 | | const byte * base, int sourcex, int raster, gx_bitmap_id id, |
388 | | int x, int y, int w, int h, gx_color_index zero, |
389 | | gx_color_index one) |
390 | 20.8k | { |
391 | 20.8k | gx_device_pdf *pdev = (gx_device_pdf *) dev; |
392 | | |
393 | 20.8k | if (w <= 0 || h <= 0) |
394 | 20.8k | return 0; |
395 | 0 | return pdf_copy_mono(pdev, base, sourcex, raster, id, x, y, w, h, |
396 | 0 | zero, one, NULL); |
397 | 20.8k | } |
398 | | |
399 | | /* Copy a color bitmap. for_pattern = -1 means put the image in-line, */ |
400 | | /* 1 means put the image in a resource, 2 means image is a rasterized shading. */ |
401 | | int |
402 | | pdf_copy_color_data(gx_device_pdf * pdev, const byte * base, int sourcex, |
403 | | int raster, gx_bitmap_id id, int x, int y, int w, int h, |
404 | | gs_image_t *pim, pdf_image_writer *piw, |
405 | | int for_pattern) |
406 | 2.54k | { |
407 | 2.54k | int depth = pdev->color_info.depth; |
408 | 2.54k | int bytes_per_pixel = depth >> 3; |
409 | 2.54k | gs_color_space *pcs; |
410 | 2.54k | cos_value_t cs_value; |
411 | 2.54k | uint64_t nbytes; |
412 | 2.54k | int code = pdf_cspace_init_Device(pdev->memory, &pcs, bytes_per_pixel); |
413 | 2.54k | const byte *row_base; |
414 | 2.54k | int row_step; |
415 | 2.54k | bool in_line; |
416 | | |
417 | 2.54k | if (code < 0) |
418 | 0 | return code; /* can't happen */ |
419 | 2.54k | if (!base) |
420 | 0 | return 1; |
421 | 2.54k | gs_image_t_init(pim, pcs); |
422 | 2.54k | pdf_make_bitmap_image(pim, x, y, w, h); |
423 | 2.54k | pim->BitsPerComponent = 8; |
424 | 2.54k | nbytes = (uint64_t)w * bytes_per_pixel * h; |
425 | | |
426 | 2.54k | if (for_pattern == 1) { |
427 | | /* |
428 | | * Patterns must be emitted in order of increasing user Y, i.e., |
429 | | * the opposite of PDF's standard image order. |
430 | | */ |
431 | 0 | row_base = base + (h - 1) * raster; |
432 | 0 | row_step = -raster; |
433 | 0 | in_line = for_pattern < 0; |
434 | 2.54k | } else { |
435 | 2.54k | row_base = base; |
436 | 2.54k | row_step = raster; |
437 | 2.54k | in_line = nbytes < pdev->MaxInlineImageSize; |
438 | 2.54k | pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0); |
439 | | /* |
440 | | * Check whether we've already made an XObject resource for this |
441 | | * image. |
442 | | */ |
443 | 2.54k | if (id != gx_no_bitmap_id) { |
444 | 0 | piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id); |
445 | 0 | if (piw->pres) |
446 | 0 | return 0; |
447 | 0 | } |
448 | 2.54k | } |
449 | | /* |
450 | | * We have to be able to control whether to put Pattern images in line, |
451 | | * to avoid trying to create an XObject resource while we're in the |
452 | | * middle of writing a Pattern resource. |
453 | | */ |
454 | 2.54k | if (for_pattern < 0) |
455 | 0 | stream_puts(pdev->strm, "q "); |
456 | | /* |
457 | | * We don't have to worry about color space scaling: the color |
458 | | * space is always a Device space. |
459 | | */ |
460 | 2.54k | pdf_image_writer_init(piw); |
461 | 2.54k | pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel; |
462 | 2.54k | if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 || |
463 | 2.54k | (code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs, |
464 | 2.54k | &piw->pin->color_spaces, in_line, NULL, 0, false)) < 0 || |
465 | 2.54k | (for_pattern < 2 || nbytes < 512000 ? |
466 | 2.54k | (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev, |
467 | 2.54k | &piw->binary[0], (gs_pixel_image_t *)pim, false)) : |
468 | 2.54k | (code = psdf_setup_image_filters((gx_device_psdf *) pdev, |
469 | 0 | &piw->binary[0], (gs_pixel_image_t *)pim, NULL, NULL, false, false)) |
470 | 2.54k | ) < 0 || |
471 | 2.54k | (code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim, |
472 | 2.54k | &cs_value, 0)) < 0 |
473 | 2.54k | ) |
474 | 0 | return code; |
475 | 2.54k | pdf_copy_color_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h, |
476 | 2.54k | bytes_per_pixel); |
477 | 2.54k | pdf_end_image_binary(pdev, piw, piw->height); |
478 | 2.54k | rc_decrement(pcs, "pdf_copy_color_data"); |
479 | 2.54k | return pdf_end_write_image(pdev, piw); |
480 | 2.54k | } |
481 | | |
482 | | int |
483 | | gdev_pdf_copy_color(gx_device * dev, const byte * base, int sourcex, |
484 | | int raster, gx_bitmap_id id, int x, int y, int w, int h) |
485 | 3 | { |
486 | 3 | gx_device_pdf *pdev = (gx_device_pdf *) dev; |
487 | 3 | gs_image_t image; |
488 | 3 | pdf_image_writer writer; |
489 | 3 | int code; |
490 | | |
491 | 3 | if (w <= 0 || h <= 0) |
492 | 0 | return 0; |
493 | 3 | code = pdf_open_page(pdev, PDF_IN_STREAM); |
494 | 3 | if (code < 0) |
495 | 0 | return code; |
496 | | /* Make sure we aren't being clipped. */ |
497 | 3 | code = pdf_put_clip_path(pdev, NULL); |
498 | 3 | if (code < 0) |
499 | 0 | return code; |
500 | 3 | code = pdf_copy_color_data(pdev, base, sourcex, raster, id, x, y, w, h, |
501 | 3 | &image, &writer, 0); |
502 | 3 | switch (code) { |
503 | 0 | default: |
504 | 0 | return code; /* error */ |
505 | 3 | case 1: |
506 | 3 | return 0; |
507 | 0 | case 0: |
508 | 0 | return pdf_do_image(pdev, writer.pres, NULL, true); |
509 | 3 | } |
510 | 3 | } |
511 | | |
512 | | /* Fill a mask. */ |
513 | | int |
514 | | gdev_pdf_fill_mask(gx_device * dev, |
515 | | const byte * data, int data_x, int raster, gx_bitmap_id id, |
516 | | int x, int y, int width, int height, |
517 | | const gx_drawing_color * pdcolor, int depth, |
518 | | gs_logical_operation_t lop, const gx_clip_path * pcpath) |
519 | 2.31M | { |
520 | 2.31M | gx_device_pdf *pdev = (gx_device_pdf *) dev; |
521 | 2.31M | pdf_text_enum_t *penum = (pdf_text_enum_t *)pdev->OCR_enum; |
522 | | |
523 | 2.31M | if (width <= 0 || height <= 0) |
524 | 495k | return 0; |
525 | | |
526 | | /* If OCRStage is 'OCR_Rendering' then we are handling an image which is a rendered glyph |
527 | | * that we want to have OCR software process and return a Unicode code point for. |
528 | | * We specifically do *not* want to send the image to the output PDF file! |
529 | | */ |
530 | 1.81M | if (pdev->OCRStage == OCR_Rendering) { |
531 | 0 | int code = 0; |
532 | 0 | ocr_glyph_t *new_glyph = NULL; |
533 | 0 | int index; |
534 | |
|
535 | 0 | new_glyph = (ocr_glyph_t *)gs_alloc_bytes(pdev->pdf_memory, sizeof(ocr_glyph_t), ""); |
536 | 0 | if (new_glyph == NULL) |
537 | 0 | return_error(gs_error_VMerror); |
538 | 0 | new_glyph->data = gs_alloc_bytes(pdev->pdf_memory, raster*height, ""); |
539 | 0 | if (new_glyph->data == NULL) |
540 | 0 | return_error(gs_error_VMerror); |
541 | 0 | memcpy(new_glyph->data, data, raster * height); |
542 | 0 | new_glyph->height = height; |
543 | 0 | new_glyph->width = width; |
544 | 0 | new_glyph->raster = raster; |
545 | 0 | new_glyph->x = x; |
546 | 0 | new_glyph->y = y; |
547 | 0 | if (penum != NULL) { |
548 | 0 | new_glyph->char_code = penum->pte_default->returned.current_char; |
549 | 0 | new_glyph->glyph = penum->pte_default->returned.current_glyph; |
550 | 0 | } else { |
551 | 0 | new_glyph->char_code = pdev->OCR_char_code; |
552 | 0 | new_glyph->glyph = pdev->OCR_glyph; |
553 | 0 | } |
554 | 0 | new_glyph->next = NULL; |
555 | 0 | new_glyph->is_space = true; |
556 | 0 | for(index = 0; index < height * raster;index++){ |
557 | 0 | if(data[index] != 0x00) { |
558 | 0 | new_glyph->is_space = false; |
559 | 0 | break; |
560 | 0 | } |
561 | 0 | } |
562 | 0 | if (pdev->ocr_glyphs == NULL) |
563 | 0 | pdev->ocr_glyphs = new_glyph; |
564 | 0 | else { |
565 | 0 | ocr_glyph_t *next = pdev->ocr_glyphs; |
566 | |
|
567 | 0 | while (next->next != NULL) |
568 | 0 | next = next->next; |
569 | 0 | next->next = new_glyph; |
570 | 0 | } |
571 | 0 | return code; |
572 | 0 | } |
573 | | |
574 | 1.81M | if (depth > 1 || (!gx_dc_is_pure(pdcolor) != 0 && !(gx_dc_is_pattern1_color(pdcolor)))) |
575 | 0 | return gx_default_fill_mask(dev, data, data_x, raster, id, |
576 | 0 | x, y, width, height, pdcolor, depth, lop, |
577 | 0 | pcpath); |
578 | 1.81M | return pdf_copy_mono(pdev, data, data_x, raster, id, x, y, width, height, |
579 | 1.81M | gx_no_color_index, gx_dc_pure_color(pdcolor), |
580 | 1.81M | pcpath); |
581 | 1.81M | } |
582 | | |
583 | | /* Tile with a bitmap. This is important for pattern fills. */ |
584 | | int |
585 | | gdev_pdf_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles, |
586 | | int x, int y, int w, int h, |
587 | | gx_color_index color0, gx_color_index color1, |
588 | | int px, int py) |
589 | 1 | { |
590 | 1 | gx_device_pdf *const pdev = (gx_device_pdf *) dev; |
591 | 1 | int tw = tiles->rep_width, th = tiles->rep_height; |
592 | 1 | double xscale = pdev->HWResolution[0] / 72.0, |
593 | 1 | yscale = pdev->HWResolution[1] / 72.0; |
594 | 1 | bool mask; |
595 | 1 | int depth; |
596 | 1 | int (*copy_data)(gx_device_pdf *, const byte *, int, int, |
597 | 1 | gx_bitmap_id, int, int, int, int, |
598 | 1 | gs_image_t *, pdf_image_writer *, int); |
599 | 1 | pdf_resource_t *pres; |
600 | 1 | cos_value_t cs_value; |
601 | 1 | int code; |
602 | | |
603 | 1 | if (tiles->id == gx_no_bitmap_id || tiles->shift != 0 || |
604 | 1 | (w < tw && h < th) || |
605 | 1 | color0 != gx_no_color_index |
606 | 1 | ) |
607 | 1 | goto use_default; |
608 | 0 | if (color1 != gx_no_color_index) { |
609 | | /* This is a mask pattern. */ |
610 | 0 | mask = true; |
611 | 0 | depth = 1; |
612 | 0 | copy_data = pdf_copy_mask_data; |
613 | 0 | code = pdf_cs_Pattern_uncolored(pdev, &cs_value); |
614 | 0 | } else { |
615 | | /* This is a colored pattern. */ |
616 | 0 | mask = false; |
617 | 0 | depth = pdev->color_info.depth; |
618 | 0 | copy_data = pdf_copy_color_data; |
619 | 0 | code = pdf_cs_Pattern_colored(pdev, &cs_value); |
620 | 0 | } |
621 | 0 | if (code < 0) |
622 | 0 | goto use_default; |
623 | 0 | pres = pdf_find_resource_by_gs_id(pdev, resourcePattern, tiles->id); |
624 | 0 | if (!pres) { |
625 | | /* Create the Pattern resource. */ |
626 | 0 | int code; |
627 | 0 | int64_t length_id; |
628 | 0 | gs_offset_t start, end; |
629 | 0 | stream *s; |
630 | 0 | gs_image_t image; |
631 | 0 | pdf_image_writer writer; |
632 | 0 | int64_t image_bytes = ((int64_t)tw * depth + 7) / 8 * th; |
633 | 0 | bool in_line = image_bytes < pdev->MaxInlineImageSize; |
634 | 0 | int64_t tile_id = |
635 | 0 | (tw == tiles->size.x && th == tiles->size.y ? tiles->id : |
636 | 0 | gx_no_bitmap_id); |
637 | |
|
638 | 0 | if (!in_line) |
639 | 0 | goto use_default; |
640 | | |
641 | 0 | code = pdf_begin_resource(pdev, resourcePattern, tiles->id, &pres); |
642 | 0 | if (code < 0) |
643 | 0 | goto use_default; |
644 | 0 | s = pdev->strm; |
645 | 0 | pprintd1(s, "/PatternType 1/PaintType %d/TilingType 1/Resources<<\n", |
646 | 0 | (mask ? 2 : 1)); |
647 | |
|
648 | 0 | if (pdev->CompatibilityLevel <= 1.7) |
649 | 0 | pprints1(s, "/ProcSet[/PDF/Image%s]>>\n", (mask ? "B" : "C")); |
650 | | /* |
651 | | * Because of bugs in Acrobat Reader's Print function, we can't use |
652 | | * the natural BBox and Step here: they have to be 1. |
653 | | */ |
654 | 0 | pprintg2(s, "/Matrix[%g 0 0 %g 0 0]", tw / xscale, th / yscale); |
655 | 0 | stream_puts(s, "/BBox[0 0 1 1]/XStep 1/YStep 1/Length "); |
656 | 0 | length_id = pdf_obj_ref(pdev); |
657 | 0 | pprinti64d1(s, "%"PRId64" 0 R>>stream\n", length_id); |
658 | 0 | start = pdf_stell(pdev); |
659 | 0 | code = copy_data(pdev, tiles->data, 0, tiles->raster, |
660 | 0 | tile_id, 0, 0, tw, th, &image, &writer, -1); |
661 | 0 | switch (code) { |
662 | 0 | default: |
663 | 0 | return code; /* error */ |
664 | 0 | case 1: |
665 | 0 | break; |
666 | 0 | case 0: /* not possible */ |
667 | 0 | return_error(gs_error_Fatal); |
668 | 0 | } |
669 | 0 | end = pdf_stell(pdev); |
670 | 0 | stream_puts(s, "\nendstream\n"); |
671 | 0 | pdf_end_resource(pdev, resourcePattern); |
672 | 0 | pdf_open_separate(pdev, length_id, resourceNone); |
673 | 0 | pprinti64d1(pdev->strm, "%"PRId64"\n", end - start); |
674 | 0 | pdf_end_separate(pdev, resourceNone); |
675 | 0 | pres->object->written = true; /* don't write at end of page */ |
676 | 0 | } |
677 | | /* Fill the rectangle with the Pattern. */ |
678 | 0 | { |
679 | 0 | int code = pdf_open_page(pdev, PDF_IN_STREAM); |
680 | 0 | stream *s; |
681 | |
|
682 | 0 | if (code < 0) |
683 | 0 | goto use_default; |
684 | | /* Make sure we aren't being clipped. */ |
685 | 0 | code = pdf_put_clip_path(pdev, NULL); |
686 | 0 | if (code < 0) |
687 | 0 | return code; |
688 | 0 | s = pdev->strm; |
689 | | /* |
690 | | * Because of bugs in Acrobat Reader's Print function, we can't |
691 | | * leave the CTM alone here: we have to reset it to the default. |
692 | | */ |
693 | 0 | pprintg2(s, "q %g 0 0 %g 0 0 cm\n", xscale, yscale); |
694 | 0 | cos_value_write(&cs_value, pdev); |
695 | 0 | stream_puts(s, " cs"); |
696 | 0 | if (mask) |
697 | 0 | pprintg3(s, " %g %g %g", (int)(color1 >> 16) / 255.0, |
698 | 0 | (int)((color1 >> 8) & 0xff) / 255.0, |
699 | 0 | (int)(color1 & 0xff) / 255.0); |
700 | 0 | pprinti64d1(s, "/R%"PRId64" scn", pdf_resource_id(pres)); |
701 | 0 | pprintg4(s, " %g %g %g %g re f Q\n", |
702 | 0 | x / xscale, y / yscale, w / xscale, h / xscale); |
703 | 0 | } |
704 | 0 | return 0; |
705 | 1 | use_default: |
706 | 1 | return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h, |
707 | 1 | color0, color1, px, py); |
708 | 0 | } |