/src/ghostpdl/pdf/pdf_page.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2019-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 | | /* Page-level operations for the PDF interpreter */ |
17 | | |
18 | | #include "pdf_int.h" |
19 | | #include "pdf_stack.h" |
20 | | #include "pdf_doc.h" |
21 | | #include "pdf_deref.h" |
22 | | #include "pdf_page.h" |
23 | | #include "pdf_file.h" |
24 | | #include "pdf_dict.h" |
25 | | #include "pdf_array.h" |
26 | | #include "pdf_loop_detect.h" |
27 | | #include "pdf_colour.h" |
28 | | #include "pdf_trans.h" |
29 | | #include "pdf_font_types.h" |
30 | | #include "pdf_gstate.h" |
31 | | #include "pdf_misc.h" |
32 | | #include "pdf_optcontent.h" |
33 | | #include "pdf_device.h" |
34 | | #include "pdf_annot.h" |
35 | | #include "pdf_check.h" |
36 | | #include "pdf_mark.h" |
37 | | |
38 | | #include "gscoord.h" /* for gs_concat() and others */ |
39 | | #include "gspaint.h" /* For gs_erasepage() */ |
40 | | #include "gsstate.h" /* For gs_initgraphics() */ |
41 | | #include "gspath2.h" /* For gs_rectclip() */ |
42 | | |
43 | | static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict) |
44 | 43.3k | { |
45 | 43.3k | int i, code = 0; |
46 | 43.3k | pdf_obj *o, *o1; |
47 | | |
48 | | #if PURGE_CACHE_PER_PAGE |
49 | | pdfi_purge_obj_cache(ctx); |
50 | | #endif |
51 | | |
52 | 43.3k | code = pdfi_dict_get(ctx, page_dict, "Contents", &o); |
53 | 43.3k | if (code == gs_error_undefined) |
54 | | /* Don't throw an error if there are no contents, just render nothing.... */ |
55 | 1.44k | return 0; |
56 | 41.9k | if (code < 0) |
57 | 608 | return code; |
58 | | |
59 | 41.3k | if (pdfi_type_of(o) == PDF_INDIRECT) { |
60 | 5 | if (((pdf_indirect_ref *)o)->ref_object_num == page_dict->object_num) |
61 | 0 | return_error(gs_error_circular_reference); |
62 | | |
63 | 5 | code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o)->ref_object_num, ((pdf_indirect_ref *)o)->ref_generation_num, &o1); |
64 | 5 | pdfi_countdown(o); |
65 | 5 | if (code < 0) { |
66 | 1 | if (code == gs_error_VMerror) |
67 | 0 | return code; |
68 | 1 | return 0; |
69 | 1 | } |
70 | 4 | o = o1; |
71 | 4 | } |
72 | | |
73 | 41.3k | code = pdfi_gsave(ctx); |
74 | 41.3k | if (code < 0) { |
75 | 0 | pdfi_countdown(o); |
76 | 0 | return code; |
77 | 0 | } |
78 | | |
79 | 41.3k | ctx->encryption.decrypt_strings = false; |
80 | 41.3k | if (pdfi_type_of(o) == PDF_ARRAY) { |
81 | 2.87k | pdf_array *a = (pdf_array *)o; |
82 | | |
83 | 12.1k | for (i=0;i < pdfi_array_size(a); i++) { |
84 | 9.87k | pdf_indirect_ref *r; |
85 | 9.87k | code = pdfi_array_get_no_deref(ctx, a, i, (pdf_obj **)&r); |
86 | 9.87k | if (code < 0) |
87 | 0 | goto page_error; |
88 | 9.87k | if (pdfi_type_of (r) == PDF_STREAM) { |
89 | 0 | code = pdfi_interpret_content_stream(ctx, NULL, (pdf_stream *)r, page_dict); |
90 | 0 | pdfi_countdown(r); |
91 | 0 | if (code < 0) |
92 | 0 | goto page_error; |
93 | 9.87k | } else { |
94 | 9.87k | if (pdfi_type_of(r) != PDF_INDIRECT) { |
95 | 18 | pdfi_countdown(r); |
96 | 18 | code = gs_note_error(gs_error_typecheck); |
97 | 18 | goto page_error; |
98 | 9.85k | } else { |
99 | 9.85k | if (r->ref_object_num == page_dict->object_num) { |
100 | 0 | pdfi_countdown(r); |
101 | 0 | code = gs_note_error(gs_error_circular_reference); |
102 | 0 | goto page_error; |
103 | 0 | } |
104 | 9.85k | code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, &o1); |
105 | 9.85k | pdfi_countdown(r); |
106 | 9.85k | if (code < 0) { |
107 | 530 | if (code != gs_error_VMerror || ctx->args.pdfstoponerror == false) |
108 | 530 | code = 0; |
109 | 530 | goto page_error; |
110 | 530 | } |
111 | 9.32k | if (pdfi_type_of(o1) != PDF_STREAM) { |
112 | 40 | pdfi_countdown(o1); |
113 | 40 | code = gs_note_error(gs_error_typecheck); |
114 | 40 | goto page_error; |
115 | 40 | } |
116 | 9.28k | code = pdfi_interpret_content_stream(ctx, NULL, (pdf_stream *)o1, page_dict); |
117 | 9.28k | pdfi_countdown(o1); |
118 | 9.28k | if (code < 0) { |
119 | 159 | if (code == gs_error_VMerror || ctx->args.pdfstoponerror == true) |
120 | 0 | goto page_error; |
121 | 159 | } |
122 | 9.28k | } |
123 | 9.87k | } |
124 | 9.87k | } |
125 | 38.4k | } else { |
126 | 38.4k | if (pdfi_type_of(o) == PDF_STREAM) { |
127 | 38.2k | code = pdfi_interpret_content_stream(ctx, NULL, (pdf_stream *)o, page_dict); |
128 | 38.2k | } else { |
129 | 257 | pdfi_countdown(o); |
130 | 257 | ctx->encryption.decrypt_strings = true; |
131 | 257 | return_error(gs_error_typecheck); |
132 | 257 | } |
133 | 38.4k | } |
134 | 41.0k | page_error: |
135 | 41.0k | ctx->encryption.decrypt_strings = true; |
136 | 41.0k | pdfi_clearstack(ctx); |
137 | 41.0k | pdfi_grestore(ctx); |
138 | 41.0k | pdfi_countdown(o); |
139 | 41.0k | return code; |
140 | 41.3k | } |
141 | | |
142 | | /* Render one page (including annotations) (see pdf_main.ps/showpagecontents) */ |
143 | | static int pdfi_process_one_page(pdf_context *ctx, pdf_dict *page_dict) |
144 | 43.3k | { |
145 | 43.3k | stream_save local_entry_save; |
146 | 43.3k | int code, code1; |
147 | | |
148 | | /* Save the current stream state, for later cleanup, in a local variable */ |
149 | 43.3k | local_save_stream_state(ctx, &local_entry_save); |
150 | 43.3k | initialise_stream_save(ctx); |
151 | | |
152 | 43.3k | code = pdfi_process_page_contents(ctx, page_dict); |
153 | | |
154 | | /* Put our state back the way it was before we ran the contents |
155 | | * and check if the stream had problems |
156 | | */ |
157 | | #if PROBE_STREAMS |
158 | | if (ctx->pgs->level > ctx->current_stream_save.gsave_level || |
159 | | pdfi_count_stack(ctx) > ctx->current_stream_save.stack_count) |
160 | | code = ((pdf_context *)0)->first_page; |
161 | | #endif |
162 | | |
163 | 43.3k | cleanup_context_interpretation(ctx, &local_entry_save); |
164 | 43.3k | local_restore_stream_state(ctx, &local_entry_save); |
165 | | |
166 | 43.3k | code1 = pdfi_do_annotations(ctx, page_dict); |
167 | 43.3k | if (code > 0) code = code1; |
168 | | |
169 | 43.3k | code1 = pdfi_do_acroform(ctx, page_dict); |
170 | 43.3k | if (code > 0) code = code1; |
171 | | |
172 | 43.3k | return code; |
173 | 43.3k | } |
174 | | |
175 | | /* See pdf_PDF2PS_matrix and .pdfshowpage_Install */ |
176 | | static void pdfi_set_ctm(pdf_context *ctx) |
177 | 0 | { |
178 | 0 | gs_matrix mat; |
179 | | |
180 | | /* Adjust for page.UserUnits */ |
181 | 0 | mat.xx = ctx->page.UserUnit; |
182 | 0 | mat.xy = 0; |
183 | 0 | mat.yx = 0; |
184 | 0 | mat.yy = ctx->page.UserUnit; |
185 | 0 | mat.tx = 0; |
186 | 0 | mat.ty = 0; |
187 | 0 | gs_concat(ctx->pgs, &mat); |
188 | | |
189 | | /* We need to make sure the default matrix is properly set. |
190 | | * If we do gs_initgraphics() later (such as for annotations) |
191 | | * then it uses this default matrix if it is set. |
192 | | * Needed for page rotations to work correctly with Annotations. |
193 | | */ |
194 | 0 | gs_setdefaultmatrix(ctx->pgs, &ctm_only(ctx->pgs)); |
195 | |
|
196 | 0 | } |
197 | | |
198 | | /* Get .MediaSize from the device to setup page.Size in context */ |
199 | | static int pdfi_get_media_size(pdf_context *ctx, pdf_dict *page_dict) |
200 | 43.3k | { |
201 | 43.3k | pdf_array *a = NULL, *default_media = NULL; |
202 | 43.3k | double d[4]; |
203 | 43.3k | int code = 0; |
204 | 43.3k | uint64_t i; |
205 | 43.3k | double userunit = 1.0; |
206 | | |
207 | 43.3k | code = pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&default_media); |
208 | 43.3k | if (code < 0) { |
209 | 212 | pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_get_media_size", NULL); |
210 | 212 | code = gs_erasepage(ctx->pgs); |
211 | 212 | return 0; |
212 | 212 | } |
213 | | |
214 | 43.1k | if (ctx->args.usecropbox) { |
215 | 0 | if (a != NULL) |
216 | 0 | pdfi_countdown(a); |
217 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a); |
218 | 0 | } |
219 | 43.1k | if (ctx->args.useartbox) { |
220 | 0 | if (a != NULL) |
221 | 0 | pdfi_countdown(a); |
222 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "ArtBox", PDF_ARRAY, (pdf_obj **)&a); |
223 | 0 | } |
224 | 43.1k | if (ctx->args.usebleedbox) { |
225 | 0 | if (a != NULL) |
226 | 0 | pdfi_countdown(a); |
227 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "BleedBox", PDF_ARRAY, (pdf_obj **)&a); |
228 | 0 | } |
229 | 43.1k | if (ctx->args.usetrimbox) { |
230 | 0 | if (a != NULL) |
231 | 0 | pdfi_countdown(a); |
232 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "TrimBox", PDF_ARRAY, (pdf_obj **)&a); |
233 | 0 | } |
234 | 43.1k | if (a == NULL) { |
235 | 43.1k | a = default_media; |
236 | 43.1k | } |
237 | | |
238 | 43.1k | if (!ctx->args.nouserunit) { |
239 | 43.1k | (void)pdfi_dict_knownget_number(ctx, page_dict, "UserUnit", &userunit); |
240 | 43.1k | } |
241 | 43.1k | ctx->page.UserUnit = userunit; |
242 | | |
243 | 215k | for (i=0;i<4;i++) { |
244 | 172k | code = pdfi_array_get_number(ctx, a, i, &d[i]); |
245 | 172k | d[i] *= userunit; |
246 | 172k | } |
247 | 43.1k | pdfi_countdown(a); |
248 | | |
249 | 43.1k | normalize_rectangle(d); |
250 | 43.1k | memcpy(ctx->page.Size, d, 4 * sizeof(double)); |
251 | | |
252 | 43.1k | return code; |
253 | 43.3k | } |
254 | | |
255 | | static int pdfi_set_media_size(pdf_context *ctx, pdf_dict *page_dict) |
256 | 0 | { |
257 | 0 | gs_c_param_list list; |
258 | 0 | gs_param_float_array fa; |
259 | 0 | pdf_array *a = NULL, *default_media = NULL; |
260 | 0 | float fv[2]; |
261 | 0 | double d[4], d_crop[4]; |
262 | 0 | gs_rect bbox; |
263 | 0 | int code, do_crop = false; |
264 | 0 | uint64_t i; |
265 | 0 | int64_t rotate = 0; |
266 | 0 | double userunit = 1.0; |
267 | |
|
268 | 0 | code = pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&default_media); |
269 | 0 | if (code < 0) { |
270 | 0 | pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_get_media_size", NULL); |
271 | 0 | code = gs_erasepage(ctx->pgs); |
272 | 0 | return 0; |
273 | 0 | } |
274 | | |
275 | 0 | if (ctx->args.usecropbox) { |
276 | 0 | if (a != NULL) |
277 | 0 | pdfi_countdown(a); |
278 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a); |
279 | 0 | } |
280 | 0 | if (ctx->args.useartbox) { |
281 | 0 | if (a != NULL) |
282 | 0 | pdfi_countdown(a); |
283 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "ArtBox", PDF_ARRAY, (pdf_obj **)&a); |
284 | 0 | } |
285 | 0 | if (ctx->args.usebleedbox) { |
286 | 0 | if (a != NULL) |
287 | 0 | pdfi_countdown(a); |
288 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "BleedBox", PDF_ARRAY, (pdf_obj **)&a); |
289 | 0 | } |
290 | 0 | if (ctx->args.usetrimbox) { |
291 | 0 | if (a != NULL) |
292 | 0 | pdfi_countdown(a); |
293 | 0 | (void)pdfi_dict_get_type(ctx, page_dict, "TrimBox", PDF_ARRAY, (pdf_obj **)&a); |
294 | 0 | } |
295 | 0 | if (a == NULL) { |
296 | 0 | code = pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a); |
297 | 0 | if (code >= 0 && pdfi_array_size(a) >= 4) { |
298 | 0 | pdf_obj *box_obj = NULL; |
299 | |
|
300 | 0 | for (i=0;i<4;i++) { |
301 | 0 | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
302 | 0 | if (code >= 0) { |
303 | 0 | code = pdfi_obj_to_real(ctx, box_obj, &d_crop[i]); |
304 | 0 | pdfi_countdown(box_obj); |
305 | 0 | } |
306 | 0 | if (code < 0) |
307 | 0 | break; |
308 | 0 | } |
309 | 0 | pdfi_countdown(a); |
310 | 0 | if (code >= 0) { |
311 | 0 | normalize_rectangle(d_crop); |
312 | 0 | memcpy(ctx->page.Crop, d_crop, 4 * sizeof(double)); |
313 | 0 | do_crop = true; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | a = default_media; |
317 | 0 | } |
318 | |
|
319 | 0 | if (!ctx->args.nouserunit) { |
320 | 0 | (void)pdfi_dict_knownget_number(ctx, page_dict, "UserUnit", &userunit); |
321 | 0 | } |
322 | 0 | ctx->page.UserUnit = userunit; |
323 | |
|
324 | 0 | for (i=0;i<4;i++) { |
325 | 0 | pdf_obj *box_obj = NULL; |
326 | |
|
327 | 0 | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
328 | 0 | if (code >= 0) { |
329 | 0 | code = pdfi_obj_to_real(ctx, box_obj, &d[i]); |
330 | 0 | pdfi_countdown(box_obj); |
331 | 0 | } |
332 | |
|
333 | 0 | if (code < 0) { |
334 | 0 | pdfi_countdown(a); |
335 | 0 | pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_get_media_size", NULL); |
336 | 0 | code = gs_erasepage(ctx->pgs); |
337 | 0 | return 0; |
338 | 0 | } |
339 | 0 | d[i] *= userunit; |
340 | 0 | } |
341 | 0 | pdfi_countdown(a); |
342 | |
|
343 | 0 | normalize_rectangle(d); |
344 | 0 | memcpy(ctx->page.Size, d, 4 * sizeof(double)); |
345 | |
|
346 | 0 | code = pdfi_dict_get_int(ctx, page_dict, "Rotate", &rotate); |
347 | |
|
348 | 0 | rotate = rotate % 360; |
349 | |
|
350 | 0 | switch(rotate) { |
351 | 0 | default: |
352 | 0 | case 0: |
353 | 0 | case 360: |
354 | 0 | case -180: |
355 | 0 | case 180: |
356 | 0 | fv[0] = (float)(d[2] - d[0]); |
357 | 0 | fv[1] = (float)(d[3] - d[1]); |
358 | 0 | break; |
359 | 0 | case -90: |
360 | 0 | case 90: |
361 | 0 | case -270: |
362 | 0 | case 270: |
363 | 0 | fv[1] = (float)(d[2] - d[0]); |
364 | 0 | fv[0] = (float)(d[3] - d[1]); |
365 | 0 | break; |
366 | 0 | } |
367 | | |
368 | 0 | fa.persistent = false; |
369 | 0 | fa.data = fv; |
370 | 0 | fa.size = 2; |
371 | | |
372 | | /* ----- setup specific device parameters ----- */ |
373 | 0 | gs_c_param_list_write(&list, ctx->memory); |
374 | |
|
375 | 0 | code = param_write_float_array((gs_param_list *)&list, ".MediaSize", &fa); |
376 | 0 | if (code >= 0) |
377 | 0 | { |
378 | 0 | gx_device *dev = gs_currentdevice(ctx->pgs); |
379 | |
|
380 | 0 | gs_c_param_list_read(&list); |
381 | 0 | code = gs_putdeviceparams(dev, (gs_param_list *)&list); |
382 | 0 | if (code < 0) { |
383 | 0 | gs_c_param_list_release(&list); |
384 | 0 | return code; |
385 | 0 | } |
386 | 0 | } |
387 | 0 | gs_c_param_list_release(&list); |
388 | | /* ----- end setup specific device parameters ----- */ |
389 | | |
390 | | /* Resets the default matrix to NULL before doing initgraphics, because |
391 | | * otherwise initgraphics would keep old matrix. |
392 | | * (see pdfi_set_ctm()) |
393 | | */ |
394 | 0 | gs_setdefaultmatrix(ctx->pgs, NULL); |
395 | 0 | gs_initgraphics(ctx->pgs); |
396 | |
|
397 | 0 | switch(rotate) { |
398 | 0 | case 0: |
399 | 0 | break; |
400 | 0 | case -270: |
401 | 0 | case 90: |
402 | 0 | gs_translate(ctx->pgs, 0, fv[1]); |
403 | 0 | gs_rotate(ctx->pgs, -90); |
404 | 0 | break; |
405 | 0 | case -180: |
406 | 0 | case 180: |
407 | 0 | gs_translate(ctx->pgs, fv[0], fv[1]); |
408 | 0 | gs_rotate(ctx->pgs, 180); |
409 | 0 | break; |
410 | 0 | case -90: |
411 | 0 | case 270: |
412 | 0 | gs_translate(ctx->pgs, fv[0], 0); |
413 | 0 | gs_rotate(ctx->pgs, 90); |
414 | 0 | break; |
415 | 0 | default: |
416 | 0 | break; |
417 | 0 | } |
418 | | |
419 | 0 | if (do_crop) { |
420 | 0 | bbox.p.x = d_crop[0] - d[0]; |
421 | 0 | bbox.p.y = d_crop[1] - d[1]; |
422 | 0 | bbox.q.x = d_crop[2] - d[0]; |
423 | 0 | bbox.q.y = d_crop[3] - d[1]; |
424 | |
|
425 | 0 | code = gs_rectclip(ctx->pgs, &bbox, 1); |
426 | 0 | if (code < 0) |
427 | 0 | return code; |
428 | 0 | } |
429 | | |
430 | 0 | gs_translate(ctx->pgs, d[0] * -1, d[1] * -1); |
431 | |
|
432 | 0 | code = gs_erasepage(ctx->pgs); |
433 | 0 | return 0; |
434 | 0 | } |
435 | | |
436 | | /* Setup default transfer functions */ |
437 | | static void pdfi_setup_transfers(pdf_context *ctx) |
438 | 43.3k | { |
439 | 43.3k | if (ctx->pgs->set_transfer.red == 0x00) { |
440 | 43.3k | ctx->page.DefaultTransfers[0].proc = gs_identity_transfer; |
441 | 43.3k | memset(ctx->page.DefaultTransfers[0].values, 0x00, transfer_map_size * sizeof(frac)); |
442 | 43.3k | } else { |
443 | 0 | ctx->page.DefaultTransfers[0].proc = ctx->pgs->set_transfer.red->proc; |
444 | 0 | memcpy(ctx->page.DefaultTransfers[0].values, ctx->pgs->set_transfer.red->values, transfer_map_size * sizeof(frac)); |
445 | 0 | } |
446 | 43.3k | if (ctx->pgs->set_transfer.green == 0x00) { |
447 | 43.3k | ctx->page.DefaultTransfers[1].proc = gs_identity_transfer; |
448 | 43.3k | memset(ctx->page.DefaultTransfers[1].values, 0x00, transfer_map_size * sizeof(frac)); |
449 | 43.3k | } else { |
450 | 0 | ctx->page.DefaultTransfers[1].proc = ctx->pgs->set_transfer.green->proc; |
451 | 0 | memcpy(ctx->page.DefaultTransfers[1].values, ctx->pgs->set_transfer.green->values, transfer_map_size * sizeof(frac)); |
452 | 0 | } |
453 | 43.3k | if (ctx->pgs->set_transfer.blue == 0x00) { |
454 | 43.3k | ctx->page.DefaultTransfers[2].proc = gs_identity_transfer; |
455 | 43.3k | memset(ctx->page.DefaultTransfers[2].values, 0x00, transfer_map_size * sizeof(frac)); |
456 | 43.3k | } else { |
457 | 0 | ctx->page.DefaultTransfers[2].proc = ctx->pgs->set_transfer.blue->proc; |
458 | 0 | memcpy(ctx->page.DefaultTransfers[2].values, ctx->pgs->set_transfer.blue->values, transfer_map_size * sizeof(frac)); |
459 | 0 | } |
460 | 43.3k | if (ctx->pgs->set_transfer.gray == 0x00) { |
461 | 0 | ctx->page.DefaultTransfers[3].proc = gs_identity_transfer; |
462 | 0 | memset(ctx->page.DefaultTransfers[3].values, 0x00, transfer_map_size * sizeof(frac)); |
463 | 43.3k | } else { |
464 | 43.3k | ctx->page.DefaultTransfers[3].proc = ctx->pgs->set_transfer.gray->proc; |
465 | 43.3k | memcpy(ctx->page.DefaultTransfers[3].values, ctx->pgs->set_transfer.gray->values, transfer_map_size * sizeof(frac)); |
466 | 43.3k | } |
467 | 43.3k | if (ctx->pgs->black_generation == 0x00) { |
468 | 0 | ctx->page.DefaultBG.proc = gs_identity_transfer; |
469 | 0 | memset(ctx->page.DefaultBG.values, 0x00, transfer_map_size * sizeof(frac)); |
470 | 43.3k | } else { |
471 | 43.3k | ctx->page.DefaultBG.proc = ctx->pgs->black_generation->proc; |
472 | 43.3k | memcpy(ctx->page.DefaultBG.values, ctx->pgs->black_generation->values, transfer_map_size * sizeof(frac)); |
473 | 43.3k | } |
474 | 43.3k | if (ctx->pgs->undercolor_removal == 0x00) { |
475 | 0 | ctx->page.DefaultUCR.proc = gs_identity_transfer; |
476 | 0 | memset(ctx->page.DefaultUCR.values, 0x00, transfer_map_size * sizeof(frac)); |
477 | 43.3k | } else { |
478 | 43.3k | ctx->page.DefaultUCR.proc = ctx->pgs->undercolor_removal->proc; |
479 | 43.3k | memcpy(ctx->page.DefaultUCR.values, ctx->pgs->undercolor_removal->values, transfer_map_size * sizeof(frac)); |
480 | 43.3k | } |
481 | 43.3k | } |
482 | | |
483 | | /* Return a dictionary containing information about the page. Basic information is that |
484 | | * required to render the page; if extended is true then additionally contains an |
485 | | * array of spot ink names and an array of dictionaries each of which contains |
486 | | * information about a font used on the page. THis is normally only used for tools |
487 | | * like pdf_info.ps |
488 | | */ |
489 | | int pdfi_page_info(pdf_context *ctx, uint64_t page_num, pdf_dict **info, bool extended) |
490 | 54.0k | { |
491 | 54.0k | int code = 0, i=0; |
492 | 54.0k | pdf_dict *page_dict = NULL, *info_dict = NULL; |
493 | 54.0k | pdf_array *fonts_array = NULL, *spots_array = NULL; |
494 | 54.0k | pdf_array *a = NULL; |
495 | 54.0k | pdf_obj *o = NULL; |
496 | 54.0k | bool known = false; |
497 | 54.0k | double dummy; |
498 | | |
499 | 54.0k | code = pdfi_page_get_dict(ctx, page_num, &page_dict); |
500 | 54.0k | if (code < 0) |
501 | 10.5k | return code; |
502 | | |
503 | 43.5k | if (code > 0) { |
504 | 0 | code = gs_note_error(gs_error_unknownerror); |
505 | 0 | goto done; |
506 | 0 | } |
507 | | |
508 | 43.5k | code = pdfi_dict_alloc(ctx, 6, &info_dict); |
509 | 43.5k | if (code < 0) |
510 | 0 | goto done; |
511 | | |
512 | 43.5k | pdfi_countup(info_dict); |
513 | | |
514 | 43.5k | if (extended) |
515 | 0 | code = pdfi_check_page(ctx, page_dict, &fonts_array, &spots_array, false); |
516 | 43.5k | else |
517 | 43.5k | code = pdfi_check_page(ctx, page_dict, NULL, NULL, false); |
518 | 43.5k | if (code < 0) |
519 | 0 | goto done; |
520 | | |
521 | 43.5k | if (spots_array != NULL) { |
522 | 0 | code = pdfi_dict_put(ctx, info_dict, "Spots", (pdf_obj *)spots_array); |
523 | 0 | if (code < 0) |
524 | 0 | goto done; |
525 | 0 | pdfi_countdown(spots_array); |
526 | 0 | } |
527 | | |
528 | 43.5k | if (fonts_array != NULL) { |
529 | 0 | code = pdfi_dict_put(ctx, info_dict, "Fonts", (pdf_obj *)fonts_array); |
530 | 0 | if (code < 0) |
531 | 0 | goto done; |
532 | 0 | pdfi_countdown(fonts_array); |
533 | 0 | } |
534 | | |
535 | 43.5k | code = pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&a); |
536 | 43.5k | if (code < 0) |
537 | 212 | pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_page_info", NULL); |
538 | | |
539 | 43.5k | if (code >= 0) { |
540 | 43.3k | pdf_obj *box_obj = NULL; |
541 | | |
542 | 216k | for (i = 0;i < pdfi_array_size(a); i++) { |
543 | 173k | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
544 | 173k | if (code >= 0) { |
545 | 173k | code = pdfi_obj_to_real(ctx, box_obj, &dummy); |
546 | 173k | pdfi_countdown(box_obj); |
547 | 173k | } |
548 | 173k | if (code < 0) { |
549 | 42 | pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_page_info", NULL); |
550 | 42 | goto done; |
551 | 42 | } |
552 | 173k | } |
553 | | |
554 | 43.2k | code = pdfi_dict_put(ctx, info_dict, "MediaBox", (pdf_obj *)a); |
555 | 43.2k | if (code < 0) |
556 | 0 | goto done; |
557 | 43.2k | pdfi_countdown(a); |
558 | 43.2k | a = NULL; |
559 | 43.2k | } |
560 | | |
561 | 43.4k | code = pdfi_dict_get_type(ctx, page_dict, "ArtBox", PDF_ARRAY, (pdf_obj **)&a); |
562 | 43.4k | if (code >= 0) { |
563 | 3.85k | pdf_obj *box_obj = NULL; |
564 | | |
565 | 19.2k | for (i = 0;i < pdfi_array_size(a); i++) { |
566 | 15.4k | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
567 | 15.4k | if (code >= 0) { |
568 | 15.4k | code = pdfi_obj_to_real(ctx, box_obj, &dummy); |
569 | 15.4k | pdfi_countdown(box_obj); |
570 | 15.4k | } |
571 | 15.4k | if (code < 0) |
572 | 0 | break; |
573 | 15.4k | } |
574 | 3.85k | if (code >= 0) { |
575 | 3.85k | code = pdfi_dict_put(ctx, info_dict, "ArtBox", (pdf_obj *)a); |
576 | 3.85k | if (code < 0) |
577 | 0 | goto done; |
578 | 3.85k | } |
579 | 3.85k | pdfi_countdown(a); |
580 | 3.85k | a = NULL; |
581 | 3.85k | } |
582 | | |
583 | 43.4k | code = pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a); |
584 | 43.4k | if (code >= 0) { |
585 | 23.0k | pdf_obj *box_obj = NULL; |
586 | | |
587 | 115k | for (i = 0;i < pdfi_array_size(a); i++) { |
588 | 92.0k | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
589 | 92.0k | if (code >= 0) { |
590 | 92.0k | code = pdfi_obj_to_real(ctx, box_obj, &dummy); |
591 | 92.0k | pdfi_countdown(box_obj); |
592 | 92.0k | } |
593 | 92.0k | if (code < 0) |
594 | 14 | break; |
595 | 92.0k | } |
596 | 23.0k | if (code >= 0) { |
597 | 22.9k | code = pdfi_dict_put(ctx, info_dict, "CropBox", (pdf_obj *)a); |
598 | 22.9k | if (code < 0) |
599 | 0 | goto done; |
600 | 22.9k | } |
601 | 23.0k | pdfi_countdown(a); |
602 | 23.0k | a = NULL; |
603 | 23.0k | } |
604 | | |
605 | 43.4k | code = pdfi_dict_get_type(ctx, page_dict, "TrimBox", PDF_ARRAY, (pdf_obj **)&a); |
606 | 43.4k | if (code >= 0) { |
607 | 4.00k | pdf_obj *box_obj = NULL; |
608 | | |
609 | 20.0k | for (i = 0;i < pdfi_array_size(a); i++) { |
610 | 16.0k | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
611 | 16.0k | if (code >= 0) { |
612 | 16.0k | code = pdfi_obj_to_real(ctx, box_obj, &dummy); |
613 | 16.0k | pdfi_countdown(box_obj); |
614 | 16.0k | } |
615 | 16.0k | if (code < 0) |
616 | 1 | break; |
617 | 16.0k | } |
618 | 4.00k | if (code >= 0) { |
619 | 4.00k | code = pdfi_dict_put(ctx, info_dict, "TrimBox", (pdf_obj *)a); |
620 | 4.00k | if (code < 0) |
621 | 0 | goto done; |
622 | 4.00k | } |
623 | 4.00k | pdfi_countdown(a); |
624 | 4.00k | a = NULL; |
625 | 4.00k | } |
626 | | |
627 | 43.4k | code = pdfi_dict_get_type(ctx, page_dict, "BleedBox", PDF_ARRAY, (pdf_obj **)&a); |
628 | 43.4k | if (code >= 0) { |
629 | 3.93k | pdf_obj *box_obj = NULL; |
630 | | |
631 | 19.6k | for (i = 0;i < pdfi_array_size(a); i++) { |
632 | 15.7k | code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj); |
633 | 15.7k | if (code >= 0) { |
634 | 15.7k | code = pdfi_obj_to_real(ctx, box_obj, &dummy); |
635 | 15.7k | pdfi_countdown(box_obj); |
636 | 15.7k | } |
637 | 15.7k | if (code < 0) |
638 | 0 | break; |
639 | 15.7k | } |
640 | 3.93k | if (code >= 0) { |
641 | 3.93k | code = pdfi_dict_put(ctx, info_dict, "BleedBox", (pdf_obj *)a); |
642 | 3.93k | if (code < 0) |
643 | 0 | goto done; |
644 | 3.93k | } |
645 | 3.93k | pdfi_countdown(a); |
646 | 3.93k | a = NULL; |
647 | 3.93k | } |
648 | 43.4k | code = 0; |
649 | | |
650 | 43.4k | code = pdfi_dict_get(ctx, page_dict, "Rotate", &o); |
651 | 43.4k | if (code >= 0) { |
652 | 22.0k | if (pdfi_type_of(o) == PDF_INT || pdfi_type_of(o) == PDF_REAL) { |
653 | 22.0k | code = pdfi_dict_put(ctx, info_dict, "Rotate", o); |
654 | 22.0k | if (code < 0) |
655 | 0 | goto done; |
656 | 22.0k | } |
657 | 22.0k | pdfi_countdown(o); |
658 | 22.0k | } |
659 | | |
660 | 43.4k | code = pdfi_dict_get(ctx, page_dict, "UserUnit", &o); |
661 | 43.4k | if (code >= 0) { |
662 | 257 | if (pdfi_type_of(o) == PDF_INT || pdfi_type_of(o) == PDF_REAL) { |
663 | 257 | code = pdfi_dict_put(ctx, info_dict, "UserUnit", o); |
664 | 257 | if (code < 0) |
665 | 0 | goto done; |
666 | 257 | } |
667 | 257 | pdfi_countdown(o); |
668 | 257 | } |
669 | | |
670 | 43.4k | if (ctx->page.has_transparency) |
671 | 2.61k | code = pdfi_dict_put(ctx, info_dict, "UsesTransparency", PDF_TRUE_OBJ); |
672 | 40.8k | else |
673 | 40.8k | code = pdfi_dict_put(ctx, info_dict, "UsesTransparency", PDF_FALSE_OBJ); |
674 | 43.4k | if (code < 0) |
675 | 0 | goto done; |
676 | | |
677 | 43.4k | code = pdfi_dict_known(ctx, page_dict, "Annots", &known); |
678 | 43.4k | if (code >= 0 && known) |
679 | 18.7k | code = pdfi_dict_put(ctx, info_dict, "Annots", PDF_TRUE_OBJ); |
680 | 24.7k | else |
681 | 24.7k | code = pdfi_dict_put(ctx, info_dict, "Annots", PDF_FALSE_OBJ); |
682 | 43.4k | if (code < 0) |
683 | 0 | goto done; |
684 | | |
685 | 43.4k | code = pdfi_object_alloc(ctx, PDF_INT, 0, &o); |
686 | 43.4k | if (code >= 0) { |
687 | 43.4k | pdfi_countup(o); |
688 | 43.4k | ((pdf_num *)o)->value.i = ctx->page.num_spots; |
689 | 43.4k | code = pdfi_dict_put(ctx, info_dict, "NumSpots", o); |
690 | 43.4k | pdfi_countdown(o); |
691 | 43.4k | o = NULL; |
692 | 43.4k | if (code < 0) |
693 | 0 | goto done; |
694 | 43.4k | } |
695 | | |
696 | 43.5k | done: |
697 | 43.5k | if (code < 0) { |
698 | 42 | pdfi_countdown(info_dict); |
699 | 42 | info_dict = NULL; |
700 | 42 | *info = NULL; |
701 | 42 | } else |
702 | 43.4k | *info = info_dict; |
703 | | |
704 | 43.5k | pdfi_countdown(a); |
705 | 43.5k | pdfi_countdown(page_dict); |
706 | 43.5k | return code; |
707 | 43.4k | } |
708 | | |
709 | | int pdfi_page_get_dict(pdf_context *ctx, uint64_t page_num, pdf_dict **dict) |
710 | 97.5k | { |
711 | 97.5k | int code = 0; |
712 | 97.5k | uint64_t page_offset = 0; |
713 | | |
714 | 97.5k | code = pdfi_loop_detector_mark(ctx); |
715 | 97.5k | if (code < 0) |
716 | 0 | return code; |
717 | | |
718 | 97.5k | if (ctx->PagesTree == NULL) { |
719 | 239 | pdf_obj *o = NULL; |
720 | 239 | pdf_name *n = NULL; |
721 | | /* The only way this should be true is if the Pages entry in the Root dictionary |
722 | | * points to a single instance of a Page dictionary, instead of to a Pages dictionary. |
723 | | * in which case, simply retrieve that dictionary and return. |
724 | | */ |
725 | 239 | code = pdfi_dict_get(ctx, ctx->Root, "Pages", &o); |
726 | 239 | if (code < 0) |
727 | 0 | goto page_error; |
728 | 239 | if (pdfi_type_of(o) != PDF_DICT) { |
729 | 0 | code = gs_note_error(gs_error_typecheck); |
730 | 0 | goto page_error; |
731 | 0 | } |
732 | 239 | code = pdfi_dict_get_type(ctx, (pdf_dict *)o, "Type", PDF_NAME, (pdf_obj **)&n); |
733 | 239 | if (code == 0) { |
734 | 239 | if(pdfi_name_is(n, "Page")) { |
735 | 239 | *dict = (pdf_dict *)o; |
736 | 239 | pdfi_countup(*dict); |
737 | 239 | } else |
738 | 0 | code = gs_note_error(gs_error_undefined); |
739 | 239 | } |
740 | 239 | page_error: |
741 | 239 | pdfi_loop_detector_cleartomark(ctx); |
742 | 239 | pdfi_countdown(o); |
743 | 239 | pdfi_countdown(n); |
744 | 239 | return code; |
745 | 239 | } |
746 | | |
747 | 97.2k | code = pdfi_loop_detector_add_object(ctx, ctx->PagesTree->object_num); |
748 | 97.2k | if (code < 0) |
749 | 0 | goto exit; |
750 | | |
751 | 97.2k | code = pdfi_get_page_dict(ctx, ctx->PagesTree, page_num, &page_offset, dict, NULL); |
752 | 97.2k | if (code > 0) |
753 | 0 | code = gs_error_unknownerror; |
754 | | |
755 | | /* Cache the page_dict number in page_array */ |
756 | 97.2k | if (*dict) |
757 | 86.7k | ctx->page_array[page_num] = (*dict)->object_num; |
758 | | |
759 | 97.2k | exit: |
760 | 97.2k | pdfi_loop_detector_cleartomark(ctx); |
761 | 97.2k | return code; |
762 | 97.2k | } |
763 | | |
764 | | /* Find the page number that corresponds to a page dictionary |
765 | | * Uses page_array cache to minimize the number of times a page_dict needs to |
766 | | * be fetched, because this is expensive. |
767 | | */ |
768 | | int pdfi_page_get_number(pdf_context *ctx, pdf_dict *target_dict, uint64_t *page_num) |
769 | 7.10k | { |
770 | 7.10k | uint64_t i; |
771 | 7.10k | int code = 0; |
772 | 7.10k | pdf_dict *page_dict = NULL; |
773 | 7.10k | uint32_t object_num; |
774 | | |
775 | 7.23k | for (i=0; i<ctx->num_pages; i++) { |
776 | | /* If the page has been processed before, then its object_num should already |
777 | | * be cached in the page_array, so check that first |
778 | | */ |
779 | 7.23k | object_num = ctx->page_array[i]; |
780 | 7.23k | if (object_num == 0) { |
781 | | /* It wasn't cached, so this will cache it */ |
782 | 70 | code = pdfi_page_get_dict(ctx, i, &page_dict); |
783 | 70 | if (code < 0) |
784 | 0 | continue; |
785 | 70 | object_num = ctx->page_array[i]; |
786 | 70 | } |
787 | 7.23k | if (target_dict->object_num == object_num) { |
788 | 7.10k | *page_num = i; |
789 | 7.10k | goto exit; |
790 | 7.10k | } |
791 | | |
792 | 133 | pdfi_countdown(page_dict); |
793 | 133 | page_dict = NULL; |
794 | 133 | } |
795 | | |
796 | 0 | code = gs_note_error(gs_error_undefined); |
797 | |
|
798 | 7.10k | exit: |
799 | 7.10k | pdfi_countdown(page_dict); |
800 | 7.10k | return code; |
801 | 0 | } |
802 | | |
803 | | static void release_page_DefaultSpaces(pdf_context *ctx) |
804 | 86.7k | { |
805 | 86.7k | if (ctx->page.DefaultGray_cs != NULL) { |
806 | 0 | if (ctx->page.DefaultGray_cs->interpreter_data != NULL) { |
807 | 0 | pdf_obj *o = (pdf_obj *)(ctx->page.DefaultGray_cs->interpreter_data); |
808 | 0 | if (o != NULL && pdfi_type_of(o) == PDF_NAME) { |
809 | 0 | pdfi_countdown(o); |
810 | 0 | ctx->page.DefaultGray_cs->interpreter_data = NULL; |
811 | 0 | } |
812 | 0 | } |
813 | 0 | rc_decrement(ctx->page.DefaultGray_cs, "pdfi_page_render"); |
814 | 0 | ctx->page.DefaultGray_cs = NULL; |
815 | 0 | } |
816 | 86.7k | if (ctx->page.DefaultRGB_cs != NULL) { |
817 | 127 | if (ctx->page.DefaultRGB_cs->interpreter_data != NULL) { |
818 | 127 | pdf_obj *o = (pdf_obj *)(ctx->page.DefaultRGB_cs->interpreter_data); |
819 | 127 | if (o != NULL && pdfi_type_of(o) == PDF_NAME) { |
820 | 28 | pdfi_countdown(o); |
821 | 28 | ctx->page.DefaultRGB_cs->interpreter_data = NULL; |
822 | 28 | } |
823 | 127 | } |
824 | 127 | rc_decrement(ctx->page.DefaultRGB_cs, "pdfi_page_render"); |
825 | 127 | ctx->page.DefaultRGB_cs = NULL; |
826 | 127 | } |
827 | 86.7k | if (ctx->page.DefaultCMYK_cs != NULL) { |
828 | 8 | if (ctx->page.DefaultCMYK_cs->interpreter_data != NULL) { |
829 | 8 | pdf_obj *o = (pdf_obj *)(ctx->page.DefaultCMYK_cs->interpreter_data); |
830 | 8 | if (o != NULL && pdfi_type_of(o) == PDF_NAME) { |
831 | 0 | pdfi_countdown(o); |
832 | 0 | ctx->page.DefaultCMYK_cs->interpreter_data = NULL; |
833 | 0 | } |
834 | 8 | } |
835 | 8 | rc_decrement(ctx->page.DefaultCMYK_cs, "pdfi_page_render"); |
836 | 8 | ctx->page.DefaultCMYK_cs = NULL; |
837 | 8 | } |
838 | 86.7k | } |
839 | | |
840 | | static int setup_page_DefaultSpaces(pdf_context *ctx, pdf_dict *page_dict) |
841 | 43.3k | { |
842 | | /* First off, discard any dangling Default* colour spaces, just in case. */ |
843 | 43.3k | release_page_DefaultSpaces(ctx); |
844 | | |
845 | 43.3k | return(pdfi_setup_DefaultSpaces(ctx, page_dict)); |
846 | 43.3k | } |
847 | | |
848 | | static bool |
849 | | pdfi_pattern_purge_all_proc(gx_color_tile * ctile, void *proc_data) |
850 | 6.96k | { |
851 | 6.96k | return true; |
852 | 6.96k | } |
853 | | |
854 | | int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics) |
855 | 43.3k | { |
856 | 43.3k | int code, code1=0; |
857 | 43.3k | pdf_dict *page_dict = NULL; |
858 | 43.3k | bool page_group_known = false; |
859 | 43.3k | pdf_dict *group_dict = NULL; |
860 | 43.3k | bool page_dict_error = false; |
861 | 43.3k | bool need_pdf14 = false; /* true if the device is needed and was successfully pushed */ |
862 | 43.3k | int trans_depth = 0; /* -1 means special mode for transparency simulation */ |
863 | | |
864 | 43.3k | if (page_num > ctx->num_pages) |
865 | 0 | return_error(gs_error_rangecheck); |
866 | | |
867 | 43.3k | if (ctx->args.pdfdebug) |
868 | 43.3k | dmprintf1(ctx->memory, "%% Processing Page %"PRIi64" content stream\n", page_num + 1); |
869 | | |
870 | 43.3k | code = pdfi_page_get_dict(ctx, page_num, &page_dict); |
871 | 43.3k | if (code < 0) { |
872 | 0 | char extra_info[256]; |
873 | |
|
874 | 0 | page_dict_error = true; |
875 | 0 | gs_snprintf(extra_info, sizeof(extra_info), "*** ERROR: Page %ld has invalid Page dict, skipping\n", page_num+1); |
876 | 0 | pdfi_set_error(ctx, 0, NULL, E_PDF_PAGEDICTERROR, "pdfi_page_render", extra_info); |
877 | 0 | if (code != gs_error_VMerror && !ctx->args.pdfstoponerror) |
878 | 0 | code = 0; |
879 | 0 | goto exit3; |
880 | 0 | } |
881 | | |
882 | 43.3k | code = pdfi_check_page(ctx, page_dict, NULL, NULL, init_graphics); |
883 | 43.3k | if (code < 0) |
884 | 0 | goto exit3; |
885 | | |
886 | 43.3k | if (ctx->args.pdfdebug) { |
887 | 0 | dbgmprintf2(ctx->memory, "Current page %ld transparency setting is %d", page_num+1, |
888 | 0 | ctx->page.has_transparency); |
889 | |
|
890 | 0 | if (ctx->device_state.spot_capable) |
891 | 0 | dbgmprintf1(ctx->memory, ", spots=%d\n", ctx->page.num_spots); |
892 | 0 | else |
893 | 0 | dbgmprintf(ctx->memory, "\n"); |
894 | 0 | } |
895 | | |
896 | 43.3k | code = pdfi_dict_knownget_type(ctx, page_dict, "Group", PDF_DICT, (pdf_obj **)&group_dict); |
897 | | /* Ignore errors retrieving the Group dictionary, we will just ignore it. This allows us |
898 | | * to handle files such as Bug #705206 where the Group dictionary is a free object in a |
899 | | * compressed object stream. |
900 | | */ |
901 | 43.3k | if (code < 0) |
902 | 49 | pdfi_set_error(ctx, 0, NULL, E_BAD_GROUP_DICT, "pdfi_page_render", NULL); |
903 | 43.3k | if (group_dict != NULL) |
904 | 2.72k | page_group_known = true; |
905 | | |
906 | 43.3k | pdfi_countdown(ctx->page.CurrentPageDict); |
907 | 43.3k | ctx->page.CurrentPageDict = page_dict; |
908 | 43.3k | pdfi_countup(ctx->page.CurrentPageDict); |
909 | | |
910 | | /* In case we don't call pdfi_set_media_size, which sets this up. |
911 | | * We shouldn't ever use it in that case, but best to be safe. |
912 | | */ |
913 | 43.3k | ctx->page.UserUnit = 1.0f; |
914 | | /* If we are being called from the PDF interpreter then |
915 | | * we need to set up the page and the default graphics state |
916 | | * but if we are being called from PostScript we do *not* |
917 | | * want to alter any of the graphics state or the media size. |
918 | | */ |
919 | | /* TODO: I think this is a mix of things we might need to |
920 | | * still be setting up. |
921 | | * (for example, I noticed the blendmode and moved it outside the if) |
922 | | */ |
923 | 43.3k | if (init_graphics) { |
924 | 0 | code = pdfi_set_media_size(ctx, page_dict); |
925 | 0 | if (code < 0) |
926 | 0 | goto exit2; |
927 | | |
928 | 0 | pdfi_set_ctm(ctx); |
929 | |
|
930 | 43.3k | } else { |
931 | | /* Gets ctx->page.Size setup correctly |
932 | | * TODO: Probably not right if the page is rotated? |
933 | | * page.Size is needed by the transparency code, |
934 | | * not sure where else it might be used, if anywhere. |
935 | | */ |
936 | 43.3k | pdfi_get_media_size(ctx, page_dict); |
937 | 43.3k | } |
938 | | |
939 | | /* Write the various CropBox, TrimBox etc to the device */ |
940 | 43.3k | pdfi_pdfmark_write_boxes(ctx, page_dict); |
941 | | |
942 | 43.3k | code = setup_page_DefaultSpaces(ctx, page_dict); |
943 | 43.3k | if (code < 0) |
944 | 0 | goto exit2; |
945 | | |
946 | 43.3k | pdfi_setup_transfers(ctx); |
947 | | |
948 | | /* Set whether device needs OP support |
949 | | * This needs to be before transparency device is pushed, if applicable |
950 | | */ |
951 | 43.3k | pdfi_trans_set_needs_OP(ctx); |
952 | 43.3k | pdfi_oc_init(ctx); |
953 | | |
954 | 43.3k | code = pdfi_gsave(ctx); |
955 | 43.3k | if (code < 0) |
956 | 0 | goto exit2; |
957 | | |
958 | | /* Figure out if pdf14 device is needed. |
959 | | * This can be either for normal transparency deviceN, or because we are using |
960 | | * Overprint=/simulate for other devices |
961 | | */ |
962 | 43.3k | if (ctx->page.has_transparency) { |
963 | 2.60k | need_pdf14 = true; |
964 | 2.60k | if (ctx->page.simulate_op) |
965 | 0 | trans_depth = -1; |
966 | 40.7k | } else { |
967 | | /* This is the case where we are simulating overprint without transparency */ |
968 | 40.7k | if (ctx->page.simulate_op) { |
969 | 0 | need_pdf14 = true; |
970 | 0 | trans_depth = -1; |
971 | 0 | } |
972 | 40.7k | } |
973 | 43.3k | if (need_pdf14) { |
974 | | /* We don't retain the PDF14 device */ |
975 | 2.60k | code = gs_push_pdf14trans_device(ctx->pgs, false, false, trans_depth, ctx->page.num_spots); |
976 | 2.60k | if (code >= 0) { |
977 | 2.60k | if (ctx->page.has_transparency && page_group_known) { |
978 | 1.02k | code = pdfi_trans_begin_page_group(ctx, page_dict, group_dict); |
979 | | /* If setting the page group failed for some reason, abandon the page group, |
980 | | * but continue with the page |
981 | | */ |
982 | 1.02k | if (code < 0) |
983 | 27 | page_group_known = false; |
984 | 1.02k | } |
985 | 2.60k | } else { |
986 | | /* Couldn't push the transparency compositor. |
987 | | * This is probably fatal, but attempt to recover by abandoning transparency |
988 | | */ |
989 | 0 | ctx->page.has_transparency = false; |
990 | 0 | need_pdf14 = false; |
991 | 0 | } |
992 | 2.60k | } |
993 | | |
994 | | /* Init a base_pgs graphics state for Patterns |
995 | | * (this has to be after transparency device pushed, if applicable) |
996 | | */ |
997 | 43.3k | pdfi_set_DefaultQState(ctx, ctx->pgs); |
998 | | |
999 | | /* Render one page (including annotations) */ |
1000 | 43.3k | if (!ctx->args.QUIET) |
1001 | 0 | outprintf(ctx->memory, "Page %"PRId64"\n", page_num + 1); |
1002 | | |
1003 | 43.3k | code = pdfi_process_one_page(ctx, page_dict); |
1004 | | |
1005 | 43.3k | if (need_pdf14 && ctx->page.has_transparency && page_group_known) { |
1006 | 1.00k | code1 = pdfi_trans_end_group(ctx); |
1007 | 1.00k | } |
1008 | | |
1009 | 43.3k | if (need_pdf14) { |
1010 | 2.60k | if (code1 < 0) { |
1011 | 0 | (void)gs_abort_pdf14trans_device(ctx->pgs); |
1012 | 0 | code = code1; |
1013 | 0 | goto exit1; |
1014 | 0 | } |
1015 | | |
1016 | 2.60k | code = gs_pop_pdf14trans_device(ctx->pgs, false); |
1017 | 2.60k | if (code < 0) { |
1018 | 10 | goto exit1; |
1019 | 10 | } |
1020 | 2.60k | } |
1021 | | |
1022 | 43.3k | exit1: |
1023 | 43.3k | pdfi_free_DefaultQState(ctx); |
1024 | 43.3k | pdfi_grestore(ctx); |
1025 | | |
1026 | 43.3k | exit2: |
1027 | 43.3k | pdfi_countdown(ctx->page.CurrentPageDict); |
1028 | 43.3k | ctx->page.CurrentPageDict = NULL; |
1029 | | |
1030 | 43.3k | exit3: |
1031 | 43.3k | pdfi_countdown(page_dict); |
1032 | 43.3k | pdfi_countdown(group_dict); |
1033 | | |
1034 | 43.3k | release_page_DefaultSpaces(ctx); |
1035 | | |
1036 | | /* Flush any pattern tiles. We don't want to (potentially) return to PostScript |
1037 | | * with any pattern tiles referencing our objects, in case the garbager runs. |
1038 | | */ |
1039 | 43.3k | gx_pattern_cache_winnow(gstate_pattern_cache(ctx->pgs), pdfi_pattern_purge_all_proc, NULL); |
1040 | | |
1041 | 43.3k | if (code == 0 || (!ctx->args.pdfstoponerror && code != gs_error_pdf_stackoverflow)) |
1042 | 43.3k | if (!page_dict_error && ctx->finish_page != NULL) |
1043 | 0 | code = ctx->finish_page(ctx); |
1044 | 43.3k | return code; |
1045 | 43.3k | } |