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