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