Coverage Report

Created: 2024-09-08 06:22

/src/mupdf/source/fitz/util.c
Line
Count
Source (jump to first uncovered line)
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
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
  return fz_fill_pixmap_from_display_list(ctx, list, ctm, pix);
123
0
}
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
0
{
128
0
  fz_device *dev = NULL;
129
130
0
  fz_var(dev);
131
132
0
  fz_try(ctx)
133
0
  {
134
0
    dev = fz_new_draw_device(ctx, ctm, pix);
135
0
    fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);
136
0
    fz_close_device(ctx, dev);
137
0
  }
138
0
  fz_always(ctx)
139
0
  {
140
0
    fz_drop_device(ctx, dev);
141
0
  }
142
0
  fz_catch(ctx)
143
0
  {
144
0
    fz_drop_pixmap(ctx, pix);
145
0
    fz_rethrow(ctx);
146
0
  }
147
148
0
  return pix;
149
0
}
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
0
{
154
0
  return fz_new_pixmap_from_page_contents_with_separations(ctx, page, ctm, cs, NULL, alpha);
155
0
}
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
0
{
160
0
  fz_rect rect;
161
0
  fz_irect bbox;
162
0
  fz_pixmap *pix;
163
0
  fz_device *dev = NULL;
164
165
0
  fz_var(dev);
166
167
0
  rect = fz_bound_page(ctx, page);
168
0
  rect = fz_transform_rect(rect, ctm);
169
0
  bbox = fz_round_rect(rect);
170
171
0
  pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha);
172
0
  if (alpha)
173
0
    fz_clear_pixmap(ctx, pix);
174
0
  else
175
0
    fz_clear_pixmap_with_value(ctx, pix, 0xFF);
176
177
0
  fz_try(ctx)
178
0
  {
179
0
    dev = fz_new_draw_device(ctx, ctm, pix);
180
0
    fz_run_page_contents(ctx, page, dev, fz_identity, NULL);
181
0
    fz_close_device(ctx, dev);
182
0
  }
183
0
  fz_always(ctx)
184
0
  {
185
0
    fz_drop_device(ctx, dev);
186
0
  }
187
0
  fz_catch(ctx)
188
0
  {
189
0
    fz_drop_pixmap(ctx, pix);
190
0
    fz_rethrow(ctx);
191
0
  }
192
193
0
  return pix;
194
0
}
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
0
{
199
0
  return fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, NULL, alpha);
200
0
}
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
12.6k
{
205
12.6k
  fz_rect rect;
206
12.6k
  fz_irect bbox;
207
12.6k
  fz_pixmap *pix;
208
12.6k
  fz_device *dev = NULL;
209
210
12.6k
  fz_var(dev);
211
212
12.6k
  rect = fz_bound_page(ctx, page);
213
12.6k
  rect = fz_transform_rect(rect, ctm);
214
12.6k
  bbox = fz_round_rect(rect);
215
216
12.6k
  pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha);
217
218
25.3k
  fz_try(ctx)
219
25.3k
  {
220
12.6k
    if (alpha)
221
0
      fz_clear_pixmap(ctx, pix);
222
12.6k
    else
223
12.6k
      fz_clear_pixmap_with_value(ctx, pix, 0xFF);
224
225
12.6k
    dev = fz_new_draw_device(ctx, ctm, pix);
226
12.6k
    fz_run_page(ctx, page, dev, fz_identity, NULL);
227
12.6k
    fz_close_device(ctx, dev);
228
12.6k
  }
229
25.3k
  fz_always(ctx)
230
12.6k
  {
231
12.6k
    fz_drop_device(ctx, dev);
232
12.6k
  }
233
12.6k
  fz_catch(ctx)
234
140
  {
235
140
    fz_drop_pixmap(ctx, pix);
236
140
    fz_rethrow(ctx);
237
140
  }
238
239
12.5k
  return pix;
240
12.6k
}
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
13.8k
{
245
13.8k
  return fz_new_pixmap_from_page_number_with_separations(ctx, doc, number, ctm, cs, NULL, alpha);
246
13.8k
}
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
13.8k
{
251
13.8k
  fz_page *page;
252
13.8k
  fz_pixmap *pix = NULL;
253
254
13.8k
  page = fz_load_page(ctx, doc, number);
255
25.3k
  fz_try(ctx)
256
25.3k
    pix = fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, seps, alpha);
257
25.3k
  fz_always(ctx)
258
12.6k
    fz_drop_page(ctx, page);
259
12.6k
  fz_catch(ctx)
260
163
    fz_rethrow(ctx);
261
13.6k
  return pix;
262
13.8k
}
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
0
{
267
0
  fz_stext_page *text;
268
0
  fz_device *dev = NULL;
269
270
0
  fz_var(dev);
271
272
0
  if (list == NULL)
273
0
    return NULL;
274
275
0
  text = fz_new_stext_page(ctx, fz_bound_display_list(ctx, list));
276
0
  fz_try(ctx)
277
0
  {
278
0
    dev = fz_new_stext_device(ctx, text, options);
279
0
    fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);
280
0
    fz_close_device(ctx, dev);
281
0
  }
282
0
  fz_always(ctx)
283
0
  {
284
0
    fz_drop_device(ctx, dev);
285
0
  }
286
0
  fz_catch(ctx)
287
0
  {
288
0
    fz_drop_stext_page(ctx, text);
289
0
    fz_rethrow(ctx);
290
0
  }
291
292
0
  return text;
293
0
}
294
295
fz_stext_page *
296
fz_new_stext_page_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options)
297
0
{
298
0
  fz_stext_page *text;
299
0
  fz_device *dev = NULL;
300
301
0
  fz_var(dev);
302
303
0
  if (page == NULL)
304
0
    return NULL;
305
306
0
  text = fz_new_stext_page(ctx, fz_bound_page(ctx, page));
307
0
  fz_try(ctx)
308
0
  {
309
0
    dev = fz_new_stext_device(ctx, text, options);
310
0
    fz_run_page_contents(ctx, page, dev, fz_identity, NULL);
311
0
    fz_close_device(ctx, dev);
312
0
  }
313
0
  fz_always(ctx)
314
0
  {
315
0
    fz_drop_device(ctx, dev);
316
0
  }
317
0
  fz_catch(ctx)
318
0
  {
319
0
    fz_drop_stext_page(ctx, text);
320
0
    fz_rethrow(ctx);
321
0
  }
322
323
0
  return text;
324
0
}
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
0
{
329
0
  fz_page *page;
330
0
  fz_stext_page *text = NULL;
331
332
0
  page = fz_load_page(ctx, doc, number);
333
0
  fz_try(ctx)
334
0
    text = fz_new_stext_page_from_page(ctx, page, options);
335
0
  fz_always(ctx)
336
0
    fz_drop_page(ctx, page);
337
0
  fz_catch(ctx)
338
0
    fz_rethrow(ctx);
339
0
  return text;
340
0
}
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
0
{
345
0
  fz_page *page;
346
0
  fz_stext_page *text = NULL;
347
348
0
  page = fz_load_chapter_page(ctx, doc, chapter, number);
349
0
  fz_try(ctx)
350
0
    text = fz_new_stext_page_from_page(ctx, page, options);
351
0
  fz_always(ctx)
352
0
    fz_drop_page(ctx, page);
353
0
  fz_catch(ctx)
354
0
    fz_rethrow(ctx);
355
0
  return text;
356
0
}
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
0
{
361
0
  fz_stext_page *text;
362
0
  int count = 0;
363
364
0
  text = fz_new_stext_page_from_display_list(ctx, list, NULL);
365
0
  fz_try(ctx)
366
0
    count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
367
0
  fz_always(ctx)
368
0
    fz_drop_stext_page(ctx, text);
369
0
  fz_catch(ctx)
370
0
    fz_rethrow(ctx);
371
0
  return count;
372
0
}
373
374
int
375
fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
376
0
{
377
0
  fz_stext_options opts = { FZ_STEXT_DEHYPHENATE };
378
0
  fz_stext_page *text;
379
0
  int count = 0;
380
381
0
  text = fz_new_stext_page_from_page(ctx, page, &opts);
382
0
  fz_try(ctx)
383
0
    count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
384
0
  fz_always(ctx)
385
0
    fz_drop_stext_page(ctx, text);
386
0
  fz_catch(ctx)
387
0
    fz_rethrow(ctx);
388
0
  return count;
389
0
}
390
391
int
392
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)
393
0
{
394
0
  fz_page *page;
395
0
  int count = 0;
396
397
0
  page = fz_load_page(ctx, doc, number);
398
0
  fz_try(ctx)
399
0
    count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
400
0
  fz_always(ctx)
401
0
    fz_drop_page(ctx, page);
402
0
  fz_catch(ctx)
403
0
    fz_rethrow(ctx);
404
0
  return count;
405
0
}
406
407
int
408
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)
409
0
{
410
0
  fz_page *page;
411
0
  int count = 0;
412
413
0
  page = fz_load_chapter_page(ctx, doc, chapter, number);
414
0
  fz_try(ctx)
415
0
    count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
416
0
  fz_always(ctx)
417
0
    fz_drop_page(ctx, page);
418
0
  fz_catch(ctx)
419
0
    fz_rethrow(ctx);
420
0
  return count;
421
0
}
422
423
fz_buffer *
424
fz_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *page)
425
0
{
426
0
  fz_stext_block *block;
427
0
  fz_stext_line *line;
428
0
  fz_stext_char *ch;
429
0
  fz_buffer *buf;
430
431
0
  buf = fz_new_buffer(ctx, 256);
432
0
  fz_try(ctx)
433
0
  {
434
0
    for (block = page->first_block; block; block = block->next)
435
0
    {
436
0
      if (block->type == FZ_STEXT_BLOCK_TEXT)
437
0
      {
438
0
        for (line = block->u.t.first_line; line; line = line->next)
439
0
        {
440
0
          for (ch = line->first_char; ch; ch = ch->next)
441
0
            fz_append_rune(ctx, buf, ch->c);
442
0
          fz_append_byte(ctx, buf, '\n');
443
0
        }
444
0
        fz_append_byte(ctx, buf, '\n');
445
0
      }
446
0
    }
447
0
  }
448
0
  fz_catch(ctx)
449
0
  {
450
0
    fz_drop_buffer(ctx, buf);
451
0
    fz_rethrow(ctx);
452
0
  }
453
454
0
  return buf;
455
0
}
456
457
fz_buffer *
458
fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options)
459
0
{
460
0
  fz_stext_page *text;
461
0
  fz_buffer *buf = NULL;
462
463
0
  text = fz_new_stext_page_from_display_list(ctx, list, options);
464
0
  fz_try(ctx)
465
0
    buf = fz_new_buffer_from_stext_page(ctx, text);
466
0
  fz_always(ctx)
467
0
    fz_drop_stext_page(ctx, text);
468
0
  fz_catch(ctx)
469
0
    fz_rethrow(ctx);
470
0
  return buf;
471
0
}
472
473
fz_buffer *
474
fz_new_buffer_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options)
475
0
{
476
0
  fz_stext_page *text;
477
0
  fz_buffer *buf = NULL;
478
479
0
  text = fz_new_stext_page_from_page(ctx, page, options);
480
0
  fz_try(ctx)
481
0
    buf = fz_new_buffer_from_stext_page(ctx, text);
482
0
  fz_always(ctx)
483
0
    fz_drop_stext_page(ctx, text);
484
0
  fz_catch(ctx)
485
0
    fz_rethrow(ctx);
486
0
  return buf;
487
0
}
488
489
fz_buffer *
490
fz_new_buffer_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options)
491
0
{
492
0
  fz_page *page;
493
0
  fz_buffer *buf = NULL;
494
495
0
  page = fz_load_page(ctx, doc, number);
496
0
  fz_try(ctx)
497
0
    buf = fz_new_buffer_from_page(ctx, page, options);
498
0
  fz_always(ctx)
499
0
    fz_drop_page(ctx, page);
500
0
  fz_catch(ctx)
501
0
    fz_rethrow(ctx);
502
0
  return buf;
503
0
}
504
505
void
506
fz_write_image_as_data_uri(fz_context *ctx, fz_output *out, fz_image *image)
507
0
{
508
0
  fz_compressed_buffer *cbuf;
509
0
  fz_buffer *buf;
510
511
0
  cbuf = fz_compressed_image_buffer(ctx, image);
512
513
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG)
514
0
  {
515
0
    int type = fz_colorspace_type(ctx, image->colorspace);
516
0
    if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB)
517
0
    {
518
0
      fz_write_string(ctx, out, "data:image/jpeg;base64,");
519
0
      fz_write_base64_buffer(ctx, out, cbuf->buffer, 1);
520
0
      return;
521
0
    }
522
0
  }
523
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_PNG)
524
0
  {
525
0
    fz_write_string(ctx, out, "data:image/png;base64,");
526
0
    fz_write_base64_buffer(ctx, out, cbuf->buffer, 1);
527
0
    return;
528
0
  }
529
530
0
  buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);
531
0
  fz_try(ctx)
532
0
  {
533
0
    fz_write_string(ctx, out, "data:image/png;base64,");
534
0
    fz_write_base64_buffer(ctx, out, buf, 1);
535
0
  }
536
0
  fz_always(ctx)
537
0
    fz_drop_buffer(ctx, buf);
538
0
  fz_catch(ctx)
539
0
    fz_rethrow(ctx);
540
0
}
541
542
static uint32_t read16(const uint8_t *d, size_t *pos, size_t len, int order)
543
0
{
544
0
  size_t p = *pos;
545
0
  uint32_t v;
546
547
0
  if (p+1 >= len)
548
0
  {
549
0
    *pos = len;
550
0
    return 0;
551
0
  }
552
553
0
  if (order)
554
0
  {
555
0
    v = d[p++]<<8; /* BE */
556
0
    v |= d[p++];
557
0
  }
558
0
  else
559
0
  {
560
0
    v = d[p++]; /* LE */
561
0
    v |= d[p++]<<8;
562
0
  }
563
564
0
  *pos = p;
565
566
0
  return v;
567
0
}
568
569
static uint32_t read32(const uint8_t *d, size_t *pos, size_t len, int order)
570
0
{
571
0
  size_t p = *pos;
572
0
  uint32_t v;
573
574
0
  if (p+3 >= len)
575
0
  {
576
0
    *pos = len;
577
0
    return 0;
578
0
  }
579
580
0
  if (order)
581
0
  {
582
0
    v = d[p++]<<24; /* BE */
583
0
    v |= d[p++]<<16;
584
0
    v |= d[p++]<<8;
585
0
    v |= d[p++];
586
0
  }
587
0
  else
588
0
  {
589
0
    v = d[p++];
590
0
    v |= d[p++]<<8; /* LE */
591
0
    v |= d[p++]<<16;
592
0
    v |= d[p++]<<24;
593
0
  }
594
595
0
  *pos = p;
596
597
0
  return v;
598
0
}
599
600
static void write16(uint8_t *d, size_t *pos, size_t len, int order, uint32_t v)
601
0
{
602
0
  size_t p = *pos;
603
604
0
  if (p+1 >= len)
605
0
  {
606
0
    *pos = len;
607
0
    return;
608
0
  }
609
610
0
  if (order)
611
0
  {
612
0
    d[p++] = (v>>8);
613
0
    d[p++] = v;
614
0
  }
615
0
  else
616
0
  {
617
0
    d[p++] = v;
618
0
    d[p++] = (v>>8);
619
0
  }
620
621
0
  *pos = p;
622
0
}
623
624
static void write32( uint8_t *d, size_t *pos, size_t len, int order, uint32_t v)
625
0
{
626
0
  size_t p = *pos;
627
628
0
  if (p+3 >= len)
629
0
  {
630
0
    *pos = len;
631
0
    return;
632
0
  }
633
634
0
  if (order)
635
0
  {
636
0
    d[p++] = (v>>24);
637
0
    d[p++] = (v>>16);
638
0
    d[p++] = (v>>8);
639
0
    d[p++] = v;
640
0
  }
641
0
  else
642
0
  {
643
0
    d[p++] = v;
644
0
    d[p++] = (v>>8);
645
0
    d[p++] = (v>>16);
646
0
    d[p++] = (v>>24);
647
0
  }
648
649
0
  *pos = p;
650
0
}
651
652
fz_buffer *
653
fz_sanitize_jpeg_buffer(fz_context *ctx, fz_buffer *in)
654
0
{
655
0
  fz_buffer *out = fz_clone_buffer(ctx, in);
656
0
  size_t len = out->len;
657
0
  size_t pos = 0;
658
0
  uint8_t *d = out->data;
659
660
  /* We need at least 4 data bytes. */
661
0
  while (pos+4 < len)
662
0
  {
663
0
    uint8_t m;
664
    /* We should be on a marker. If not, inch forwards until we are. */
665
0
    if (d[pos++] != 0xff)
666
0
      continue;
667
0
    m = d[pos++];
668
0
    if (m == 0xDA)
669
0
      break; /* Start Of Scan. All our rewriting happens before this. */
670
0
    if (m == 0xE1)
671
0
    {
672
0
      uint8_t order;
673
0
      uint32_t tmp;
674
0
      size_t body_start;
675
      /* APP1 tag. This is where the EXIF data lives. */
676
      /* Read and discard the marker length. We're not continuing after this anyway. */
677
0
      (void)read16(d, &pos, len, 0);
678
0
      tmp = read32(d, &pos, len, 0);
679
0
      if (tmp != 0x66697845) /* Exif */
680
0
        break; /* Not exif - nothing to rewrite. */
681
0
      tmp = read16(d, &pos, len, 0);
682
0
      if (tmp != 0) /* Terminator + Pad */
683
0
        break; /* Not exif - nothing to rewrite. */
684
      /* Now we're at the APP1 Body. */
685
0
      body_start = pos;
686
0
      tmp = read16(d, &pos, len, 0);
687
0
      if (tmp == 0x4949)
688
0
        order = 0; /* LE */
689
0
      else if (tmp == 0x4d4d)
690
0
        order = 1; /* BE */
691
0
      else
692
0
        break; /* Bad TIFF type. Bale. */
693
0
      tmp = read16(d, &pos, len, order);
694
0
      if (tmp != 0x002a) /* 42 */
695
0
        break; /* Bad version field.  Bale. */
696
0
      do
697
0
      {
698
0
        uint32_t i, n;
699
0
        tmp = read32(d, &pos, len, order);
700
0
        pos = body_start + tmp;
701
0
        if (tmp == 0 || pos >= len)
702
0
          break;
703
0
        n = read16(d, &pos, len, order);
704
0
        for (i = 0; i < n; i++)
705
0
        {
706
0
          if (read16(d, &pos, len, order) == 0x112)
707
0
          {
708
            /* Orientation tag! */
709
0
            write16(d, &pos, len, order, 3); /* 3 = short */
710
0
            write32(d, &pos, len, order, 1); /* Count = 1 */
711
0
            write16(d, &pos, len, order, 1); /* Value = 1 */
712
0
            write16(d, &pos, len, order, 0); /* padding */
713
0
            i = n;
714
0
            pos = len; /* Done! */
715
0
          }
716
0
          else
717
0
            pos += 10;
718
0
        }
719
0
      }
720
0
      while (pos+4 < len);
721
0
      break;
722
0
    }
723
0
    else if (m >= 0xD0 && m <= 0xD7)
724
0
    {
725
      /* RSTm - no length code. But we shouldn't hit this! */
726
0
    }
727
0
    else if (m == 0x01)
728
0
    {
729
      /* TEM - temporary private use in arithmetic coding - shouldn't hit this either. */
730
0
    }
731
0
    else if (m == 0xD8)
732
0
    {
733
      /* SOI - start of image. */
734
0
    }
735
0
    else if (m == 0x01)
736
0
    {
737
      /* EOI - end of image. */
738
0
    }
739
0
    else
740
0
    {
741
      /* All other markers have a length. */
742
0
      size_t marker_len = d[pos]*256 + d[pos+1];
743
0
      pos += marker_len; /* The 2 length bytes are included in the marker_len */
744
0
    }
745
0
  }
746
747
0
  return out;
748
0
}
749
750
void
751
fz_append_image_as_data_uri(fz_context *ctx, fz_buffer *out, fz_image *image)
752
0
{
753
0
  fz_compressed_buffer *cbuf;
754
0
  fz_buffer *buf;
755
756
0
  cbuf = fz_compressed_image_buffer(ctx, image);
757
758
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG)
759
0
  {
760
0
    int type = fz_colorspace_type(ctx, image->colorspace);
761
0
    if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB)
762
0
    {
763
0
      fz_buffer *new_buf = fz_sanitize_jpeg_buffer(ctx, cbuf->buffer);
764
0
      fz_append_string(ctx, out, "data:image/jpeg;base64,");
765
0
      fz_try(ctx)
766
0
        fz_append_base64_buffer(ctx, out, new_buf, 1);
767
0
      fz_always(ctx)
768
0
        fz_drop_buffer(ctx, new_buf);
769
0
      fz_catch(ctx)
770
0
        fz_rethrow(ctx);
771
0
      return;
772
0
    }
773
0
  }
774
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_PNG)
775
0
  {
776
0
    fz_append_string(ctx, out, "data:image/png;base64,");
777
0
    fz_append_base64_buffer(ctx, out, cbuf->buffer, 1);
778
0
    return;
779
0
  }
780
781
0
  buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);
782
0
  fz_try(ctx)
783
0
  {
784
0
    fz_append_string(ctx, out, "data:image/png;base64,");
785
0
    fz_append_base64_buffer(ctx, out, buf, 1);
786
0
  }
787
0
  fz_always(ctx)
788
0
    fz_drop_buffer(ctx, buf);
789
0
  fz_catch(ctx)
790
0
    fz_rethrow(ctx);
791
0
}
792
793
void
794
fz_write_pixmap_as_data_uri(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
795
0
{
796
0
  fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params);
797
0
  fz_try(ctx)
798
0
  {
799
0
    fz_write_string(ctx, out, "data:image/png;base64,");
800
0
    fz_write_base64_buffer(ctx, out, buf, 1);
801
0
  }
802
0
  fz_always(ctx)
803
0
    fz_drop_buffer(ctx, buf);
804
0
  fz_catch(ctx)
805
0
    fz_rethrow(ctx);
806
0
}
807
808
void
809
fz_append_pixmap_as_data_uri(fz_context *ctx, fz_buffer *out, fz_pixmap *pixmap)
810
0
{
811
0
  fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params);
812
0
  fz_try(ctx)
813
0
  {
814
0
    fz_append_string(ctx, out, "data:image/png;base64,");
815
0
    fz_append_base64_buffer(ctx, out, buf, 1);
816
0
  }
817
0
  fz_always(ctx)
818
0
    fz_drop_buffer(ctx, buf);
819
0
  fz_catch(ctx)
820
0
    fz_rethrow(ctx);
821
0
}
822
823
fz_document *
824
fz_new_xhtml_document_from_document(fz_context *ctx, fz_document *old_doc, const fz_stext_options *opts)
825
0
{
826
0
  fz_stext_options default_opts = { FZ_STEXT_PRESERVE_IMAGES | FZ_STEXT_DEHYPHENATE };
827
0
  fz_document *new_doc;
828
0
  fz_buffer *buf = NULL;
829
0
  fz_output *out = NULL;
830
0
  fz_stream *stm = NULL;
831
0
  fz_stext_page *text = NULL;
832
0
  int i;
833
834
0
  fz_var(buf);
835
0
  fz_var(out);
836
0
  fz_var(stm);
837
0
  fz_var(text);
838
839
0
  if (!opts)
840
0
    opts = &default_opts;
841
842
0
  fz_try(ctx)
843
0
  {
844
0
    buf = fz_new_buffer(ctx, 8192);
845
0
    out = fz_new_output_with_buffer(ctx, buf);
846
0
    fz_print_stext_header_as_xhtml(ctx, out);
847
848
0
    for (i = 0; i < fz_count_pages(ctx, old_doc); ++i)
849
0
    {
850
0
      text = fz_new_stext_page_from_page_number(ctx, old_doc, i, opts);
851
0
      fz_print_stext_page_as_xhtml(ctx, out, text, i+1);
852
0
      fz_drop_stext_page(ctx, text);
853
0
      text = NULL;
854
0
    }
855
856
0
    fz_print_stext_trailer_as_xhtml(ctx, out);
857
0
    fz_close_output(ctx, out);
858
0
    fz_terminate_buffer(ctx, buf);
859
860
0
    stm = fz_open_buffer(ctx, buf);
861
0
    new_doc = fz_open_document_with_stream(ctx, "application/xhtml+xml", stm);
862
0
  }
863
0
  fz_always(ctx)
864
0
  {
865
0
    fz_drop_stream(ctx, stm);
866
0
    fz_drop_buffer(ctx, buf);
867
0
    fz_drop_output(ctx, out);
868
0
    fz_drop_stext_page(ctx, text);
869
0
  }
870
0
  fz_catch(ctx)
871
0
    fz_rethrow(ctx);
872
873
0
  return new_doc;
874
0
}
875
876
fz_buffer *
877
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)
878
0
{
879
0
  fz_buffer *buf = NULL;
880
0
  fz_output *out;
881
0
  fz_document_writer *writer = NULL;
882
0
  fz_device *dev = NULL;
883
884
0
  fz_var(buf);
885
0
  fz_var(writer);
886
0
  fz_var(dev);
887
888
0
  fz_try(ctx)
889
0
  {
890
0
    buf = fz_new_buffer(ctx, 0);
891
0
    out = fz_new_output_with_buffer(ctx, buf);
892
0
    writer = fz_new_document_writer_with_output(ctx, out, format, options);
893
0
    dev = fz_begin_page(ctx, writer, fz_bound_page(ctx, page));
894
0
    fz_run_page(ctx, page, dev, transform, cookie);
895
0
    fz_end_page(ctx, writer);
896
0
    fz_close_document_writer(ctx, writer);
897
0
  }
898
0
  fz_always(ctx)
899
0
    fz_drop_document_writer(ctx, writer);
900
0
  fz_catch(ctx)
901
0
  {
902
0
    fz_drop_buffer(ctx, buf);
903
0
    fz_rethrow(ctx);
904
0
  }
905
0
  return buf;
906
0
}