/src/mupdf/source/fitz/util.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2025 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include <float.h> |
26 | | |
27 | | fz_display_list * |
28 | | fz_new_display_list_from_page(fz_context *ctx, fz_page *page) |
29 | 0 | { |
30 | 0 | fz_display_list *list; |
31 | 0 | fz_device *dev = NULL; |
32 | |
|
33 | 0 | fz_var(dev); |
34 | |
|
35 | 0 | list = fz_new_display_list(ctx, fz_bound_page(ctx, page)); |
36 | 0 | fz_try(ctx) |
37 | 0 | { |
38 | 0 | dev = fz_new_list_device(ctx, list); |
39 | 0 | fz_run_page(ctx, page, dev, fz_identity, NULL); |
40 | 0 | fz_close_device(ctx, dev); |
41 | 0 | } |
42 | 0 | fz_always(ctx) |
43 | 0 | { |
44 | 0 | fz_drop_device(ctx, dev); |
45 | 0 | } |
46 | 0 | fz_catch(ctx) |
47 | 0 | { |
48 | 0 | fz_drop_display_list(ctx, list); |
49 | 0 | fz_rethrow(ctx); |
50 | 0 | } |
51 | | |
52 | 0 | return list; |
53 | 0 | } |
54 | | |
55 | | fz_display_list * |
56 | | fz_new_display_list_from_page_number(fz_context *ctx, fz_document *doc, int number) |
57 | 0 | { |
58 | 0 | fz_page *page; |
59 | 0 | fz_display_list *list = NULL; |
60 | |
|
61 | 0 | page = fz_load_page(ctx, doc, number); |
62 | 0 | fz_try(ctx) |
63 | 0 | list = fz_new_display_list_from_page(ctx, page); |
64 | 0 | fz_always(ctx) |
65 | 0 | fz_drop_page(ctx, page); |
66 | 0 | fz_catch(ctx) |
67 | 0 | fz_rethrow(ctx); |
68 | 0 | return list; |
69 | 0 | } |
70 | | |
71 | | fz_display_list * |
72 | | fz_new_display_list_from_page_contents(fz_context *ctx, fz_page *page) |
73 | 0 | { |
74 | 0 | fz_display_list *list; |
75 | 0 | fz_device *dev = NULL; |
76 | |
|
77 | 0 | fz_var(dev); |
78 | |
|
79 | 0 | list = fz_new_display_list(ctx, fz_bound_page(ctx, page)); |
80 | 0 | fz_try(ctx) |
81 | 0 | { |
82 | 0 | dev = fz_new_list_device(ctx, list); |
83 | 0 | fz_run_page_contents(ctx, page, dev, fz_identity, NULL); |
84 | 0 | fz_close_device(ctx, dev); |
85 | 0 | } |
86 | 0 | fz_always(ctx) |
87 | 0 | { |
88 | 0 | fz_drop_device(ctx, dev); |
89 | 0 | } |
90 | 0 | fz_catch(ctx) |
91 | 0 | { |
92 | 0 | fz_drop_display_list(ctx, list); |
93 | 0 | fz_rethrow(ctx); |
94 | 0 | } |
95 | | |
96 | 0 | return list; |
97 | 0 | } |
98 | | |
99 | | fz_pixmap * |
100 | | fz_new_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_colorspace *cs, int alpha) |
101 | 0 | { |
102 | 0 | return fz_new_pixmap_from_display_list_with_separations(ctx, list, ctm, cs, NULL, alpha); |
103 | 0 | } |
104 | | |
105 | | fz_pixmap * |
106 | | fz_new_pixmap_from_display_list_with_separations(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) |
107 | 0 | { |
108 | 0 | fz_rect rect; |
109 | 0 | fz_irect bbox; |
110 | 0 | fz_pixmap *pix; |
111 | |
|
112 | 0 | rect = fz_bound_display_list(ctx, list); |
113 | 0 | rect = fz_transform_rect(rect, ctm); |
114 | 0 | bbox = fz_round_rect(rect); |
115 | |
|
116 | 0 | pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha); |
117 | 0 | if (alpha) |
118 | 0 | fz_clear_pixmap(ctx, pix); |
119 | 0 | else |
120 | 0 | fz_clear_pixmap_with_value(ctx, pix, 0xFF); |
121 | |
|
122 | 0 | fz_try(ctx) |
123 | 0 | fz_fill_pixmap_from_display_list(ctx, list, ctm, pix); |
124 | 0 | fz_catch(ctx) |
125 | 0 | { |
126 | 0 | fz_drop_pixmap(ctx, pix); |
127 | 0 | fz_rethrow(ctx); |
128 | 0 | } |
129 | | |
130 | 0 | return pix; |
131 | 0 | } |
132 | | |
133 | | fz_pixmap * |
134 | | fz_fill_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_pixmap *pix) |
135 | 0 | { |
136 | 0 | fz_device *dev = NULL; |
137 | |
|
138 | 0 | fz_var(dev); |
139 | |
|
140 | 0 | fz_try(ctx) |
141 | 0 | { |
142 | 0 | dev = fz_new_draw_device(ctx, ctm, pix); |
143 | 0 | fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL); |
144 | 0 | fz_close_device(ctx, dev); |
145 | 0 | } |
146 | 0 | fz_always(ctx) |
147 | 0 | fz_drop_device(ctx, dev); |
148 | 0 | fz_catch(ctx) |
149 | 0 | fz_rethrow(ctx); |
150 | | |
151 | 0 | return pix; |
152 | 0 | } |
153 | | |
154 | | fz_pixmap * |
155 | | fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha) |
156 | 0 | { |
157 | 0 | return fz_new_pixmap_from_page_contents_with_separations(ctx, page, ctm, cs, NULL, alpha); |
158 | 0 | } |
159 | | |
160 | | fz_pixmap * |
161 | | fz_new_pixmap_from_page_contents_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) |
162 | 0 | { |
163 | 0 | fz_rect rect; |
164 | 0 | fz_irect bbox; |
165 | 0 | fz_pixmap *pix; |
166 | 0 | fz_device *dev = NULL; |
167 | |
|
168 | 0 | fz_var(dev); |
169 | |
|
170 | 0 | rect = fz_bound_page(ctx, page); |
171 | 0 | rect = fz_transform_rect(rect, ctm); |
172 | 0 | bbox = fz_round_rect(rect); |
173 | |
|
174 | 0 | pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha); |
175 | 0 | if (alpha) |
176 | 0 | fz_clear_pixmap(ctx, pix); |
177 | 0 | else |
178 | 0 | fz_clear_pixmap_with_value(ctx, pix, 0xFF); |
179 | |
|
180 | 0 | fz_try(ctx) |
181 | 0 | { |
182 | 0 | dev = fz_new_draw_device(ctx, ctm, pix); |
183 | 0 | fz_run_page_contents(ctx, page, dev, fz_identity, NULL); |
184 | 0 | fz_close_device(ctx, dev); |
185 | 0 | } |
186 | 0 | fz_always(ctx) |
187 | 0 | { |
188 | 0 | fz_drop_device(ctx, dev); |
189 | 0 | } |
190 | 0 | fz_catch(ctx) |
191 | 0 | { |
192 | 0 | fz_drop_pixmap(ctx, pix); |
193 | 0 | fz_rethrow(ctx); |
194 | 0 | } |
195 | | |
196 | 0 | return pix; |
197 | 0 | } |
198 | | |
199 | | fz_pixmap * |
200 | | fz_new_pixmap_from_page(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha) |
201 | 0 | { |
202 | 0 | return fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, NULL, alpha); |
203 | 0 | } |
204 | | |
205 | | fz_pixmap * |
206 | | fz_new_pixmap_from_page_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) |
207 | 3 | { |
208 | 3 | fz_rect rect; |
209 | 3 | fz_irect bbox; |
210 | 3 | fz_pixmap *pix; |
211 | 3 | fz_device *dev = NULL; |
212 | | |
213 | 3 | fz_var(dev); |
214 | | |
215 | 3 | rect = fz_bound_page(ctx, page); |
216 | 3 | rect = fz_transform_rect(rect, ctm); |
217 | 3 | bbox = fz_round_rect(rect); |
218 | | |
219 | 3 | pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha); |
220 | | |
221 | 6 | fz_try(ctx) |
222 | 6 | { |
223 | 3 | if (alpha) |
224 | 0 | fz_clear_pixmap(ctx, pix); |
225 | 3 | else |
226 | 3 | fz_clear_pixmap_with_value(ctx, pix, 0xFF); |
227 | | |
228 | 3 | dev = fz_new_draw_device(ctx, ctm, pix); |
229 | 3 | fz_run_page(ctx, page, dev, fz_identity, NULL); |
230 | 3 | fz_close_device(ctx, dev); |
231 | 3 | } |
232 | 6 | fz_always(ctx) |
233 | 3 | { |
234 | 3 | fz_drop_device(ctx, dev); |
235 | 3 | } |
236 | 3 | fz_catch(ctx) |
237 | 2 | { |
238 | 2 | fz_drop_pixmap(ctx, pix); |
239 | 2 | fz_rethrow(ctx); |
240 | 2 | } |
241 | | |
242 | 1 | return pix; |
243 | 3 | } |
244 | | |
245 | | fz_pixmap * |
246 | | fz_new_pixmap_from_page_number(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, int alpha) |
247 | 3 | { |
248 | 3 | return fz_new_pixmap_from_page_number_with_separations(ctx, doc, number, ctm, cs, NULL, alpha); |
249 | 3 | } |
250 | | |
251 | | fz_pixmap * |
252 | | fz_new_pixmap_from_page_number_with_separations(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) |
253 | 3 | { |
254 | 3 | fz_page *page; |
255 | 3 | fz_pixmap *pix = NULL; |
256 | | |
257 | 3 | page = fz_load_page(ctx, doc, number); |
258 | 6 | fz_try(ctx) |
259 | 6 | pix = fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, seps, alpha); |
260 | 6 | fz_always(ctx) |
261 | 3 | fz_drop_page(ctx, page); |
262 | 3 | fz_catch(ctx) |
263 | 2 | fz_rethrow(ctx); |
264 | 1 | return pix; |
265 | 3 | } |
266 | | |
267 | | fz_stext_page * |
268 | | fz_new_stext_page_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options) |
269 | 0 | { |
270 | 0 | fz_stext_page *text; |
271 | 0 | fz_device *dev = NULL; |
272 | |
|
273 | 0 | fz_var(dev); |
274 | |
|
275 | 0 | if (list == NULL) |
276 | 0 | return NULL; |
277 | | |
278 | 0 | text = fz_new_stext_page(ctx, fz_bound_display_list(ctx, list)); |
279 | 0 | fz_try(ctx) |
280 | 0 | { |
281 | 0 | dev = fz_new_stext_device(ctx, text, options); |
282 | 0 | fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL); |
283 | 0 | fz_close_device(ctx, dev); |
284 | 0 | } |
285 | 0 | fz_always(ctx) |
286 | 0 | { |
287 | 0 | fz_drop_device(ctx, dev); |
288 | 0 | } |
289 | 0 | fz_catch(ctx) |
290 | 0 | { |
291 | 0 | fz_drop_stext_page(ctx, text); |
292 | 0 | fz_rethrow(ctx); |
293 | 0 | } |
294 | | |
295 | 0 | return text; |
296 | 0 | } |
297 | | |
298 | | fz_stext_page * |
299 | | fz_new_stext_page_from_page_with_cookie(fz_context *ctx, fz_page *page, const fz_stext_options *options, fz_cookie *cookie) |
300 | 0 | { |
301 | 0 | fz_stext_page *text; |
302 | 0 | fz_device *dev = NULL; |
303 | |
|
304 | 0 | fz_var(dev); |
305 | |
|
306 | 0 | if (page == NULL) |
307 | 0 | return NULL; |
308 | | |
309 | 0 | text = fz_new_stext_page(ctx, fz_bound_page(ctx, page)); |
310 | 0 | fz_try(ctx) |
311 | 0 | { |
312 | 0 | dev = fz_new_stext_device(ctx, text, options); |
313 | 0 | fz_run_page_contents(ctx, page, dev, fz_identity, cookie); |
314 | 0 | fz_close_device(ctx, dev); |
315 | 0 | } |
316 | 0 | fz_always(ctx) |
317 | 0 | { |
318 | 0 | fz_drop_device(ctx, dev); |
319 | 0 | } |
320 | 0 | fz_catch(ctx) |
321 | 0 | { |
322 | 0 | fz_drop_stext_page(ctx, text); |
323 | 0 | fz_rethrow(ctx); |
324 | 0 | } |
325 | | |
326 | 0 | return text; |
327 | 0 | } |
328 | | |
329 | | fz_stext_page * |
330 | | fz_new_stext_page_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options) |
331 | 0 | { |
332 | 0 | return fz_new_stext_page_from_page_with_cookie(ctx, page, options, NULL); |
333 | 0 | } |
334 | | |
335 | | fz_stext_page * |
336 | | fz_new_stext_page_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options) |
337 | 0 | { |
338 | 0 | fz_page *page; |
339 | 0 | fz_stext_page *text = NULL; |
340 | |
|
341 | 0 | page = fz_load_page(ctx, doc, number); |
342 | 0 | fz_try(ctx) |
343 | 0 | text = fz_new_stext_page_from_page(ctx, page, options); |
344 | 0 | fz_always(ctx) |
345 | 0 | fz_drop_page(ctx, page); |
346 | 0 | fz_catch(ctx) |
347 | 0 | fz_rethrow(ctx); |
348 | 0 | return text; |
349 | 0 | } |
350 | | |
351 | | fz_stext_page * |
352 | | fz_new_stext_page_from_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const fz_stext_options *options) |
353 | 0 | { |
354 | 0 | fz_page *page; |
355 | 0 | fz_stext_page *text = NULL; |
356 | |
|
357 | 0 | page = fz_load_chapter_page(ctx, doc, chapter, number); |
358 | 0 | fz_try(ctx) |
359 | 0 | text = fz_new_stext_page_from_page(ctx, page, options); |
360 | 0 | fz_always(ctx) |
361 | 0 | fz_drop_page(ctx, page); |
362 | 0 | fz_catch(ctx) |
363 | 0 | fz_rethrow(ctx); |
364 | 0 | return text; |
365 | 0 | } |
366 | | |
367 | | int |
368 | | fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) |
369 | 0 | { |
370 | 0 | fz_stext_page *text; |
371 | 0 | int count = 0; |
372 | |
|
373 | 0 | text = fz_new_stext_page_from_display_list(ctx, list, NULL); |
374 | 0 | fz_try(ctx) |
375 | 0 | count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max); |
376 | 0 | fz_always(ctx) |
377 | 0 | fz_drop_stext_page(ctx, text); |
378 | 0 | fz_catch(ctx) |
379 | 0 | fz_rethrow(ctx); |
380 | 0 | return count; |
381 | 0 | } |
382 | | |
383 | | int |
384 | | fz_search_display_list_cb(fz_context *ctx, fz_display_list *list, const char *needle, fz_search_callback_fn *cb, void *opaque) |
385 | 0 | { |
386 | 0 | fz_stext_page *text; |
387 | 0 | int count = 0; |
388 | |
|
389 | 0 | text = fz_new_stext_page_from_display_list(ctx, list, NULL); |
390 | 0 | fz_try(ctx) |
391 | 0 | count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque); |
392 | 0 | fz_always(ctx) |
393 | 0 | fz_drop_stext_page(ctx, text); |
394 | 0 | fz_catch(ctx) |
395 | 0 | fz_rethrow(ctx); |
396 | 0 | return count; |
397 | 0 | } |
398 | | |
399 | | int |
400 | | fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) |
401 | 0 | { |
402 | 0 | fz_stext_options opts = { FZ_STEXT_DEHYPHENATE }; |
403 | 0 | fz_stext_page *text; |
404 | 0 | int count = 0; |
405 | |
|
406 | 0 | text = fz_new_stext_page_from_page(ctx, page, &opts); |
407 | 0 | fz_try(ctx) |
408 | 0 | count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max); |
409 | 0 | fz_always(ctx) |
410 | 0 | fz_drop_stext_page(ctx, text); |
411 | 0 | fz_catch(ctx) |
412 | 0 | fz_rethrow(ctx); |
413 | 0 | return count; |
414 | 0 | } |
415 | | |
416 | | int |
417 | | fz_search_page_cb(fz_context *ctx, fz_page *page, const char *needle, fz_search_callback_fn *cb, void *opaque) |
418 | 0 | { |
419 | 0 | fz_stext_options opts = { FZ_STEXT_DEHYPHENATE }; |
420 | 0 | fz_stext_page *text; |
421 | 0 | int count = 0; |
422 | |
|
423 | 0 | text = fz_new_stext_page_from_page(ctx, page, &opts); |
424 | 0 | fz_try(ctx) |
425 | 0 | count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque); |
426 | 0 | fz_always(ctx) |
427 | 0 | fz_drop_stext_page(ctx, text); |
428 | 0 | fz_catch(ctx) |
429 | 0 | fz_rethrow(ctx); |
430 | 0 | return count; |
431 | 0 | } |
432 | | |
433 | | int |
434 | | fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) |
435 | 0 | { |
436 | 0 | fz_page *page; |
437 | 0 | int count = 0; |
438 | |
|
439 | 0 | page = fz_load_page(ctx, doc, number); |
440 | 0 | fz_try(ctx) |
441 | 0 | count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max); |
442 | 0 | fz_always(ctx) |
443 | 0 | fz_drop_page(ctx, page); |
444 | 0 | fz_catch(ctx) |
445 | 0 | fz_rethrow(ctx); |
446 | 0 | return count; |
447 | 0 | } |
448 | | |
449 | | int |
450 | | fz_search_page_number_cb(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_search_callback_fn *cb, void *opaque) |
451 | 0 | { |
452 | 0 | fz_page *page; |
453 | 0 | int count = 0; |
454 | |
|
455 | 0 | page = fz_load_page(ctx, doc, number); |
456 | 0 | fz_try(ctx) |
457 | 0 | count = fz_search_page_cb(ctx, page, needle, cb, opaque); |
458 | 0 | fz_always(ctx) |
459 | 0 | fz_drop_page(ctx, page); |
460 | 0 | fz_catch(ctx) |
461 | 0 | fz_rethrow(ctx); |
462 | 0 | return count; |
463 | 0 | } |
464 | | |
465 | | int |
466 | | fz_search_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) |
467 | 0 | { |
468 | 0 | fz_page *page; |
469 | 0 | int count = 0; |
470 | |
|
471 | 0 | page = fz_load_chapter_page(ctx, doc, chapter, number); |
472 | 0 | fz_try(ctx) |
473 | 0 | count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max); |
474 | 0 | fz_always(ctx) |
475 | 0 | fz_drop_page(ctx, page); |
476 | 0 | fz_catch(ctx) |
477 | 0 | fz_rethrow(ctx); |
478 | 0 | return count; |
479 | 0 | } |
480 | | |
481 | | int |
482 | | fz_search_chapter_page_number_cb(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, fz_search_callback_fn *cb, void *opaque) |
483 | 0 | { |
484 | 0 | fz_page *page; |
485 | 0 | int count = 0; |
486 | |
|
487 | 0 | page = fz_load_chapter_page(ctx, doc, chapter, number); |
488 | 0 | fz_try(ctx) |
489 | 0 | count = fz_search_page_cb(ctx, page, needle, cb, opaque); |
490 | 0 | fz_always(ctx) |
491 | 0 | fz_drop_page(ctx, page); |
492 | 0 | fz_catch(ctx) |
493 | 0 | fz_rethrow(ctx); |
494 | 0 | return count; |
495 | 0 | } |
496 | | |
497 | | int |
498 | | fz_match_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max, fz_search_options options) |
499 | 0 | { |
500 | 0 | fz_stext_page *text; |
501 | 0 | int count = 0; |
502 | |
|
503 | 0 | text = fz_new_stext_page_from_display_list(ctx, list, NULL); |
504 | 0 | fz_try(ctx) |
505 | 0 | count = fz_match_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max, options); |
506 | 0 | fz_always(ctx) |
507 | 0 | fz_drop_stext_page(ctx, text); |
508 | 0 | fz_catch(ctx) |
509 | 0 | fz_rethrow(ctx); |
510 | 0 | return count; |
511 | 0 | } |
512 | | |
513 | | int |
514 | | fz_match_display_list_cb(fz_context *ctx, fz_display_list *list, const char *needle, fz_match_callback_fn *cb, void *opaque, fz_search_options options) |
515 | 0 | { |
516 | 0 | fz_stext_page *text; |
517 | 0 | int count = 0; |
518 | |
|
519 | 0 | text = fz_new_stext_page_from_display_list(ctx, list, NULL); |
520 | 0 | fz_try(ctx) |
521 | 0 | count = fz_match_stext_page_cb(ctx, text, needle, cb, opaque, options); |
522 | 0 | fz_always(ctx) |
523 | 0 | fz_drop_stext_page(ctx, text); |
524 | 0 | fz_catch(ctx) |
525 | 0 | fz_rethrow(ctx); |
526 | 0 | return count; |
527 | 0 | } |
528 | | |
529 | | int |
530 | | fz_match_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max, fz_search_options options) |
531 | 0 | { |
532 | 0 | fz_stext_options opts = { FZ_STEXT_DEHYPHENATE }; |
533 | 0 | fz_stext_page *text; |
534 | 0 | int count = 0; |
535 | |
|
536 | 0 | text = fz_new_stext_page_from_page(ctx, page, &opts); |
537 | 0 | fz_try(ctx) |
538 | 0 | count = fz_match_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max, options); |
539 | 0 | fz_always(ctx) |
540 | 0 | fz_drop_stext_page(ctx, text); |
541 | 0 | fz_catch(ctx) |
542 | 0 | fz_rethrow(ctx); |
543 | 0 | return count; |
544 | 0 | } |
545 | | |
546 | | int |
547 | | fz_match_page_cb(fz_context *ctx, fz_page *page, const char *needle, fz_match_callback_fn *cb, void *opaque, fz_search_options options) |
548 | 0 | { |
549 | 0 | fz_stext_options opts = { FZ_STEXT_DEHYPHENATE }; |
550 | 0 | fz_stext_page *text; |
551 | 0 | int count = 0; |
552 | |
|
553 | 0 | text = fz_new_stext_page_from_page(ctx, page, &opts); |
554 | 0 | fz_try(ctx) |
555 | 0 | count = fz_match_stext_page_cb(ctx, text, needle, cb, opaque, options); |
556 | 0 | fz_always(ctx) |
557 | 0 | fz_drop_stext_page(ctx, text); |
558 | 0 | fz_catch(ctx) |
559 | 0 | fz_rethrow(ctx); |
560 | 0 | return count; |
561 | 0 | } |
562 | | |
563 | | int |
564 | | fz_match_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max, fz_search_options options) |
565 | 0 | { |
566 | 0 | fz_page *page; |
567 | 0 | int count = 0; |
568 | |
|
569 | 0 | page = fz_load_page(ctx, doc, number); |
570 | 0 | fz_try(ctx) |
571 | 0 | count = fz_match_page(ctx, page, needle, hit_mark, hit_bbox, hit_max, options); |
572 | 0 | fz_always(ctx) |
573 | 0 | fz_drop_page(ctx, page); |
574 | 0 | fz_catch(ctx) |
575 | 0 | fz_rethrow(ctx); |
576 | 0 | return count; |
577 | 0 | } |
578 | | |
579 | | int |
580 | | fz_match_page_number_cb(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_match_callback_fn *cb, void *opaque, fz_search_options options) |
581 | 0 | { |
582 | 0 | fz_page *page; |
583 | 0 | int count = 0; |
584 | |
|
585 | 0 | page = fz_load_page(ctx, doc, number); |
586 | 0 | fz_try(ctx) |
587 | 0 | count = fz_match_page_cb(ctx, page, needle, cb, opaque, options); |
588 | 0 | fz_always(ctx) |
589 | 0 | fz_drop_page(ctx, page); |
590 | 0 | fz_catch(ctx) |
591 | 0 | fz_rethrow(ctx); |
592 | 0 | return count; |
593 | 0 | } |
594 | | |
595 | | int |
596 | | fz_match_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max, fz_search_options options) |
597 | 0 | { |
598 | 0 | fz_page *page; |
599 | 0 | int count = 0; |
600 | |
|
601 | 0 | page = fz_load_chapter_page(ctx, doc, chapter, number); |
602 | 0 | fz_try(ctx) |
603 | 0 | count = fz_match_page(ctx, page, needle, hit_mark, hit_bbox, hit_max, options); |
604 | 0 | fz_always(ctx) |
605 | 0 | fz_drop_page(ctx, page); |
606 | 0 | fz_catch(ctx) |
607 | 0 | fz_rethrow(ctx); |
608 | 0 | return count; |
609 | 0 | } |
610 | | |
611 | | int |
612 | | fz_match_chapter_page_number_cb(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, fz_match_callback_fn *cb, void *opaque, fz_search_options options) |
613 | 0 | { |
614 | 0 | fz_page *page; |
615 | 0 | int count = 0; |
616 | |
|
617 | 0 | page = fz_load_chapter_page(ctx, doc, chapter, number); |
618 | 0 | fz_try(ctx) |
619 | 0 | count = fz_match_page_cb(ctx, page, needle, cb, opaque, options); |
620 | 0 | fz_always(ctx) |
621 | 0 | fz_drop_page(ctx, page); |
622 | 0 | fz_catch(ctx) |
623 | 0 | fz_rethrow(ctx); |
624 | 0 | return count; |
625 | 0 | } |
626 | | |
627 | | fz_buffer * |
628 | | fz_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *page) |
629 | 0 | { |
630 | 0 | return fz_new_buffer_from_flattened_stext_page(ctx, page, FZ_TEXT_FLATTEN_KEEP_PARAGRAPHS, NULL); |
631 | 0 | } |
632 | | |
633 | | static int |
634 | | inhibit_space_after_line_break(int c) |
635 | 0 | { |
636 | 0 | return fz_is_unicode_whitespace(c) || fz_is_unicode_hyphen(c); |
637 | 0 | } |
638 | | |
639 | | static int |
640 | | do_flatten(fz_context *ctx, fz_buffer *buf, fz_stext_position **map, fz_stext_page *page, fz_stext_struct *parent, fz_stext_block *block, fz_text_flatten flatten, int *ws) |
641 | 0 | { |
642 | 0 | fz_stext_line *line; |
643 | 0 | fz_stext_char *ch; |
644 | 0 | int n = 0; |
645 | |
|
646 | 0 | #define EMIT(X,Y) \ |
647 | 0 | { \ |
648 | 0 | if (map && *map) *(*map)++ = (fz_stext_position){ page, parent, block, line, ch }; \ |
649 | 0 | if (buf) fz_append_rune(ctx, buf, Y); \ |
650 | 0 | ++n; \ |
651 | 0 | } |
652 | |
|
653 | 0 | for (; block != NULL; block = block->next) |
654 | 0 | { |
655 | 0 | if (block->type == FZ_STEXT_BLOCK_TEXT) |
656 | 0 | { |
657 | 0 | int join_line = 0; |
658 | 0 | for (line = block->u.t.first_line; line; line = line->next) |
659 | 0 | { |
660 | 0 | join_line = 0; |
661 | 0 | for (ch = line->first_char; ch; ch = ch->next) |
662 | 0 | { |
663 | | /* Last character of a line where we aren't keeping hyphens; check for dehyphenation. */ |
664 | 0 | if (ch == line->last_char && (flatten & FZ_TEXT_FLATTEN_KEEP_HYPHENS) == 0) |
665 | 0 | { |
666 | | /* Soft hyphens are always removed. */ |
667 | 0 | if (ch->c == 0xad) |
668 | 0 | { |
669 | 0 | join_line = 1; |
670 | 0 | continue; |
671 | 0 | } |
672 | | /* Non-soft hyphens are only broken if we extracted with dehyphenation. */ |
673 | 0 | if ((line->flags & FZ_STEXT_LINE_FLAGS_JOINED) != 0 && fz_is_unicode_hyphen(ch->c)) |
674 | 0 | { |
675 | 0 | join_line = 1; |
676 | 0 | continue; |
677 | 0 | } |
678 | 0 | } |
679 | | |
680 | | /* Soft hyphens at the beginning or in the middle of a line are always removed. */ |
681 | 0 | if (ch != line->last_char && ch->c == 0xad) |
682 | 0 | { |
683 | 0 | continue; |
684 | 0 | } |
685 | | |
686 | 0 | EMIT(ch, ch->c); |
687 | |
|
688 | 0 | *ws = inhibit_space_after_line_break(ch->c); |
689 | 0 | } |
690 | |
|
691 | 0 | if (join_line) |
692 | 0 | { |
693 | | /* No whitespace, no linebreak. */ |
694 | 0 | } |
695 | 0 | else if (flatten & FZ_TEXT_FLATTEN_KEEP_LINES) |
696 | 0 | { |
697 | 0 | EMIT(NULL, '\n'); |
698 | 0 | *ws = 1; |
699 | 0 | } |
700 | 0 | else |
701 | 0 | { |
702 | 0 | if (!*ws) |
703 | 0 | EMIT(NULL, ' '); |
704 | 0 | *ws = 1; |
705 | 0 | } |
706 | 0 | } |
707 | |
|
708 | 0 | if (flatten & FZ_TEXT_FLATTEN_KEEP_PARAGRAPHS) |
709 | 0 | { |
710 | 0 | EMIT(NULL, '\n'); |
711 | 0 | *ws = 1; |
712 | 0 | } |
713 | 0 | else if (!join_line) |
714 | 0 | { |
715 | 0 | EMIT(NULL, '\n'); |
716 | 0 | *ws = 1; |
717 | 0 | } |
718 | 0 | } |
719 | 0 | else if (block->type == FZ_STEXT_BLOCK_STRUCT && block->u.s.down) |
720 | 0 | { |
721 | 0 | n += do_flatten(ctx, buf, map, page, block->u.s.down, block->u.s.down->first_block, flatten, ws); |
722 | 0 | } |
723 | 0 | } |
724 | |
|
725 | 0 | return n; |
726 | 0 | } |
727 | | |
728 | | fz_buffer * |
729 | | fz_new_buffer_from_flattened_stext_page(fz_context *ctx, fz_stext_page *page, fz_text_flatten flatten, fz_stext_position **mapp) |
730 | 0 | { |
731 | 0 | fz_stext_position *map = NULL; |
732 | 0 | fz_buffer *buf = NULL; |
733 | 0 | int ws, len; |
734 | |
|
735 | 0 | fz_var(map); |
736 | 0 | fz_var(buf); |
737 | |
|
738 | 0 | if (mapp) |
739 | 0 | { |
740 | 0 | ws = 0; |
741 | 0 | len = do_flatten(ctx, NULL, NULL, page, NULL, page->first_block, flatten, &ws); |
742 | 0 | } |
743 | |
|
744 | 0 | fz_try(ctx) |
745 | 0 | { |
746 | 0 | buf = fz_new_buffer(ctx, 256); |
747 | 0 | if (mapp) |
748 | 0 | map = *mapp = fz_malloc_array(ctx, len, fz_stext_position); |
749 | 0 | ws = 0; |
750 | 0 | do_flatten(ctx, buf, &map, page, NULL, page->first_block, flatten, &ws); |
751 | 0 | } |
752 | 0 | fz_catch(ctx) |
753 | 0 | { |
754 | 0 | if (mapp) |
755 | 0 | fz_free(ctx, *mapp); |
756 | 0 | fz_drop_buffer(ctx, buf); |
757 | 0 | fz_rethrow(ctx); |
758 | 0 | } |
759 | | |
760 | 0 | return buf; |
761 | 0 | } |
762 | | |
763 | | fz_buffer * |
764 | | fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options) |
765 | 0 | { |
766 | 0 | return fz_new_buffer_from_flattened_display_list(ctx, list, options, FZ_TEXT_FLATTEN_KEEP_PARAGRAPHS); |
767 | 0 | } |
768 | | |
769 | | fz_buffer * |
770 | | fz_new_buffer_from_flattened_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options, fz_text_flatten flatten) |
771 | 0 | { |
772 | 0 | fz_stext_page *text; |
773 | 0 | fz_buffer *buf = NULL; |
774 | |
|
775 | 0 | text = fz_new_stext_page_from_display_list(ctx, list, options); |
776 | 0 | fz_try(ctx) |
777 | 0 | buf = fz_new_buffer_from_flattened_stext_page(ctx, text, flatten, NULL); |
778 | 0 | fz_always(ctx) |
779 | 0 | fz_drop_stext_page(ctx, text); |
780 | 0 | fz_catch(ctx) |
781 | 0 | fz_rethrow(ctx); |
782 | 0 | return buf; |
783 | 0 | } |
784 | | |
785 | | fz_buffer * |
786 | | fz_new_buffer_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options) |
787 | 0 | { |
788 | 0 | return fz_new_buffer_from_flattened_page(ctx, page, options, FZ_TEXT_FLATTEN_KEEP_PARAGRAPHS); |
789 | 0 | } |
790 | | |
791 | | fz_buffer * |
792 | | fz_new_buffer_from_flattened_page(fz_context *ctx, fz_page *page, const fz_stext_options *options, fz_text_flatten flatten) |
793 | 0 | { |
794 | 0 | fz_stext_page *text; |
795 | 0 | fz_buffer *buf = NULL; |
796 | |
|
797 | 0 | text = fz_new_stext_page_from_page(ctx, page, options); |
798 | 0 | fz_try(ctx) |
799 | 0 | buf = fz_new_buffer_from_flattened_stext_page(ctx, text, flatten, NULL); |
800 | 0 | fz_always(ctx) |
801 | 0 | fz_drop_stext_page(ctx, text); |
802 | 0 | fz_catch(ctx) |
803 | 0 | fz_rethrow(ctx); |
804 | 0 | return buf; |
805 | 0 | } |
806 | | |
807 | | fz_buffer * |
808 | | fz_new_buffer_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options) |
809 | 0 | { |
810 | 0 | return fz_new_buffer_from_flattened_page_number(ctx, doc, number, options, FZ_TEXT_FLATTEN_KEEP_PARAGRAPHS); |
811 | 0 | } |
812 | | |
813 | | fz_buffer * |
814 | | fz_new_buffer_from_flattened_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options, fz_text_flatten flatten) |
815 | 0 | { |
816 | 0 | fz_page *page; |
817 | 0 | fz_buffer *buf = NULL; |
818 | |
|
819 | 0 | page = fz_load_page(ctx, doc, number); |
820 | 0 | fz_try(ctx) |
821 | 0 | buf = fz_new_buffer_from_flattened_page(ctx, page, options, flatten); |
822 | 0 | fz_always(ctx) |
823 | 0 | fz_drop_page(ctx, page); |
824 | 0 | fz_catch(ctx) |
825 | 0 | fz_rethrow(ctx); |
826 | 0 | return buf; |
827 | 0 | } |
828 | | |
829 | | void |
830 | | fz_write_image_as_data_uri(fz_context *ctx, fz_output *out, fz_image *image) |
831 | 0 | { |
832 | 0 | fz_compressed_buffer *cbuf; |
833 | 0 | fz_buffer *buf; |
834 | |
|
835 | 0 | cbuf = fz_compressed_image_buffer(ctx, image); |
836 | |
|
837 | 0 | if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG) |
838 | 0 | { |
839 | 0 | int type = fz_colorspace_type(ctx, image->colorspace); |
840 | 0 | if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB) |
841 | 0 | { |
842 | 0 | fz_write_string(ctx, out, "data:image/jpeg;base64,"); |
843 | 0 | fz_write_base64_buffer(ctx, out, cbuf->buffer, 1); |
844 | 0 | return; |
845 | 0 | } |
846 | 0 | } |
847 | 0 | if (cbuf && cbuf->params.type == FZ_IMAGE_PNG) |
848 | 0 | { |
849 | 0 | fz_write_string(ctx, out, "data:image/png;base64,"); |
850 | 0 | fz_write_base64_buffer(ctx, out, cbuf->buffer, 1); |
851 | 0 | return; |
852 | 0 | } |
853 | | |
854 | 0 | buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params); |
855 | 0 | fz_try(ctx) |
856 | 0 | { |
857 | 0 | fz_write_string(ctx, out, "data:image/png;base64,"); |
858 | 0 | fz_write_base64_buffer(ctx, out, buf, 1); |
859 | 0 | } |
860 | 0 | fz_always(ctx) |
861 | 0 | fz_drop_buffer(ctx, buf); |
862 | 0 | fz_catch(ctx) |
863 | 0 | fz_rethrow(ctx); |
864 | 0 | } |
865 | | |
866 | | static uint32_t read16(const uint8_t *d, size_t *pos, size_t len, int order) |
867 | 0 | { |
868 | 0 | size_t p = *pos; |
869 | 0 | if (p+1 >= len) |
870 | 0 | return *pos = len, 0; |
871 | 0 | if (order) |
872 | 0 | return *pos = p+2, fz_unpack_uint16(d+p); |
873 | 0 | else |
874 | 0 | return *pos = p+2, fz_unpack_uint16_le(d+p); |
875 | 0 | } |
876 | | |
877 | | static uint32_t read32(const uint8_t *d, size_t *pos, size_t len, int order) |
878 | 0 | { |
879 | 0 | size_t p = *pos; |
880 | 0 | if (p+3 >= len) |
881 | 0 | return *pos = len, 0; |
882 | 0 | if (order) |
883 | 0 | return *pos = p+4, fz_unpack_uint32(d+p); |
884 | 0 | else |
885 | 0 | return *pos = p+4, fz_unpack_uint32_le(d+p); |
886 | 0 | } |
887 | | |
888 | | static void write16(uint8_t *d, size_t *pos, size_t len, int order, uint32_t v) |
889 | 0 | { |
890 | 0 | size_t p = *pos; |
891 | 0 | if (p+1 >= len) |
892 | 0 | { |
893 | 0 | *pos = len; |
894 | 0 | return; |
895 | 0 | } |
896 | 0 | if (order) |
897 | 0 | fz_pack_uint16(d+p, v); |
898 | 0 | else |
899 | 0 | fz_pack_uint16_le(d+p, v); |
900 | 0 | *pos = p+2; |
901 | 0 | } |
902 | | |
903 | | static void write32(uint8_t *d, size_t *pos, size_t len, int order, uint32_t v) |
904 | 0 | { |
905 | 0 | size_t p = *pos; |
906 | 0 | if (p+3 >= len) |
907 | 0 | { |
908 | 0 | *pos = len; |
909 | 0 | return; |
910 | 0 | } |
911 | 0 | if (order) |
912 | 0 | fz_pack_uint32(d+p, v); |
913 | 0 | else |
914 | 0 | fz_pack_uint32_le(d+p, v); |
915 | 0 | *pos = p+4; |
916 | 0 | } |
917 | | |
918 | | fz_buffer * |
919 | | fz_sanitize_jpeg_buffer(fz_context *ctx, fz_buffer *in) |
920 | 0 | { |
921 | 0 | fz_buffer *out = fz_clone_buffer(ctx, in); |
922 | 0 | size_t len = out->len; |
923 | 0 | size_t pos = 0; |
924 | 0 | uint8_t *d = out->data; |
925 | | |
926 | | /* We need at least 4 data bytes. */ |
927 | 0 | while (pos+4 < len) |
928 | 0 | { |
929 | 0 | uint8_t m; |
930 | | /* We should be on a marker. If not, inch forwards until we are. */ |
931 | 0 | if (d[pos++] != 0xff) |
932 | 0 | continue; |
933 | 0 | m = d[pos++]; |
934 | 0 | if (m == 0xDA) |
935 | 0 | break; /* Start Of Scan. All our rewriting happens before this. */ |
936 | 0 | if (m == 0xE1) |
937 | 0 | { |
938 | 0 | uint8_t order; |
939 | 0 | uint32_t tmp; |
940 | 0 | size_t body_start; |
941 | | /* APP1 tag. This is where the EXIF data lives. */ |
942 | | /* Read and discard the marker length. We're not continuing after this anyway. */ |
943 | 0 | (void)read16(d, &pos, len, 0); |
944 | 0 | tmp = read32(d, &pos, len, 0); |
945 | 0 | if (tmp != 0x66697845) /* Exif */ |
946 | 0 | break; /* Not exif - nothing to rewrite. */ |
947 | 0 | tmp = read16(d, &pos, len, 0); |
948 | 0 | if (tmp != 0) /* Terminator + Pad */ |
949 | 0 | break; /* Not exif - nothing to rewrite. */ |
950 | | /* Now we're at the APP1 Body. */ |
951 | 0 | body_start = pos; |
952 | 0 | tmp = read16(d, &pos, len, 0); |
953 | 0 | if (tmp == 0x4949) |
954 | 0 | order = 0; /* LE */ |
955 | 0 | else if (tmp == 0x4d4d) |
956 | 0 | order = 1; /* BE */ |
957 | 0 | else |
958 | 0 | break; /* Bad TIFF type. Bale. */ |
959 | 0 | tmp = read16(d, &pos, len, order); |
960 | 0 | if (tmp != 0x002a) /* 42 */ |
961 | 0 | break; /* Bad version field. Bale. */ |
962 | 0 | do |
963 | 0 | { |
964 | 0 | uint32_t i, n; |
965 | 0 | tmp = read32(d, &pos, len, order); |
966 | 0 | pos = body_start + tmp; |
967 | 0 | if (tmp == 0 || pos >= len) |
968 | 0 | break; |
969 | 0 | n = read16(d, &pos, len, order); |
970 | 0 | for (i = 0; i < n; i++) |
971 | 0 | { |
972 | 0 | if (read16(d, &pos, len, order) == 0x112) |
973 | 0 | { |
974 | | /* Orientation tag! */ |
975 | 0 | write16(d, &pos, len, order, 3); /* 3 = short */ |
976 | 0 | write32(d, &pos, len, order, 1); /* Count = 1 */ |
977 | 0 | write16(d, &pos, len, order, 1); /* Value = 1 */ |
978 | 0 | write16(d, &pos, len, order, 0); /* padding */ |
979 | 0 | i = n; |
980 | 0 | pos = len; /* Done! */ |
981 | 0 | } |
982 | 0 | else |
983 | 0 | pos += 10; |
984 | 0 | } |
985 | 0 | } |
986 | 0 | while (pos+4 < len); |
987 | 0 | break; |
988 | 0 | } |
989 | 0 | else if (m >= 0xD0 && m <= 0xD7) |
990 | 0 | { |
991 | | /* RSTm - no length code. But we shouldn't hit this! */ |
992 | 0 | } |
993 | 0 | else if (m == 0x01) |
994 | 0 | { |
995 | | /* TEM - temporary private use in arithmetic coding - shouldn't hit this either. */ |
996 | 0 | } |
997 | 0 | else if (m == 0xD8) |
998 | 0 | { |
999 | | /* SOI - start of image. */ |
1000 | 0 | } |
1001 | 0 | else if (m == 0x01) |
1002 | 0 | { |
1003 | | /* EOI - end of image. */ |
1004 | 0 | } |
1005 | 0 | else |
1006 | 0 | { |
1007 | | /* All other markers have a length. */ |
1008 | 0 | size_t marker_len = d[pos]*256 + d[pos+1]; |
1009 | 0 | pos += marker_len; /* The 2 length bytes are included in the marker_len */ |
1010 | 0 | } |
1011 | 0 | } |
1012 | |
|
1013 | 0 | return out; |
1014 | 0 | } |
1015 | | |
1016 | | void |
1017 | | fz_append_image_as_data_uri(fz_context *ctx, fz_buffer *out, fz_image *image) |
1018 | 0 | { |
1019 | 0 | fz_compressed_buffer *cbuf; |
1020 | 0 | fz_buffer *buf; |
1021 | 0 | const char *mime; |
1022 | |
|
1023 | 0 | cbuf = fz_compressed_image_buffer(ctx, image); |
1024 | |
|
1025 | 0 | if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG) |
1026 | 0 | { |
1027 | 0 | int type = fz_colorspace_type(ctx, image->colorspace); |
1028 | 0 | if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB) |
1029 | 0 | { |
1030 | 0 | fz_buffer *new_buf = fz_sanitize_jpeg_buffer(ctx, cbuf->buffer); |
1031 | 0 | fz_append_string(ctx, out, "data:image/jpeg;base64,"); |
1032 | 0 | fz_try(ctx) |
1033 | 0 | fz_append_base64_buffer(ctx, out, new_buf, 1); |
1034 | 0 | fz_always(ctx) |
1035 | 0 | fz_drop_buffer(ctx, new_buf); |
1036 | 0 | fz_catch(ctx) |
1037 | 0 | fz_rethrow(ctx); |
1038 | 0 | return; |
1039 | 0 | } |
1040 | 0 | } |
1041 | | |
1042 | 0 | if (cbuf && cbuf->params.type == FZ_IMAGE_PNG) |
1043 | 0 | { |
1044 | 0 | fz_append_string(ctx, out, "data:image/png;base64,"); |
1045 | 0 | fz_append_base64_buffer(ctx, out, cbuf->buffer, 1); |
1046 | 0 | return; |
1047 | 0 | } |
1048 | | |
1049 | 0 | if (fz_is_lossy_image(ctx, image)) |
1050 | 0 | { |
1051 | | /* Convert lossy image formats to JPEG */ |
1052 | 0 | buf = fz_new_buffer_from_image_as_jpeg(ctx, image, fz_default_color_params, 90, 0); |
1053 | 0 | mime = "data:image/jpeg;base64,"; |
1054 | 0 | } |
1055 | 0 | else |
1056 | 0 | { |
1057 | 0 | buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params); |
1058 | 0 | mime = "data:image/png;base64,"; |
1059 | 0 | } |
1060 | |
|
1061 | 0 | fz_try(ctx) |
1062 | 0 | { |
1063 | 0 | fz_append_string(ctx, out, mime); |
1064 | 0 | fz_append_base64_buffer(ctx, out, buf, 1); |
1065 | 0 | } |
1066 | 0 | fz_always(ctx) |
1067 | 0 | fz_drop_buffer(ctx, buf); |
1068 | 0 | fz_catch(ctx) |
1069 | 0 | fz_rethrow(ctx); |
1070 | 0 | } |
1071 | | |
1072 | | void |
1073 | | fz_write_pixmap_as_data_uri(fz_context *ctx, fz_output *out, fz_pixmap *pixmap) |
1074 | 0 | { |
1075 | 0 | fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params); |
1076 | 0 | fz_try(ctx) |
1077 | 0 | { |
1078 | 0 | fz_write_string(ctx, out, "data:image/png;base64,"); |
1079 | 0 | fz_write_base64_buffer(ctx, out, buf, 1); |
1080 | 0 | } |
1081 | 0 | fz_always(ctx) |
1082 | 0 | fz_drop_buffer(ctx, buf); |
1083 | 0 | fz_catch(ctx) |
1084 | 0 | fz_rethrow(ctx); |
1085 | 0 | } |
1086 | | |
1087 | | void |
1088 | | fz_append_pixmap_as_data_uri(fz_context *ctx, fz_buffer *out, fz_pixmap *pixmap) |
1089 | 0 | { |
1090 | 0 | fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params); |
1091 | 0 | fz_try(ctx) |
1092 | 0 | { |
1093 | 0 | fz_append_string(ctx, out, "data:image/png;base64,"); |
1094 | 0 | fz_append_base64_buffer(ctx, out, buf, 1); |
1095 | 0 | } |
1096 | 0 | fz_always(ctx) |
1097 | 0 | fz_drop_buffer(ctx, buf); |
1098 | 0 | fz_catch(ctx) |
1099 | 0 | fz_rethrow(ctx); |
1100 | 0 | } |
1101 | | |
1102 | | fz_document * |
1103 | | fz_new_xhtml_document_from_document(fz_context *ctx, fz_document *old_doc, const fz_stext_options *opts) |
1104 | 0 | { |
1105 | 0 | fz_stext_options default_opts = { FZ_STEXT_PRESERVE_IMAGES | FZ_STEXT_DEHYPHENATE }; |
1106 | 0 | fz_document *new_doc; |
1107 | 0 | fz_buffer *buf = NULL; |
1108 | 0 | fz_output *out = NULL; |
1109 | 0 | fz_stream *stm = NULL; |
1110 | 0 | fz_stext_page *text = NULL; |
1111 | 0 | int i; |
1112 | |
|
1113 | 0 | fz_var(buf); |
1114 | 0 | fz_var(out); |
1115 | 0 | fz_var(stm); |
1116 | 0 | fz_var(text); |
1117 | |
|
1118 | 0 | if (!opts) |
1119 | 0 | opts = &default_opts; |
1120 | |
|
1121 | 0 | fz_try(ctx) |
1122 | 0 | { |
1123 | 0 | buf = fz_new_buffer(ctx, 8192); |
1124 | 0 | out = fz_new_output_with_buffer(ctx, buf); |
1125 | 0 | fz_print_stext_header_as_xhtml(ctx, out); |
1126 | |
|
1127 | 0 | for (i = 0; i < fz_count_pages(ctx, old_doc); ++i) |
1128 | 0 | { |
1129 | 0 | text = fz_new_stext_page_from_page_number(ctx, old_doc, i, opts); |
1130 | 0 | fz_print_stext_page_as_xhtml(ctx, out, text, i+1); |
1131 | 0 | fz_drop_stext_page(ctx, text); |
1132 | 0 | text = NULL; |
1133 | 0 | } |
1134 | |
|
1135 | 0 | fz_print_stext_trailer_as_xhtml(ctx, out); |
1136 | 0 | fz_close_output(ctx, out); |
1137 | 0 | fz_terminate_buffer(ctx, buf); |
1138 | |
|
1139 | 0 | stm = fz_open_buffer(ctx, buf); |
1140 | 0 | new_doc = fz_open_document_with_stream(ctx, "application/xhtml+xml", stm); |
1141 | 0 | } |
1142 | 0 | fz_always(ctx) |
1143 | 0 | { |
1144 | 0 | fz_drop_stream(ctx, stm); |
1145 | 0 | fz_drop_buffer(ctx, buf); |
1146 | 0 | fz_drop_output(ctx, out); |
1147 | 0 | fz_drop_stext_page(ctx, text); |
1148 | 0 | } |
1149 | 0 | fz_catch(ctx) |
1150 | 0 | fz_rethrow(ctx); |
1151 | | |
1152 | 0 | return new_doc; |
1153 | 0 | } |
1154 | | |
1155 | | fz_buffer * |
1156 | | fz_new_buffer_from_page_with_format(fz_context *ctx, fz_page *page, const char *format, const char *options, fz_matrix transform, fz_cookie *cookie) |
1157 | 0 | { |
1158 | 0 | fz_buffer *buf = NULL; |
1159 | 0 | fz_output *out; |
1160 | 0 | fz_document_writer *writer = NULL; |
1161 | 0 | fz_device *dev = NULL; |
1162 | |
|
1163 | 0 | fz_var(buf); |
1164 | 0 | fz_var(writer); |
1165 | 0 | fz_var(dev); |
1166 | |
|
1167 | 0 | fz_try(ctx) |
1168 | 0 | { |
1169 | 0 | buf = fz_new_buffer(ctx, 0); |
1170 | 0 | out = fz_new_output_with_buffer(ctx, buf); |
1171 | 0 | writer = fz_new_document_writer_with_output(ctx, out, format, options); |
1172 | 0 | dev = fz_begin_page(ctx, writer, fz_bound_page(ctx, page)); |
1173 | 0 | fz_run_page(ctx, page, dev, transform, cookie); |
1174 | 0 | fz_end_page(ctx, writer); |
1175 | 0 | fz_close_document_writer(ctx, writer); |
1176 | 0 | } |
1177 | 0 | fz_always(ctx) |
1178 | 0 | fz_drop_document_writer(ctx, writer); |
1179 | 0 | fz_catch(ctx) |
1180 | 0 | { |
1181 | 0 | fz_drop_buffer(ctx, buf); |
1182 | 0 | fz_rethrow(ctx); |
1183 | 0 | } |
1184 | 0 | return buf; |
1185 | 0 | } |