comparison mupdf-source/source/fitz/util.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2022 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 {
30 fz_display_list *list;
31 fz_device *dev = NULL;
32
33 fz_var(dev);
34
35 list = fz_new_display_list(ctx, fz_bound_page(ctx, page));
36 fz_try(ctx)
37 {
38 dev = fz_new_list_device(ctx, list);
39 fz_run_page(ctx, page, dev, fz_identity, NULL);
40 fz_close_device(ctx, dev);
41 }
42 fz_always(ctx)
43 {
44 fz_drop_device(ctx, dev);
45 }
46 fz_catch(ctx)
47 {
48 fz_drop_display_list(ctx, list);
49 fz_rethrow(ctx);
50 }
51
52 return list;
53 }
54
55 fz_display_list *
56 fz_new_display_list_from_page_number(fz_context *ctx, fz_document *doc, int number)
57 {
58 fz_page *page;
59 fz_display_list *list = NULL;
60
61 page = fz_load_page(ctx, doc, number);
62 fz_try(ctx)
63 list = fz_new_display_list_from_page(ctx, page);
64 fz_always(ctx)
65 fz_drop_page(ctx, page);
66 fz_catch(ctx)
67 fz_rethrow(ctx);
68 return list;
69 }
70
71 fz_display_list *
72 fz_new_display_list_from_page_contents(fz_context *ctx, fz_page *page)
73 {
74 fz_display_list *list;
75 fz_device *dev = NULL;
76
77 fz_var(dev);
78
79 list = fz_new_display_list(ctx, fz_bound_page(ctx, page));
80 fz_try(ctx)
81 {
82 dev = fz_new_list_device(ctx, list);
83 fz_run_page_contents(ctx, page, dev, fz_identity, NULL);
84 fz_close_device(ctx, dev);
85 }
86 fz_always(ctx)
87 {
88 fz_drop_device(ctx, dev);
89 }
90 fz_catch(ctx)
91 {
92 fz_drop_display_list(ctx, list);
93 fz_rethrow(ctx);
94 }
95
96 return list;
97 }
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 {
102 return fz_new_pixmap_from_display_list_with_separations(ctx, list, ctm, cs, NULL, alpha);
103 }
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 {
108 fz_rect rect;
109 fz_irect bbox;
110 fz_pixmap *pix;
111
112 rect = fz_bound_display_list(ctx, list);
113 rect = fz_transform_rect(rect, ctm);
114 bbox = fz_round_rect(rect);
115
116 pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha);
117 if (alpha)
118 fz_clear_pixmap(ctx, pix);
119 else
120 fz_clear_pixmap_with_value(ctx, pix, 0xFF);
121
122 return fz_fill_pixmap_from_display_list(ctx, list, ctm, pix);
123 }
124
125 fz_pixmap *
126 fz_fill_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_pixmap *pix)
127 {
128 fz_device *dev = NULL;
129
130 fz_var(dev);
131
132 fz_try(ctx)
133 {
134 dev = fz_new_draw_device(ctx, ctm, pix);
135 fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);
136 fz_close_device(ctx, dev);
137 }
138 fz_always(ctx)
139 {
140 fz_drop_device(ctx, dev);
141 }
142 fz_catch(ctx)
143 {
144 fz_drop_pixmap(ctx, pix);
145 fz_rethrow(ctx);
146 }
147
148 return pix;
149 }
150
151 fz_pixmap *
152 fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha)
153 {
154 return fz_new_pixmap_from_page_contents_with_separations(ctx, page, ctm, cs, NULL, alpha);
155 }
156
157 fz_pixmap *
158 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)
159 {
160 fz_rect rect;
161 fz_irect bbox;
162 fz_pixmap *pix;
163 fz_device *dev = NULL;
164
165 fz_var(dev);
166
167 rect = fz_bound_page(ctx, page);
168 rect = fz_transform_rect(rect, ctm);
169 bbox = fz_round_rect(rect);
170
171 pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha);
172 if (alpha)
173 fz_clear_pixmap(ctx, pix);
174 else
175 fz_clear_pixmap_with_value(ctx, pix, 0xFF);
176
177 fz_try(ctx)
178 {
179 dev = fz_new_draw_device(ctx, ctm, pix);
180 fz_run_page_contents(ctx, page, dev, fz_identity, NULL);
181 fz_close_device(ctx, dev);
182 }
183 fz_always(ctx)
184 {
185 fz_drop_device(ctx, dev);
186 }
187 fz_catch(ctx)
188 {
189 fz_drop_pixmap(ctx, pix);
190 fz_rethrow(ctx);
191 }
192
193 return pix;
194 }
195
196 fz_pixmap *
197 fz_new_pixmap_from_page(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha)
198 {
199 return fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, NULL, alpha);
200 }
201
202 fz_pixmap *
203 fz_new_pixmap_from_page_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha)
204 {
205 fz_rect rect;
206 fz_irect bbox;
207 fz_pixmap *pix;
208 fz_device *dev = NULL;
209
210 fz_var(dev);
211
212 rect = fz_bound_page(ctx, page);
213 rect = fz_transform_rect(rect, ctm);
214 bbox = fz_round_rect(rect);
215
216 pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha);
217
218 fz_try(ctx)
219 {
220 if (alpha)
221 fz_clear_pixmap(ctx, pix);
222 else
223 fz_clear_pixmap_with_value(ctx, pix, 0xFF);
224
225 dev = fz_new_draw_device(ctx, ctm, pix);
226 fz_run_page(ctx, page, dev, fz_identity, NULL);
227 fz_close_device(ctx, dev);
228 }
229 fz_always(ctx)
230 {
231 fz_drop_device(ctx, dev);
232 }
233 fz_catch(ctx)
234 {
235 fz_drop_pixmap(ctx, pix);
236 fz_rethrow(ctx);
237 }
238
239 return pix;
240 }
241
242 fz_pixmap *
243 fz_new_pixmap_from_page_number(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, int alpha)
244 {
245 return fz_new_pixmap_from_page_number_with_separations(ctx, doc, number, ctm, cs, NULL, alpha);
246 }
247
248 fz_pixmap *
249 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)
250 {
251 fz_page *page;
252 fz_pixmap *pix = NULL;
253
254 page = fz_load_page(ctx, doc, number);
255 fz_try(ctx)
256 pix = fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, seps, alpha);
257 fz_always(ctx)
258 fz_drop_page(ctx, page);
259 fz_catch(ctx)
260 fz_rethrow(ctx);
261 return pix;
262 }
263
264 fz_stext_page *
265 fz_new_stext_page_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options)
266 {
267 fz_stext_page *text;
268 fz_device *dev = NULL;
269
270 fz_var(dev);
271
272 if (list == NULL)
273 return NULL;
274
275 text = fz_new_stext_page(ctx, fz_bound_display_list(ctx, list));
276 fz_try(ctx)
277 {
278 dev = fz_new_stext_device(ctx, text, options);
279 fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);
280 fz_close_device(ctx, dev);
281 }
282 fz_always(ctx)
283 {
284 fz_drop_device(ctx, dev);
285 }
286 fz_catch(ctx)
287 {
288 fz_drop_stext_page(ctx, text);
289 fz_rethrow(ctx);
290 }
291
292 return text;
293 }
294
295 fz_stext_page *
296 fz_new_stext_page_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options)
297 {
298 fz_stext_page *text;
299 fz_device *dev = NULL;
300
301 fz_var(dev);
302
303 if (page == NULL)
304 return NULL;
305
306 text = fz_new_stext_page(ctx, fz_bound_page(ctx, page));
307 fz_try(ctx)
308 {
309 dev = fz_new_stext_device(ctx, text, options);
310 fz_run_page_contents(ctx, page, dev, fz_identity, NULL);
311 fz_close_device(ctx, dev);
312 }
313 fz_always(ctx)
314 {
315 fz_drop_device(ctx, dev);
316 }
317 fz_catch(ctx)
318 {
319 fz_drop_stext_page(ctx, text);
320 fz_rethrow(ctx);
321 }
322
323 return text;
324 }
325
326 fz_stext_page *
327 fz_new_stext_page_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options)
328 {
329 fz_page *page;
330 fz_stext_page *text = NULL;
331
332 page = fz_load_page(ctx, doc, number);
333 fz_try(ctx)
334 text = fz_new_stext_page_from_page(ctx, page, options);
335 fz_always(ctx)
336 fz_drop_page(ctx, page);
337 fz_catch(ctx)
338 fz_rethrow(ctx);
339 return text;
340 }
341
342 fz_stext_page *
343 fz_new_stext_page_from_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const fz_stext_options *options)
344 {
345 fz_page *page;
346 fz_stext_page *text = NULL;
347
348 page = fz_load_chapter_page(ctx, doc, chapter, number);
349 fz_try(ctx)
350 text = fz_new_stext_page_from_page(ctx, page, options);
351 fz_always(ctx)
352 fz_drop_page(ctx, page);
353 fz_catch(ctx)
354 fz_rethrow(ctx);
355 return text;
356 }
357
358 int
359 fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
360 {
361 fz_stext_page *text;
362 int count = 0;
363
364 text = fz_new_stext_page_from_display_list(ctx, list, NULL);
365 fz_try(ctx)
366 count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
367 fz_always(ctx)
368 fz_drop_stext_page(ctx, text);
369 fz_catch(ctx)
370 fz_rethrow(ctx);
371 return count;
372 }
373
374 int
375 fz_search_display_list_cb(fz_context *ctx, fz_display_list *list, const char *needle, fz_search_callback_fn *cb, void *opaque)
376 {
377 fz_stext_page *text;
378 int count = 0;
379
380 text = fz_new_stext_page_from_display_list(ctx, list, NULL);
381 fz_try(ctx)
382 count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque);
383 fz_always(ctx)
384 fz_drop_stext_page(ctx, text);
385 fz_catch(ctx)
386 fz_rethrow(ctx);
387 return count;
388 }
389
390 int
391 fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
392 {
393 fz_stext_options opts = { FZ_STEXT_DEHYPHENATE };
394 fz_stext_page *text;
395 int count = 0;
396
397 text = fz_new_stext_page_from_page(ctx, page, &opts);
398 fz_try(ctx)
399 count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
400 fz_always(ctx)
401 fz_drop_stext_page(ctx, text);
402 fz_catch(ctx)
403 fz_rethrow(ctx);
404 return count;
405 }
406
407 int
408 fz_search_page_cb(fz_context *ctx, fz_page *page, const char *needle, fz_search_callback_fn *cb, void *opaque)
409 {
410 fz_stext_options opts = { FZ_STEXT_DEHYPHENATE };
411 fz_stext_page *text;
412 int count = 0;
413
414 text = fz_new_stext_page_from_page(ctx, page, &opts);
415 fz_try(ctx)
416 count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque);
417 fz_always(ctx)
418 fz_drop_stext_page(ctx, text);
419 fz_catch(ctx)
420 fz_rethrow(ctx);
421 return count;
422 }
423
424 int
425 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)
426 {
427 fz_page *page;
428 int count = 0;
429
430 page = fz_load_page(ctx, doc, number);
431 fz_try(ctx)
432 count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
433 fz_always(ctx)
434 fz_drop_page(ctx, page);
435 fz_catch(ctx)
436 fz_rethrow(ctx);
437 return count;
438 }
439
440 int
441 fz_search_page_number_cb(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_search_callback_fn *cb, void *opaque)
442 {
443 fz_page *page;
444 int count = 0;
445
446 page = fz_load_page(ctx, doc, number);
447 fz_try(ctx)
448 count = fz_search_page_cb(ctx, page, needle, cb, opaque);
449 fz_always(ctx)
450 fz_drop_page(ctx, page);
451 fz_catch(ctx)
452 fz_rethrow(ctx);
453 return count;
454 }
455
456 int
457 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)
458 {
459 fz_page *page;
460 int count = 0;
461
462 page = fz_load_chapter_page(ctx, doc, chapter, number);
463 fz_try(ctx)
464 count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
465 fz_always(ctx)
466 fz_drop_page(ctx, page);
467 fz_catch(ctx)
468 fz_rethrow(ctx);
469 return count;
470 }
471
472 int
473 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)
474 {
475 fz_page *page;
476 int count = 0;
477
478 page = fz_load_chapter_page(ctx, doc, chapter, number);
479 fz_try(ctx)
480 count = fz_search_page_cb(ctx, page, needle, cb, opaque);
481 fz_always(ctx)
482 fz_drop_page(ctx, page);
483 fz_catch(ctx)
484 fz_rethrow(ctx);
485 return count;
486 }
487
488 fz_buffer *
489 fz_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *page)
490 {
491 fz_stext_block *block;
492 fz_stext_line *line;
493 fz_stext_char *ch;
494 fz_buffer *buf;
495
496 buf = fz_new_buffer(ctx, 256);
497 fz_try(ctx)
498 {
499 for (block = page->first_block; block; block = block->next)
500 {
501 if (block->type == FZ_STEXT_BLOCK_TEXT)
502 {
503 for (line = block->u.t.first_line; line; line = line->next)
504 {
505 for (ch = line->first_char; ch; ch = ch->next)
506 fz_append_rune(ctx, buf, ch->c);
507 fz_append_byte(ctx, buf, '\n');
508 }
509 fz_append_byte(ctx, buf, '\n');
510 }
511 }
512 }
513 fz_catch(ctx)
514 {
515 fz_drop_buffer(ctx, buf);
516 fz_rethrow(ctx);
517 }
518
519 return buf;
520 }
521
522 fz_buffer *
523 fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options)
524 {
525 fz_stext_page *text;
526 fz_buffer *buf = NULL;
527
528 text = fz_new_stext_page_from_display_list(ctx, list, options);
529 fz_try(ctx)
530 buf = fz_new_buffer_from_stext_page(ctx, text);
531 fz_always(ctx)
532 fz_drop_stext_page(ctx, text);
533 fz_catch(ctx)
534 fz_rethrow(ctx);
535 return buf;
536 }
537
538 fz_buffer *
539 fz_new_buffer_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options)
540 {
541 fz_stext_page *text;
542 fz_buffer *buf = NULL;
543
544 text = fz_new_stext_page_from_page(ctx, page, options);
545 fz_try(ctx)
546 buf = fz_new_buffer_from_stext_page(ctx, text);
547 fz_always(ctx)
548 fz_drop_stext_page(ctx, text);
549 fz_catch(ctx)
550 fz_rethrow(ctx);
551 return buf;
552 }
553
554 fz_buffer *
555 fz_new_buffer_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options)
556 {
557 fz_page *page;
558 fz_buffer *buf = NULL;
559
560 page = fz_load_page(ctx, doc, number);
561 fz_try(ctx)
562 buf = fz_new_buffer_from_page(ctx, page, options);
563 fz_always(ctx)
564 fz_drop_page(ctx, page);
565 fz_catch(ctx)
566 fz_rethrow(ctx);
567 return buf;
568 }
569
570 void
571 fz_write_image_as_data_uri(fz_context *ctx, fz_output *out, fz_image *image)
572 {
573 fz_compressed_buffer *cbuf;
574 fz_buffer *buf;
575
576 cbuf = fz_compressed_image_buffer(ctx, image);
577
578 if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG)
579 {
580 int type = fz_colorspace_type(ctx, image->colorspace);
581 if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB)
582 {
583 fz_write_string(ctx, out, "data:image/jpeg;base64,");
584 fz_write_base64_buffer(ctx, out, cbuf->buffer, 1);
585 return;
586 }
587 }
588 if (cbuf && cbuf->params.type == FZ_IMAGE_PNG)
589 {
590 fz_write_string(ctx, out, "data:image/png;base64,");
591 fz_write_base64_buffer(ctx, out, cbuf->buffer, 1);
592 return;
593 }
594
595 buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);
596 fz_try(ctx)
597 {
598 fz_write_string(ctx, out, "data:image/png;base64,");
599 fz_write_base64_buffer(ctx, out, buf, 1);
600 }
601 fz_always(ctx)
602 fz_drop_buffer(ctx, buf);
603 fz_catch(ctx)
604 fz_rethrow(ctx);
605 }
606
607 static uint32_t read16(const uint8_t *d, size_t *pos, size_t len, int order)
608 {
609 size_t p = *pos;
610 uint32_t v;
611
612 if (p+1 >= len)
613 {
614 *pos = len;
615 return 0;
616 }
617
618 if (order)
619 {
620 v = d[p++]<<8; /* BE */
621 v |= d[p++];
622 }
623 else
624 {
625 v = d[p++]; /* LE */
626 v |= d[p++]<<8;
627 }
628
629 *pos = p;
630
631 return v;
632 }
633
634 static uint32_t read32(const uint8_t *d, size_t *pos, size_t len, int order)
635 {
636 size_t p = *pos;
637 uint32_t v;
638
639 if (p+3 >= len)
640 {
641 *pos = len;
642 return 0;
643 }
644
645 if (order)
646 {
647 v = d[p++]<<24; /* BE */
648 v |= d[p++]<<16;
649 v |= d[p++]<<8;
650 v |= d[p++];
651 }
652 else
653 {
654 v = d[p++];
655 v |= d[p++]<<8; /* LE */
656 v |= d[p++]<<16;
657 v |= d[p++]<<24;
658 }
659
660 *pos = p;
661
662 return v;
663 }
664
665 static void write16(uint8_t *d, size_t *pos, size_t len, int order, uint32_t v)
666 {
667 size_t p = *pos;
668
669 if (p+1 >= len)
670 {
671 *pos = len;
672 return;
673 }
674
675 if (order)
676 {
677 d[p++] = (v>>8);
678 d[p++] = v;
679 }
680 else
681 {
682 d[p++] = v;
683 d[p++] = (v>>8);
684 }
685
686 *pos = p;
687 }
688
689 static void write32( uint8_t *d, size_t *pos, size_t len, int order, uint32_t v)
690 {
691 size_t p = *pos;
692
693 if (p+3 >= len)
694 {
695 *pos = len;
696 return;
697 }
698
699 if (order)
700 {
701 d[p++] = (v>>24);
702 d[p++] = (v>>16);
703 d[p++] = (v>>8);
704 d[p++] = v;
705 }
706 else
707 {
708 d[p++] = v;
709 d[p++] = (v>>8);
710 d[p++] = (v>>16);
711 d[p++] = (v>>24);
712 }
713
714 *pos = p;
715 }
716
717 fz_buffer *
718 fz_sanitize_jpeg_buffer(fz_context *ctx, fz_buffer *in)
719 {
720 fz_buffer *out = fz_clone_buffer(ctx, in);
721 size_t len = out->len;
722 size_t pos = 0;
723 uint8_t *d = out->data;
724
725 /* We need at least 4 data bytes. */
726 while (pos+4 < len)
727 {
728 uint8_t m;
729 /* We should be on a marker. If not, inch forwards until we are. */
730 if (d[pos++] != 0xff)
731 continue;
732 m = d[pos++];
733 if (m == 0xDA)
734 break; /* Start Of Scan. All our rewriting happens before this. */
735 if (m == 0xE1)
736 {
737 uint8_t order;
738 uint32_t tmp;
739 size_t body_start;
740 /* APP1 tag. This is where the EXIF data lives. */
741 /* Read and discard the marker length. We're not continuing after this anyway. */
742 (void)read16(d, &pos, len, 0);
743 tmp = read32(d, &pos, len, 0);
744 if (tmp != 0x66697845) /* Exif */
745 break; /* Not exif - nothing to rewrite. */
746 tmp = read16(d, &pos, len, 0);
747 if (tmp != 0) /* Terminator + Pad */
748 break; /* Not exif - nothing to rewrite. */
749 /* Now we're at the APP1 Body. */
750 body_start = pos;
751 tmp = read16(d, &pos, len, 0);
752 if (tmp == 0x4949)
753 order = 0; /* LE */
754 else if (tmp == 0x4d4d)
755 order = 1; /* BE */
756 else
757 break; /* Bad TIFF type. Bale. */
758 tmp = read16(d, &pos, len, order);
759 if (tmp != 0x002a) /* 42 */
760 break; /* Bad version field. Bale. */
761 do
762 {
763 uint32_t i, n;
764 tmp = read32(d, &pos, len, order);
765 pos = body_start + tmp;
766 if (tmp == 0 || pos >= len)
767 break;
768 n = read16(d, &pos, len, order);
769 for (i = 0; i < n; i++)
770 {
771 if (read16(d, &pos, len, order) == 0x112)
772 {
773 /* Orientation tag! */
774 write16(d, &pos, len, order, 3); /* 3 = short */
775 write32(d, &pos, len, order, 1); /* Count = 1 */
776 write16(d, &pos, len, order, 1); /* Value = 1 */
777 write16(d, &pos, len, order, 0); /* padding */
778 i = n;
779 pos = len; /* Done! */
780 }
781 else
782 pos += 10;
783 }
784 }
785 while (pos+4 < len);
786 break;
787 }
788 else if (m >= 0xD0 && m <= 0xD7)
789 {
790 /* RSTm - no length code. But we shouldn't hit this! */
791 }
792 else if (m == 0x01)
793 {
794 /* TEM - temporary private use in arithmetic coding - shouldn't hit this either. */
795 }
796 else if (m == 0xD8)
797 {
798 /* SOI - start of image. */
799 }
800 else if (m == 0x01)
801 {
802 /* EOI - end of image. */
803 }
804 else
805 {
806 /* All other markers have a length. */
807 size_t marker_len = d[pos]*256 + d[pos+1];
808 pos += marker_len; /* The 2 length bytes are included in the marker_len */
809 }
810 }
811
812 return out;
813 }
814
815 void
816 fz_append_image_as_data_uri(fz_context *ctx, fz_buffer *out, fz_image *image)
817 {
818 fz_compressed_buffer *cbuf;
819 fz_buffer *buf;
820 const char *mime;
821
822 cbuf = fz_compressed_image_buffer(ctx, image);
823
824 if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG)
825 {
826 int type = fz_colorspace_type(ctx, image->colorspace);
827 if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB)
828 {
829 fz_buffer *new_buf = fz_sanitize_jpeg_buffer(ctx, cbuf->buffer);
830 fz_append_string(ctx, out, "data:image/jpeg;base64,");
831 fz_try(ctx)
832 fz_append_base64_buffer(ctx, out, new_buf, 1);
833 fz_always(ctx)
834 fz_drop_buffer(ctx, new_buf);
835 fz_catch(ctx)
836 fz_rethrow(ctx);
837 return;
838 }
839 }
840
841 if (cbuf && cbuf->params.type == FZ_IMAGE_PNG)
842 {
843 fz_append_string(ctx, out, "data:image/png;base64,");
844 fz_append_base64_buffer(ctx, out, cbuf->buffer, 1);
845 return;
846 }
847
848 if (fz_is_lossy_image(ctx, image))
849 {
850 /* Convert lossy image formats to JPEG */
851 buf = fz_new_buffer_from_image_as_jpeg(ctx, image, fz_default_color_params, 90, 0);
852 mime = "data:image/jpeg;base64,";
853 }
854 else
855 {
856 buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);
857 mime = "data:image/png;base64,";
858 }
859
860 fz_try(ctx)
861 {
862 fz_append_string(ctx, out, mime);
863 fz_append_base64_buffer(ctx, out, buf, 1);
864 }
865 fz_always(ctx)
866 fz_drop_buffer(ctx, buf);
867 fz_catch(ctx)
868 fz_rethrow(ctx);
869 }
870
871 void
872 fz_write_pixmap_as_data_uri(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
873 {
874 fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params);
875 fz_try(ctx)
876 {
877 fz_write_string(ctx, out, "data:image/png;base64,");
878 fz_write_base64_buffer(ctx, out, buf, 1);
879 }
880 fz_always(ctx)
881 fz_drop_buffer(ctx, buf);
882 fz_catch(ctx)
883 fz_rethrow(ctx);
884 }
885
886 void
887 fz_append_pixmap_as_data_uri(fz_context *ctx, fz_buffer *out, fz_pixmap *pixmap)
888 {
889 fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params);
890 fz_try(ctx)
891 {
892 fz_append_string(ctx, out, "data:image/png;base64,");
893 fz_append_base64_buffer(ctx, out, buf, 1);
894 }
895 fz_always(ctx)
896 fz_drop_buffer(ctx, buf);
897 fz_catch(ctx)
898 fz_rethrow(ctx);
899 }
900
901 fz_document *
902 fz_new_xhtml_document_from_document(fz_context *ctx, fz_document *old_doc, const fz_stext_options *opts)
903 {
904 fz_stext_options default_opts = { FZ_STEXT_PRESERVE_IMAGES | FZ_STEXT_DEHYPHENATE };
905 fz_document *new_doc;
906 fz_buffer *buf = NULL;
907 fz_output *out = NULL;
908 fz_stream *stm = NULL;
909 fz_stext_page *text = NULL;
910 int i;
911
912 fz_var(buf);
913 fz_var(out);
914 fz_var(stm);
915 fz_var(text);
916
917 if (!opts)
918 opts = &default_opts;
919
920 fz_try(ctx)
921 {
922 buf = fz_new_buffer(ctx, 8192);
923 out = fz_new_output_with_buffer(ctx, buf);
924 fz_print_stext_header_as_xhtml(ctx, out);
925
926 for (i = 0; i < fz_count_pages(ctx, old_doc); ++i)
927 {
928 text = fz_new_stext_page_from_page_number(ctx, old_doc, i, opts);
929 fz_print_stext_page_as_xhtml(ctx, out, text, i+1);
930 fz_drop_stext_page(ctx, text);
931 text = NULL;
932 }
933
934 fz_print_stext_trailer_as_xhtml(ctx, out);
935 fz_close_output(ctx, out);
936 fz_terminate_buffer(ctx, buf);
937
938 stm = fz_open_buffer(ctx, buf);
939 new_doc = fz_open_document_with_stream(ctx, "application/xhtml+xml", stm);
940 }
941 fz_always(ctx)
942 {
943 fz_drop_stream(ctx, stm);
944 fz_drop_buffer(ctx, buf);
945 fz_drop_output(ctx, out);
946 fz_drop_stext_page(ctx, text);
947 }
948 fz_catch(ctx)
949 fz_rethrow(ctx);
950
951 return new_doc;
952 }
953
954 fz_buffer *
955 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)
956 {
957 fz_buffer *buf = NULL;
958 fz_output *out;
959 fz_document_writer *writer = NULL;
960 fz_device *dev = NULL;
961
962 fz_var(buf);
963 fz_var(writer);
964 fz_var(dev);
965
966 fz_try(ctx)
967 {
968 buf = fz_new_buffer(ctx, 0);
969 out = fz_new_output_with_buffer(ctx, buf);
970 writer = fz_new_document_writer_with_output(ctx, out, format, options);
971 dev = fz_begin_page(ctx, writer, fz_bound_page(ctx, page));
972 fz_run_page(ctx, page, dev, transform, cookie);
973 fz_end_page(ctx, writer);
974 fz_close_document_writer(ctx, writer);
975 }
976 fz_always(ctx)
977 fz_drop_document_writer(ctx, writer);
978 fz_catch(ctx)
979 {
980 fz_drop_buffer(ctx, buf);
981 fz_rethrow(ctx);
982 }
983 return buf;
984 }