Coverage Report

Created: 2025-01-11 06:55

/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
13.2k
{
205
13.2k
  fz_rect rect;
206
13.2k
  fz_irect bbox;
207
13.2k
  fz_pixmap *pix;
208
13.2k
  fz_device *dev = NULL;
209
210
13.2k
  fz_var(dev);
211
212
13.2k
  rect = fz_bound_page(ctx, page);
213
13.2k
  rect = fz_transform_rect(rect, ctm);
214
13.2k
  bbox = fz_round_rect(rect);
215
216
13.2k
  pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha);
217
218
26.4k
  fz_try(ctx)
219
26.4k
  {
220
13.2k
    if (alpha)
221
0
      fz_clear_pixmap(ctx, pix);
222
13.2k
    else
223
13.2k
      fz_clear_pixmap_with_value(ctx, pix, 0xFF);
224
225
13.2k
    dev = fz_new_draw_device(ctx, ctm, pix);
226
13.2k
    fz_run_page(ctx, page, dev, fz_identity, NULL);
227
13.2k
    fz_close_device(ctx, dev);
228
13.2k
  }
229
26.4k
  fz_always(ctx)
230
13.2k
  {
231
13.2k
    fz_drop_device(ctx, dev);
232
13.2k
  }
233
13.2k
  fz_catch(ctx)
234
146
  {
235
146
    fz_drop_pixmap(ctx, pix);
236
146
    fz_rethrow(ctx);
237
146
  }
238
239
13.0k
  return pix;
240
13.2k
}
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
14.2k
{
245
14.2k
  return fz_new_pixmap_from_page_number_with_separations(ctx, doc, number, ctm, cs, NULL, alpha);
246
14.2k
}
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
14.2k
{
251
14.2k
  fz_page *page;
252
14.2k
  fz_pixmap *pix = NULL;
253
254
14.2k
  page = fz_load_page(ctx, doc, number);
255
26.4k
  fz_try(ctx)
256
26.4k
    pix = fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, seps, alpha);
257
26.4k
  fz_always(ctx)
258
13.2k
    fz_drop_page(ctx, page);
259
13.2k
  fz_catch(ctx)
260
174
    fz_rethrow(ctx);
261
14.0k
  return pix;
262
14.2k
}
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_display_list_cb(fz_context *ctx, fz_display_list *list, const char *needle, fz_search_callback_fn *cb, void *opaque)
376
0
{
377
0
  fz_stext_page *text;
378
0
  int count = 0;
379
380
0
  text = fz_new_stext_page_from_display_list(ctx, list, NULL);
381
0
  fz_try(ctx)
382
0
    count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque);
383
0
  fz_always(ctx)
384
0
    fz_drop_stext_page(ctx, text);
385
0
  fz_catch(ctx)
386
0
    fz_rethrow(ctx);
387
0
  return count;
388
0
}
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
0
{
393
0
  fz_stext_options opts = { FZ_STEXT_DEHYPHENATE };
394
0
  fz_stext_page *text;
395
0
  int count = 0;
396
397
0
  text = fz_new_stext_page_from_page(ctx, page, &opts);
398
0
  fz_try(ctx)
399
0
    count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
400
0
  fz_always(ctx)
401
0
    fz_drop_stext_page(ctx, text);
402
0
  fz_catch(ctx)
403
0
    fz_rethrow(ctx);
404
0
  return count;
405
0
}
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
0
{
410
0
  fz_stext_options opts = { FZ_STEXT_DEHYPHENATE };
411
0
  fz_stext_page *text;
412
0
  int count = 0;
413
414
0
  text = fz_new_stext_page_from_page(ctx, page, &opts);
415
0
  fz_try(ctx)
416
0
    count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque);
417
0
  fz_always(ctx)
418
0
    fz_drop_stext_page(ctx, text);
419
0
  fz_catch(ctx)
420
0
    fz_rethrow(ctx);
421
0
  return count;
422
0
}
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
0
{
427
0
  fz_page *page;
428
0
  int count = 0;
429
430
0
  page = fz_load_page(ctx, doc, number);
431
0
  fz_try(ctx)
432
0
    count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
433
0
  fz_always(ctx)
434
0
    fz_drop_page(ctx, page);
435
0
  fz_catch(ctx)
436
0
    fz_rethrow(ctx);
437
0
  return count;
438
0
}
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
0
{
443
0
  fz_page *page;
444
0
  int count = 0;
445
446
0
  page = fz_load_page(ctx, doc, number);
447
0
  fz_try(ctx)
448
0
    count = fz_search_page_cb(ctx, page, needle, cb, opaque);
449
0
  fz_always(ctx)
450
0
    fz_drop_page(ctx, page);
451
0
  fz_catch(ctx)
452
0
    fz_rethrow(ctx);
453
0
  return count;
454
0
}
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
0
{
459
0
  fz_page *page;
460
0
  int count = 0;
461
462
0
  page = fz_load_chapter_page(ctx, doc, chapter, number);
463
0
  fz_try(ctx)
464
0
    count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
465
0
  fz_always(ctx)
466
0
    fz_drop_page(ctx, page);
467
0
  fz_catch(ctx)
468
0
    fz_rethrow(ctx);
469
0
  return count;
470
0
}
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
0
{
475
0
  fz_page *page;
476
0
  int count = 0;
477
478
0
  page = fz_load_chapter_page(ctx, doc, chapter, number);
479
0
  fz_try(ctx)
480
0
    count = fz_search_page_cb(ctx, page, needle, cb, opaque);
481
0
  fz_always(ctx)
482
0
    fz_drop_page(ctx, page);
483
0
  fz_catch(ctx)
484
0
    fz_rethrow(ctx);
485
0
  return count;
486
0
}
487
488
fz_buffer *
489
fz_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *page)
490
0
{
491
0
  fz_stext_block *block;
492
0
  fz_stext_line *line;
493
0
  fz_stext_char *ch;
494
0
  fz_buffer *buf;
495
496
0
  buf = fz_new_buffer(ctx, 256);
497
0
  fz_try(ctx)
498
0
  {
499
0
    for (block = page->first_block; block; block = block->next)
500
0
    {
501
0
      if (block->type == FZ_STEXT_BLOCK_TEXT)
502
0
      {
503
0
        for (line = block->u.t.first_line; line; line = line->next)
504
0
        {
505
0
          for (ch = line->first_char; ch; ch = ch->next)
506
0
            fz_append_rune(ctx, buf, ch->c);
507
0
          fz_append_byte(ctx, buf, '\n');
508
0
        }
509
0
        fz_append_byte(ctx, buf, '\n');
510
0
      }
511
0
    }
512
0
  }
513
0
  fz_catch(ctx)
514
0
  {
515
0
    fz_drop_buffer(ctx, buf);
516
0
    fz_rethrow(ctx);
517
0
  }
518
519
0
  return buf;
520
0
}
521
522
fz_buffer *
523
fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options)
524
0
{
525
0
  fz_stext_page *text;
526
0
  fz_buffer *buf = NULL;
527
528
0
  text = fz_new_stext_page_from_display_list(ctx, list, options);
529
0
  fz_try(ctx)
530
0
    buf = fz_new_buffer_from_stext_page(ctx, text);
531
0
  fz_always(ctx)
532
0
    fz_drop_stext_page(ctx, text);
533
0
  fz_catch(ctx)
534
0
    fz_rethrow(ctx);
535
0
  return buf;
536
0
}
537
538
fz_buffer *
539
fz_new_buffer_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options)
540
0
{
541
0
  fz_stext_page *text;
542
0
  fz_buffer *buf = NULL;
543
544
0
  text = fz_new_stext_page_from_page(ctx, page, options);
545
0
  fz_try(ctx)
546
0
    buf = fz_new_buffer_from_stext_page(ctx, text);
547
0
  fz_always(ctx)
548
0
    fz_drop_stext_page(ctx, text);
549
0
  fz_catch(ctx)
550
0
    fz_rethrow(ctx);
551
0
  return buf;
552
0
}
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
0
{
557
0
  fz_page *page;
558
0
  fz_buffer *buf = NULL;
559
560
0
  page = fz_load_page(ctx, doc, number);
561
0
  fz_try(ctx)
562
0
    buf = fz_new_buffer_from_page(ctx, page, options);
563
0
  fz_always(ctx)
564
0
    fz_drop_page(ctx, page);
565
0
  fz_catch(ctx)
566
0
    fz_rethrow(ctx);
567
0
  return buf;
568
0
}
569
570
void
571
fz_write_image_as_data_uri(fz_context *ctx, fz_output *out, fz_image *image)
572
0
{
573
0
  fz_compressed_buffer *cbuf;
574
0
  fz_buffer *buf;
575
576
0
  cbuf = fz_compressed_image_buffer(ctx, image);
577
578
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG)
579
0
  {
580
0
    int type = fz_colorspace_type(ctx, image->colorspace);
581
0
    if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB)
582
0
    {
583
0
      fz_write_string(ctx, out, "data:image/jpeg;base64,");
584
0
      fz_write_base64_buffer(ctx, out, cbuf->buffer, 1);
585
0
      return;
586
0
    }
587
0
  }
588
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_PNG)
589
0
  {
590
0
    fz_write_string(ctx, out, "data:image/png;base64,");
591
0
    fz_write_base64_buffer(ctx, out, cbuf->buffer, 1);
592
0
    return;
593
0
  }
594
595
0
  buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);
596
0
  fz_try(ctx)
597
0
  {
598
0
    fz_write_string(ctx, out, "data:image/png;base64,");
599
0
    fz_write_base64_buffer(ctx, out, buf, 1);
600
0
  }
601
0
  fz_always(ctx)
602
0
    fz_drop_buffer(ctx, buf);
603
0
  fz_catch(ctx)
604
0
    fz_rethrow(ctx);
605
0
}
606
607
static uint32_t read16(const uint8_t *d, size_t *pos, size_t len, int order)
608
0
{
609
0
  size_t p = *pos;
610
0
  uint32_t v;
611
612
0
  if (p+1 >= len)
613
0
  {
614
0
    *pos = len;
615
0
    return 0;
616
0
  }
617
618
0
  if (order)
619
0
  {
620
0
    v = d[p++]<<8; /* BE */
621
0
    v |= d[p++];
622
0
  }
623
0
  else
624
0
  {
625
0
    v = d[p++]; /* LE */
626
0
    v |= d[p++]<<8;
627
0
  }
628
629
0
  *pos = p;
630
631
0
  return v;
632
0
}
633
634
static uint32_t read32(const uint8_t *d, size_t *pos, size_t len, int order)
635
0
{
636
0
  size_t p = *pos;
637
0
  uint32_t v;
638
639
0
  if (p+3 >= len)
640
0
  {
641
0
    *pos = len;
642
0
    return 0;
643
0
  }
644
645
0
  if (order)
646
0
  {
647
0
    v = d[p++]<<24; /* BE */
648
0
    v |= d[p++]<<16;
649
0
    v |= d[p++]<<8;
650
0
    v |= d[p++];
651
0
  }
652
0
  else
653
0
  {
654
0
    v = d[p++];
655
0
    v |= d[p++]<<8; /* LE */
656
0
    v |= d[p++]<<16;
657
0
    v |= d[p++]<<24;
658
0
  }
659
660
0
  *pos = p;
661
662
0
  return v;
663
0
}
664
665
static void write16(uint8_t *d, size_t *pos, size_t len, int order, uint32_t v)
666
0
{
667
0
  size_t p = *pos;
668
669
0
  if (p+1 >= len)
670
0
  {
671
0
    *pos = len;
672
0
    return;
673
0
  }
674
675
0
  if (order)
676
0
  {
677
0
    d[p++] = (v>>8);
678
0
    d[p++] = v;
679
0
  }
680
0
  else
681
0
  {
682
0
    d[p++] = v;
683
0
    d[p++] = (v>>8);
684
0
  }
685
686
0
  *pos = p;
687
0
}
688
689
static void write32( uint8_t *d, size_t *pos, size_t len, int order, uint32_t v)
690
0
{
691
0
  size_t p = *pos;
692
693
0
  if (p+3 >= len)
694
0
  {
695
0
    *pos = len;
696
0
    return;
697
0
  }
698
699
0
  if (order)
700
0
  {
701
0
    d[p++] = (v>>24);
702
0
    d[p++] = (v>>16);
703
0
    d[p++] = (v>>8);
704
0
    d[p++] = v;
705
0
  }
706
0
  else
707
0
  {
708
0
    d[p++] = v;
709
0
    d[p++] = (v>>8);
710
0
    d[p++] = (v>>16);
711
0
    d[p++] = (v>>24);
712
0
  }
713
714
0
  *pos = p;
715
0
}
716
717
fz_buffer *
718
fz_sanitize_jpeg_buffer(fz_context *ctx, fz_buffer *in)
719
0
{
720
0
  fz_buffer *out = fz_clone_buffer(ctx, in);
721
0
  size_t len = out->len;
722
0
  size_t pos = 0;
723
0
  uint8_t *d = out->data;
724
725
  /* We need at least 4 data bytes. */
726
0
  while (pos+4 < len)
727
0
  {
728
0
    uint8_t m;
729
    /* We should be on a marker. If not, inch forwards until we are. */
730
0
    if (d[pos++] != 0xff)
731
0
      continue;
732
0
    m = d[pos++];
733
0
    if (m == 0xDA)
734
0
      break; /* Start Of Scan. All our rewriting happens before this. */
735
0
    if (m == 0xE1)
736
0
    {
737
0
      uint8_t order;
738
0
      uint32_t tmp;
739
0
      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
0
      (void)read16(d, &pos, len, 0);
743
0
      tmp = read32(d, &pos, len, 0);
744
0
      if (tmp != 0x66697845) /* Exif */
745
0
        break; /* Not exif - nothing to rewrite. */
746
0
      tmp = read16(d, &pos, len, 0);
747
0
      if (tmp != 0) /* Terminator + Pad */
748
0
        break; /* Not exif - nothing to rewrite. */
749
      /* Now we're at the APP1 Body. */
750
0
      body_start = pos;
751
0
      tmp = read16(d, &pos, len, 0);
752
0
      if (tmp == 0x4949)
753
0
        order = 0; /* LE */
754
0
      else if (tmp == 0x4d4d)
755
0
        order = 1; /* BE */
756
0
      else
757
0
        break; /* Bad TIFF type. Bale. */
758
0
      tmp = read16(d, &pos, len, order);
759
0
      if (tmp != 0x002a) /* 42 */
760
0
        break; /* Bad version field.  Bale. */
761
0
      do
762
0
      {
763
0
        uint32_t i, n;
764
0
        tmp = read32(d, &pos, len, order);
765
0
        pos = body_start + tmp;
766
0
        if (tmp == 0 || pos >= len)
767
0
          break;
768
0
        n = read16(d, &pos, len, order);
769
0
        for (i = 0; i < n; i++)
770
0
        {
771
0
          if (read16(d, &pos, len, order) == 0x112)
772
0
          {
773
            /* Orientation tag! */
774
0
            write16(d, &pos, len, order, 3); /* 3 = short */
775
0
            write32(d, &pos, len, order, 1); /* Count = 1 */
776
0
            write16(d, &pos, len, order, 1); /* Value = 1 */
777
0
            write16(d, &pos, len, order, 0); /* padding */
778
0
            i = n;
779
0
            pos = len; /* Done! */
780
0
          }
781
0
          else
782
0
            pos += 10;
783
0
        }
784
0
      }
785
0
      while (pos+4 < len);
786
0
      break;
787
0
    }
788
0
    else if (m >= 0xD0 && m <= 0xD7)
789
0
    {
790
      /* RSTm - no length code. But we shouldn't hit this! */
791
0
    }
792
0
    else if (m == 0x01)
793
0
    {
794
      /* TEM - temporary private use in arithmetic coding - shouldn't hit this either. */
795
0
    }
796
0
    else if (m == 0xD8)
797
0
    {
798
      /* SOI - start of image. */
799
0
    }
800
0
    else if (m == 0x01)
801
0
    {
802
      /* EOI - end of image. */
803
0
    }
804
0
    else
805
0
    {
806
      /* All other markers have a length. */
807
0
      size_t marker_len = d[pos]*256 + d[pos+1];
808
0
      pos += marker_len; /* The 2 length bytes are included in the marker_len */
809
0
    }
810
0
  }
811
812
0
  return out;
813
0
}
814
815
void
816
fz_append_image_as_data_uri(fz_context *ctx, fz_buffer *out, fz_image *image)
817
0
{
818
0
  fz_compressed_buffer *cbuf;
819
0
  fz_buffer *buf;
820
821
0
  cbuf = fz_compressed_image_buffer(ctx, image);
822
823
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG)
824
0
  {
825
0
    int type = fz_colorspace_type(ctx, image->colorspace);
826
0
    if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB)
827
0
    {
828
0
      fz_buffer *new_buf = fz_sanitize_jpeg_buffer(ctx, cbuf->buffer);
829
0
      fz_append_string(ctx, out, "data:image/jpeg;base64,");
830
0
      fz_try(ctx)
831
0
        fz_append_base64_buffer(ctx, out, new_buf, 1);
832
0
      fz_always(ctx)
833
0
        fz_drop_buffer(ctx, new_buf);
834
0
      fz_catch(ctx)
835
0
        fz_rethrow(ctx);
836
0
      return;
837
0
    }
838
0
  }
839
0
  if (cbuf && cbuf->params.type == FZ_IMAGE_PNG)
840
0
  {
841
0
    fz_append_string(ctx, out, "data:image/png;base64,");
842
0
    fz_append_base64_buffer(ctx, out, cbuf->buffer, 1);
843
0
    return;
844
0
  }
845
846
0
  buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);
847
0
  fz_try(ctx)
848
0
  {
849
0
    fz_append_string(ctx, out, "data:image/png;base64,");
850
0
    fz_append_base64_buffer(ctx, out, buf, 1);
851
0
  }
852
0
  fz_always(ctx)
853
0
    fz_drop_buffer(ctx, buf);
854
0
  fz_catch(ctx)
855
0
    fz_rethrow(ctx);
856
0
}
857
858
void
859
fz_write_pixmap_as_data_uri(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
860
0
{
861
0
  fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params);
862
0
  fz_try(ctx)
863
0
  {
864
0
    fz_write_string(ctx, out, "data:image/png;base64,");
865
0
    fz_write_base64_buffer(ctx, out, buf, 1);
866
0
  }
867
0
  fz_always(ctx)
868
0
    fz_drop_buffer(ctx, buf);
869
0
  fz_catch(ctx)
870
0
    fz_rethrow(ctx);
871
0
}
872
873
void
874
fz_append_pixmap_as_data_uri(fz_context *ctx, fz_buffer *out, fz_pixmap *pixmap)
875
0
{
876
0
  fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params);
877
0
  fz_try(ctx)
878
0
  {
879
0
    fz_append_string(ctx, out, "data:image/png;base64,");
880
0
    fz_append_base64_buffer(ctx, out, buf, 1);
881
0
  }
882
0
  fz_always(ctx)
883
0
    fz_drop_buffer(ctx, buf);
884
0
  fz_catch(ctx)
885
0
    fz_rethrow(ctx);
886
0
}
887
888
fz_document *
889
fz_new_xhtml_document_from_document(fz_context *ctx, fz_document *old_doc, const fz_stext_options *opts)
890
0
{
891
0
  fz_stext_options default_opts = { FZ_STEXT_PRESERVE_IMAGES | FZ_STEXT_DEHYPHENATE };
892
0
  fz_document *new_doc;
893
0
  fz_buffer *buf = NULL;
894
0
  fz_output *out = NULL;
895
0
  fz_stream *stm = NULL;
896
0
  fz_stext_page *text = NULL;
897
0
  int i;
898
899
0
  fz_var(buf);
900
0
  fz_var(out);
901
0
  fz_var(stm);
902
0
  fz_var(text);
903
904
0
  if (!opts)
905
0
    opts = &default_opts;
906
907
0
  fz_try(ctx)
908
0
  {
909
0
    buf = fz_new_buffer(ctx, 8192);
910
0
    out = fz_new_output_with_buffer(ctx, buf);
911
0
    fz_print_stext_header_as_xhtml(ctx, out);
912
913
0
    for (i = 0; i < fz_count_pages(ctx, old_doc); ++i)
914
0
    {
915
0
      text = fz_new_stext_page_from_page_number(ctx, old_doc, i, opts);
916
0
      fz_print_stext_page_as_xhtml(ctx, out, text, i+1);
917
0
      fz_drop_stext_page(ctx, text);
918
0
      text = NULL;
919
0
    }
920
921
0
    fz_print_stext_trailer_as_xhtml(ctx, out);
922
0
    fz_close_output(ctx, out);
923
0
    fz_terminate_buffer(ctx, buf);
924
925
0
    stm = fz_open_buffer(ctx, buf);
926
0
    new_doc = fz_open_document_with_stream(ctx, "application/xhtml+xml", stm);
927
0
  }
928
0
  fz_always(ctx)
929
0
  {
930
0
    fz_drop_stream(ctx, stm);
931
0
    fz_drop_buffer(ctx, buf);
932
0
    fz_drop_output(ctx, out);
933
0
    fz_drop_stext_page(ctx, text);
934
0
  }
935
0
  fz_catch(ctx)
936
0
    fz_rethrow(ctx);
937
938
0
  return new_doc;
939
0
}
940
941
fz_buffer *
942
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)
943
0
{
944
0
  fz_buffer *buf = NULL;
945
0
  fz_output *out;
946
0
  fz_document_writer *writer = NULL;
947
0
  fz_device *dev = NULL;
948
949
0
  fz_var(buf);
950
0
  fz_var(writer);
951
0
  fz_var(dev);
952
953
0
  fz_try(ctx)
954
0
  {
955
0
    buf = fz_new_buffer(ctx, 0);
956
0
    out = fz_new_output_with_buffer(ctx, buf);
957
0
    writer = fz_new_document_writer_with_output(ctx, out, format, options);
958
0
    dev = fz_begin_page(ctx, writer, fz_bound_page(ctx, page));
959
0
    fz_run_page(ctx, page, dev, transform, cookie);
960
0
    fz_end_page(ctx, writer);
961
0
    fz_close_document_writer(ctx, writer);
962
0
  }
963
0
  fz_always(ctx)
964
0
    fz_drop_document_writer(ctx, writer);
965
0
  fz_catch(ctx)
966
0
  {
967
0
    fz_drop_buffer(ctx, buf);
968
0
    fz_rethrow(ctx);
969
0
  }
970
0
  return buf;
971
0
}