1 | #include "mupdf/fitz.h" |
2 | #include "mupdf/pdf.h" |
3 | |
4 | static void |
5 | pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
6 | { |
7 | fz_matrix page_ctm; |
8 | fz_rect mediabox; |
9 | pdf_processor *proc = NULL; |
10 | fz_default_colorspaces *default_cs = NULL; |
11 | int flags; |
12 | |
13 | fz_var(proc); |
14 | fz_var(default_cs); |
15 | |
16 | if (cookie && page->super.incomplete) |
17 | cookie->incomplete = 1; |
18 | |
19 | fz_try(ctx) |
20 | { |
21 | default_cs = pdf_load_default_colorspaces(ctx, doc, page); |
22 | if (default_cs) |
23 | fz_set_default_colorspaces(ctx, dev, default_cs); |
24 | |
25 | pdf_page_transform(ctx, page, &mediabox, &page_ctm); |
26 | |
27 | flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); |
28 | if (flags & PDF_ANNOT_IS_NO_ROTATE) |
29 | { |
30 | int rotate = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(Rotate))); |
31 | fz_rect rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect)); |
32 | fz_point tp = fz_transform_point_xy(rect.x0, rect.y1, page_ctm); |
33 | page_ctm = fz_concat(page_ctm, fz_translate(-tp.x, -tp.y)); |
34 | page_ctm = fz_concat(page_ctm, fz_rotate(-rotate)); |
35 | page_ctm = fz_concat(page_ctm, fz_translate(tp.x, tp.y)); |
36 | } |
37 | |
38 | ctm = fz_concat(page_ctm, ctm); |
39 | |
40 | proc = pdf_new_run_processor(ctx, dev, ctm, usage, NULL, default_cs, cookie); |
41 | pdf_process_annot(ctx, proc, doc, page, annot, cookie); |
42 | pdf_close_processor(ctx, proc); |
43 | } |
44 | fz_always(ctx) |
45 | { |
46 | pdf_drop_processor(ctx, proc); |
47 | fz_drop_default_colorspaces(ctx, default_cs); |
48 | } |
49 | fz_catch(ctx) |
50 | fz_rethrow(ctx); |
51 | } |
52 | |
53 | static void |
54 | pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
55 | { |
56 | fz_matrix page_ctm; |
57 | pdf_obj *resources; |
58 | pdf_obj *contents; |
59 | fz_rect mediabox; |
60 | pdf_processor *proc = NULL; |
61 | fz_default_colorspaces *default_cs = NULL; |
62 | fz_colorspace *colorspace = NULL; |
63 | |
64 | fz_var(proc); |
65 | fz_var(colorspace); |
66 | fz_var(default_cs); |
67 | |
68 | if (cookie && page->super.incomplete) |
69 | cookie->incomplete = 1; |
70 | |
71 | fz_try(ctx) |
72 | { |
73 | default_cs = pdf_load_default_colorspaces(ctx, doc, page); |
74 | if (default_cs) |
75 | fz_set_default_colorspaces(ctx, dev, default_cs); |
76 | |
77 | pdf_page_transform(ctx, page, &mediabox, &page_ctm); |
78 | ctm = fz_concat(page_ctm, ctm); |
79 | mediabox = fz_transform_rect(mediabox, ctm); |
80 | |
81 | resources = pdf_page_resources(ctx, page); |
82 | contents = pdf_page_contents(ctx, page); |
83 | |
84 | if (page->transparency) |
85 | { |
86 | pdf_obj *group = pdf_page_group(ctx, page); |
87 | |
88 | if (group) |
89 | { |
90 | pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME(CS)); |
91 | if (cs) |
92 | { |
93 | fz_try(ctx) |
94 | colorspace = pdf_load_colorspace(ctx, cs); |
95 | fz_catch(ctx) |
96 | { |
97 | fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); |
98 | fz_warn(ctx, "Ignoring Page blending colorspace." ); |
99 | } |
100 | if (!fz_is_valid_blend_colorspace(ctx, colorspace)) |
101 | { |
102 | fz_warn(ctx, "Ignoring invalid Page blending colorspace: %s." , colorspace->name); |
103 | fz_drop_colorspace(ctx, colorspace); |
104 | colorspace = NULL; |
105 | } |
106 | } |
107 | } |
108 | else |
109 | colorspace = fz_keep_colorspace(ctx, fz_default_output_intent(ctx, default_cs)); |
110 | |
111 | fz_begin_group(ctx, dev, mediabox, colorspace, 1, 0, 0, 1); |
112 | } |
113 | |
114 | proc = pdf_new_run_processor(ctx, dev, ctm, usage, NULL, default_cs, cookie); |
115 | pdf_process_contents(ctx, proc, doc, resources, contents, cookie); |
116 | pdf_close_processor(ctx, proc); |
117 | |
118 | if (page->transparency) |
119 | { |
120 | fz_end_group(ctx, dev); |
121 | } |
122 | } |
123 | fz_always(ctx) |
124 | { |
125 | pdf_drop_processor(ctx, proc); |
126 | fz_drop_colorspace(ctx, colorspace); |
127 | fz_drop_default_colorspaces(ctx, default_cs); |
128 | } |
129 | fz_catch(ctx) |
130 | { |
131 | fz_rethrow(ctx); |
132 | } |
133 | } |
134 | |
135 | /* |
136 | Interpret a loaded page and render it on a device. |
137 | Just the main page contents without the annotations |
138 | |
139 | page: A page loaded by pdf_load_page. |
140 | |
141 | dev: Device used for rendering, obtained from fz_new_*_device. |
142 | |
143 | ctm: A transformation matrix applied to the objects on the page, |
144 | e.g. to scale or rotate the page contents as desired. |
145 | */ |
146 | void pdf_run_page_contents(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
147 | { |
148 | pdf_document *doc = page->doc; |
149 | int nocache; |
150 | |
151 | nocache = !!(dev->hints & FZ_NO_CACHE); |
152 | if (nocache) |
153 | pdf_mark_xref(ctx, doc); |
154 | |
155 | fz_try(ctx) |
156 | { |
157 | pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, "View" , cookie); |
158 | } |
159 | fz_always(ctx) |
160 | { |
161 | if (nocache) |
162 | pdf_clear_xref_to_mark(ctx, doc); |
163 | } |
164 | fz_catch(ctx) |
165 | { |
166 | fz_rethrow(ctx); |
167 | } |
168 | } |
169 | |
170 | /* |
171 | Interpret an annotation and render it on a device. |
172 | |
173 | page: A page loaded by pdf_load_page. |
174 | |
175 | annot: an annotation. |
176 | |
177 | dev: Device used for rendering, obtained from fz_new_*_device. |
178 | |
179 | ctm: A transformation matrix applied to the objects on the page, |
180 | e.g. to scale or rotate the page contents as desired. |
181 | */ |
182 | void pdf_run_annot(fz_context *ctx, pdf_annot *annot, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
183 | { |
184 | pdf_page *page = annot->page; |
185 | pdf_document *doc = page->doc; |
186 | int nocache; |
187 | |
188 | nocache = !!(dev->hints & FZ_NO_CACHE); |
189 | if (nocache) |
190 | pdf_mark_xref(ctx, doc); |
191 | fz_try(ctx) |
192 | { |
193 | pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, "View" , cookie); |
194 | } |
195 | fz_always(ctx) |
196 | { |
197 | if (nocache) |
198 | pdf_clear_xref_to_mark(ctx, doc); |
199 | } |
200 | fz_catch(ctx) |
201 | { |
202 | fz_rethrow(ctx); |
203 | } |
204 | } |
205 | |
206 | static void |
207 | pdf_run_page_widgets_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
208 | { |
209 | pdf_widget *widget; |
210 | |
211 | if (cookie && cookie->progress_max != -1) |
212 | { |
213 | int count = 1; |
214 | for (widget = page->widgets; widget; widget = widget->next) |
215 | count++; |
216 | cookie->progress_max += count; |
217 | } |
218 | |
219 | for (widget = page->widgets; widget; widget = widget->next) |
220 | { |
221 | /* Check the cookie for aborting */ |
222 | if (cookie) |
223 | { |
224 | if (cookie->abort) |
225 | break; |
226 | cookie->progress++; |
227 | } |
228 | |
229 | pdf_run_annot_with_usage(ctx, doc, page, widget, dev, ctm, usage, cookie); |
230 | } |
231 | } |
232 | |
233 | static void |
234 | pdf_run_page_annots_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
235 | { |
236 | pdf_annot *annot; |
237 | |
238 | if (cookie && cookie->progress_max != -1) |
239 | { |
240 | int count = 1; |
241 | for (annot = page->annots; annot; annot = annot->next) |
242 | count++; |
243 | cookie->progress_max += count; |
244 | } |
245 | |
246 | for (annot = page->annots; annot; annot = annot->next) |
247 | { |
248 | /* Check the cookie for aborting */ |
249 | if (cookie) |
250 | { |
251 | if (cookie->abort) |
252 | break; |
253 | cookie->progress++; |
254 | } |
255 | |
256 | pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, usage, cookie); |
257 | } |
258 | } |
259 | |
260 | void pdf_run_page_annots(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
261 | { |
262 | pdf_document *doc = page->doc; |
263 | int nocache; |
264 | |
265 | nocache = !!(dev->hints & FZ_NO_CACHE); |
266 | if (nocache) |
267 | pdf_mark_xref(ctx, doc); |
268 | |
269 | fz_try(ctx) |
270 | { |
271 | pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, "View" , cookie); |
272 | } |
273 | fz_always(ctx) |
274 | { |
275 | if (nocache) |
276 | pdf_clear_xref_to_mark(ctx, doc); |
277 | } |
278 | fz_catch(ctx) |
279 | { |
280 | fz_rethrow(ctx); |
281 | } |
282 | } |
283 | |
284 | void pdf_run_page_widgets(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
285 | { |
286 | pdf_document *doc = page->doc; |
287 | int nocache; |
288 | |
289 | nocache = !!(dev->hints & FZ_NO_CACHE); |
290 | if (nocache) |
291 | pdf_mark_xref(ctx, doc); |
292 | |
293 | fz_try(ctx) |
294 | { |
295 | pdf_run_page_widgets_with_usage(ctx, doc, page, dev, ctm, "View" , cookie); |
296 | } |
297 | fz_always(ctx) |
298 | { |
299 | if (nocache) |
300 | pdf_clear_xref_to_mark(ctx, doc); |
301 | } |
302 | fz_catch(ctx) |
303 | { |
304 | fz_rethrow(ctx); |
305 | } |
306 | } |
307 | |
308 | /* |
309 | Interpret a loaded page and render it on a device. |
310 | |
311 | page: A page loaded by pdf_load_page. |
312 | |
313 | dev: Device used for rendering, obtained from fz_new_*_device. |
314 | |
315 | ctm: A transformation matrix applied to the objects on the page, |
316 | e.g. to scale or rotate the page contents as desired. |
317 | |
318 | usage: The 'usage' for displaying the file (typically |
319 | 'View', 'Print' or 'Export'). NULL means 'View'. |
320 | |
321 | cookie: A pointer to an optional fz_cookie structure that can be used |
322 | to track progress, collect errors etc. |
323 | */ |
324 | void |
325 | pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
326 | { |
327 | int nocache = !!(dev->hints & FZ_NO_CACHE); |
328 | |
329 | if (nocache) |
330 | pdf_mark_xref(ctx, doc); |
331 | fz_try(ctx) |
332 | { |
333 | pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, usage, cookie); |
334 | pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, usage, cookie); |
335 | pdf_run_page_widgets_with_usage(ctx, doc, page, dev, ctm, usage, cookie); |
336 | } |
337 | fz_always(ctx) |
338 | { |
339 | if (nocache) |
340 | pdf_clear_xref_to_mark(ctx, doc); |
341 | } |
342 | fz_catch(ctx) |
343 | { |
344 | fz_rethrow(ctx); |
345 | } |
346 | } |
347 | |
348 | /* |
349 | Interpret a loaded page and render it on a device. |
350 | |
351 | page: A page loaded by pdf_load_page. |
352 | |
353 | dev: Device used for rendering, obtained from fz_new_*_device. |
354 | |
355 | ctm: A transformation matrix applied to the objects on the page, |
356 | e.g. to scale or rotate the page contents as desired. |
357 | */ |
358 | void |
359 | pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
360 | { |
361 | pdf_document *doc = page->doc; |
362 | pdf_run_page_with_usage(ctx, doc, page, dev, ctm, "View" , cookie); |
363 | } |
364 | |
365 | void |
366 | pdf_run_glyph(fz_context *ctx, pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate, fz_default_colorspaces *default_cs) |
367 | { |
368 | pdf_processor *proc; |
369 | |
370 | proc = pdf_new_run_processor(ctx, dev, ctm, "View" , gstate, default_cs, NULL); |
371 | fz_try(ctx) |
372 | { |
373 | pdf_process_glyph(ctx, proc, doc, resources, contents); |
374 | pdf_close_processor(ctx, proc); |
375 | } |
376 | fz_always(ctx) |
377 | pdf_drop_processor(ctx, proc); |
378 | fz_catch(ctx) |
379 | fz_rethrow(ctx); |
380 | } |
381 | |