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