Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/pdf.h"
2
3
int
4
pdf_count_pages(fz_context *ctx, pdf_document *doc)
5
{
6
if (doc->page_count == 0)
7
{
8
pdf_obj *count = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/Pages/Count");
9
doc->page_count = pdf_to_int(ctx, count);
10
}
11
return doc->page_count;
12
}
13
14
enum
15
{
16
LOCAL_STACK_SIZE = 16
17
};
18
19
static pdf_obj *
20
pdf_lookup_page_loc_imp(fz_context *ctx, pdf_document *doc, pdf_obj *node, int *skip, pdf_obj **parentp, int *indexp)
21
{
22
pdf_obj *kids;
23
pdf_obj *hit = NULL;
24
int i, len;
25
pdf_obj *local_stack[LOCAL_STACK_SIZE];
26
pdf_obj **stack = &local_stack[0];
27
int stack_max = LOCAL_STACK_SIZE;
28
int stack_len = 0;
29
30
fz_var(hit);
31
fz_var(stack);
32
fz_var(stack_len);
33
fz_var(stack_max);
34
35
fz_try(ctx)
36
{
37
do
38
{
39
kids = pdf_dict_get(ctx, node, PDF_NAME_Kids);
40
len = pdf_array_len(ctx, kids);
41
42
if (len == 0)
43
fz_throw(ctx, FZ_ERROR_GENERIC, "Malformed pages tree");
44
45
/* Every node we need to unmark goes into the stack */
46
if (stack_len == stack_max)
47
{
48
if (stack == &local_stack[0])
49
{
50
stack = fz_malloc_array(ctx, stack_max * 2, sizeof(*stack));
51
memcpy(stack, &local_stack[0], stack_max * sizeof(*stack));
52
}
53
else
54
stack = fz_resize_array(ctx, stack, stack_max * 2, sizeof(*stack));
55
stack_max *= 2;
56
}
57
stack[stack_len++] = node;
58
59
if (pdf_mark_obj(ctx, node))
60
fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in page tree");
61
62
for (i = 0; i < len; i++)
63
{
64
pdf_obj *kid = pdf_array_get(ctx, kids, i);
65
pdf_obj *type = pdf_dict_get(ctx, kid, PDF_NAME_Type);
66
if (type ? pdf_name_eq(ctx, type, PDF_NAME_Pages) : pdf_dict_get(ctx, kid, PDF_NAME_Kids) && !pdf_dict_get(ctx, kid, PDF_NAME_MediaBox))
67
{
68
int count = pdf_to_int(ctx, pdf_dict_get(ctx, kid, PDF_NAME_Count));
69
if (*skip < count)
70
{
71
node = kid;
72
break;
73
}
74
else
75
{
76
*skip -= count;
77
}
78
}
79
else
80
{
81
if (type ? !pdf_name_eq(ctx, type, PDF_NAME_Page) != 0 : !pdf_dict_get(ctx, kid, PDF_NAME_MediaBox))
82
fz_warn(ctx, "non-page object in page tree (%s)", pdf_to_name(ctx, type));
83
if (*skip == 0)
84
{
85
if (parentp) *parentp = node;
86
if (indexp) *indexp = i;
87
hit = kid;
88
break;
89
}
90
else
91
{
92
(*skip)--;
93
}
94
}
95
}
96
}
97
while (hit == NULL);
98
}
99
fz_always(ctx)
100
{
101
for (i = stack_len; i > 0; i--)
102
pdf_unmark_obj(ctx, stack[i-1]);
103
if (stack != &local_stack[0])
104
fz_free(ctx, stack);
105
}
106
fz_catch(ctx)
107
{
108
fz_rethrow(ctx);
109
}
110
111
return hit;
112
}
113
114
pdf_obj *
115
pdf_lookup_page_loc(fz_context *ctx, pdf_document *doc, int needle, pdf_obj **parentp, int *indexp)
116
{
117
pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root);
118
pdf_obj *node = pdf_dict_get(ctx, root, PDF_NAME_Pages);
119
int skip = needle;
120
pdf_obj *hit;
121
122
if (!node)
123
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find page tree");
124
125
hit = pdf_lookup_page_loc_imp(ctx, doc, node, &skip, parentp, indexp);
126
if (!hit)
127
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find page %d in page tree", needle);
128
return hit;
129
}
130
131
pdf_obj *
132
pdf_lookup_page_obj(fz_context *ctx, pdf_document *doc, int needle)
133
{
134
return pdf_lookup_page_loc(ctx, doc, needle, NULL, NULL);
135
}
136
137
static int
138
pdf_count_pages_before_kid(fz_context *ctx, pdf_document *doc, pdf_obj *parent, int kid_num)
139
{
140
pdf_obj *kids = pdf_dict_get(ctx, parent, PDF_NAME_Kids);
141
int i, total = 0, len = pdf_array_len(ctx, kids);
142
for (i = 0; i < len; i++)
143
{
144
pdf_obj *kid = pdf_array_get(ctx, kids, i);
145
if (pdf_to_num(ctx, kid) == kid_num)
146
return total;
147
if (pdf_name_eq(ctx, pdf_dict_get(ctx, kid, PDF_NAME_Type), PDF_NAME_Pages))
148
{
149
pdf_obj *count = pdf_dict_get(ctx, kid, PDF_NAME_Count);
150
int n = pdf_to_int(ctx, count);
151
if (!pdf_is_int(ctx, count) || n < 0)
152
fz_throw(ctx, FZ_ERROR_GENERIC, "illegal or missing count in pages tree");
153
total += n;
154
}
155
else
156
total++;
157
}
158
fz_throw(ctx, FZ_ERROR_GENERIC, "kid not found in parent's kids array");
159
}
160
161
int
162
pdf_lookup_page_number(fz_context *ctx, pdf_document *doc, pdf_obj *node)
163
{
164
int needle = pdf_to_num(ctx, node);
165
int total = 0;
166
pdf_obj *parent, *parent2;
167
168
if (!pdf_name_eq(ctx, pdf_dict_get(ctx, node, PDF_NAME_Type), PDF_NAME_Page) != 0)
169
fz_throw(ctx, FZ_ERROR_GENERIC, "invalid page object");
170
171
parent2 = parent = pdf_dict_get(ctx, node, PDF_NAME_Parent);
172
fz_var(parent);
173
fz_try(ctx)
174
{
175
while (pdf_is_dict(ctx, parent))
176
{
177
if (pdf_mark_obj(ctx, parent))
178
fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in page tree (parents)");
179
total += pdf_count_pages_before_kid(ctx, doc, parent, needle);
180
needle = pdf_to_num(ctx, parent);
181
parent = pdf_dict_get(ctx, parent, PDF_NAME_Parent);
182
}
183
}
184
fz_always(ctx)
185
{
186
/* Run back and unmark */
187
while (parent2)
188
{
189
pdf_unmark_obj(ctx, parent2);
190
if (parent2 == parent)
191
break;
192
parent2 = pdf_dict_get(ctx, parent2, PDF_NAME_Parent);
193
}
194
}
195
fz_catch(ctx)
196
{
197
fz_rethrow(ctx);
198
}
199
200
return total;
201
}
202
203
static pdf_obj *
204
pdf_lookup_inherited_page_item(fz_context *ctx, pdf_document *doc, pdf_obj *node, pdf_obj *key)
205
{
206
pdf_obj *node2 = node;
207
pdf_obj *val;
208
209
/* fz_var(node); Not required as node passed in */
210
211
fz_try(ctx)
212
{
213
do
214
{
215
val = pdf_dict_get(ctx, node, key);
216
if (val)
217
break;
218
if (pdf_mark_obj(ctx, node))
219
fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in page tree (parents)");
220
node = pdf_dict_get(ctx, node, PDF_NAME_Parent);
221
}
222
while (node);
223
}
224
fz_always(ctx)
225
{
226
do
227
{
228
pdf_unmark_obj(ctx, node2);
229
if (node2 == node)
230
break;
231
node2 = pdf_dict_get(ctx, node2, PDF_NAME_Parent);
232
}
233
while (node2);
234
}
235
fz_catch(ctx)
236
{
237
fz_rethrow(ctx);
238
}
239
240
return val;
241
}
242
243
/* We need to know whether to install a page-level transparency group */
244
245
static int pdf_resources_use_blending(fz_context *ctx, pdf_document *doc, pdf_obj *rdb);
246
247
static int
248
pdf_extgstate_uses_blending(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
249
{
250
pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME_BM);
251
if (obj && !pdf_name_eq(ctx, obj, PDF_NAME_Normal))
252
return 1;
253
return 0;
254
}
255
256
static int
257
pdf_pattern_uses_blending(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
258
{
259
pdf_obj *obj;
260
obj = pdf_dict_get(ctx, dict, PDF_NAME_Resources);
261
if (pdf_resources_use_blending(ctx, doc, obj))
262
return 1;
263
obj = pdf_dict_get(ctx, dict, PDF_NAME_ExtGState);
264
return pdf_extgstate_uses_blending(ctx, doc, obj);
265
}
266
267
static int
268
pdf_xobject_uses_blending(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
269
{
270
pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME_Resources);
271
if (pdf_name_eq(ctx, pdf_dict_getp(ctx, dict, "Group/S"), PDF_NAME_Transparency))
272
return 1;
273
return pdf_resources_use_blending(ctx, doc, obj);
274
}
275
276
static int
277
pdf_resources_use_blending(fz_context *ctx, pdf_document *doc, pdf_obj *rdb)
278
{
279
pdf_obj *obj;
280
int i, n, useBM = 0;
281
282
if (!rdb)
283
return 0;
284
285
/* Have we been here before and remembered an answer? */
286
if (pdf_obj_memo(ctx, rdb, &useBM))
287
return useBM;
288
289
/* stop on cyclic resource dependencies */
290
if (pdf_mark_obj(ctx, rdb))
291
return 0;
292
293
fz_try(ctx)
294
{
295
obj = pdf_dict_get(ctx, rdb, PDF_NAME_ExtGState);
296
n = pdf_dict_len(ctx, obj);
297
for (i = 0; i < n; i++)
298
if (pdf_extgstate_uses_blending(ctx, doc, pdf_dict_get_val(ctx, obj, i)))
299
goto found;
300
301
obj = pdf_dict_get(ctx, rdb, PDF_NAME_Pattern);
302
n = pdf_dict_len(ctx, obj);
303
for (i = 0; i < n; i++)
304
if (pdf_pattern_uses_blending(ctx, doc, pdf_dict_get_val(ctx, obj, i)))
305
goto found;
306
307
obj = pdf_dict_get(ctx, rdb, PDF_NAME_XObject);
308
n = pdf_dict_len(ctx, obj);
309
for (i = 0; i < n; i++)
310
if (pdf_xobject_uses_blending(ctx, doc, pdf_dict_get_val(ctx, obj, i)))
311
goto found;
312
if (0)
313
{
314
found:
315
useBM = 1;
316
}
317
}
318
fz_always(ctx)
319
{
320
pdf_unmark_obj(ctx, rdb);
321
}
322
fz_catch(ctx)
323
{
324
fz_rethrow(ctx);
325
}
326
327
pdf_set_obj_memo(ctx, rdb, useBM);
328
return useBM;
329
}
330
331
static void
332
pdf_load_transition(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_obj *transdict)
333
{
334
pdf_obj *name;
335
pdf_obj *obj;
336
int type;
337
338
obj = pdf_dict_get(ctx, transdict, PDF_NAME_D);
339
page->transition.duration = (obj ? pdf_to_real(ctx, obj) : 1);
340
341
page->transition.vertical = !pdf_name_eq(ctx, pdf_dict_get(ctx, transdict, PDF_NAME_Dm), PDF_NAME_H);
342
page->transition.outwards = !pdf_name_eq(ctx, pdf_dict_get(ctx, transdict, PDF_NAME_M), PDF_NAME_I);
343
/* FIXME: If 'Di' is None, it should be handled differently, but
344
* this only affects Fly, and we don't implement that currently. */
345
page->transition.direction = (pdf_to_int(ctx, pdf_dict_get(ctx, transdict, PDF_NAME_Di)));
346
/* FIXME: Read SS for Fly when we implement it */
347
/* FIXME: Read B for Fly when we implement it */
348
349
name = pdf_dict_get(ctx, transdict, PDF_NAME_S);
350
if (pdf_name_eq(ctx, name, PDF_NAME_Split))
351
type = FZ_TRANSITION_SPLIT;
352
else if (pdf_name_eq(ctx, name, PDF_NAME_Blinds))
353
type = FZ_TRANSITION_BLINDS;
354
else if (pdf_name_eq(ctx, name, PDF_NAME_Box))
355
type = FZ_TRANSITION_BOX;
356
else if (pdf_name_eq(ctx, name, PDF_NAME_Wipe))
357
type = FZ_TRANSITION_WIPE;
358
else if (pdf_name_eq(ctx, name, PDF_NAME_Dissolve))
359
type = FZ_TRANSITION_DISSOLVE;
360
else if (pdf_name_eq(ctx, name, PDF_NAME_Glitter))
361
type = FZ_TRANSITION_GLITTER;
362
else if (pdf_name_eq(ctx, name, PDF_NAME_Fly))
363
type = FZ_TRANSITION_FLY;
364
else if (pdf_name_eq(ctx, name, PDF_NAME_Push))
365
type = FZ_TRANSITION_PUSH;
366
else if (pdf_name_eq(ctx, name, PDF_NAME_Cover))
367
type = FZ_TRANSITION_COVER;
368
else if (pdf_name_eq(ctx, name, PDF_NAME_Uncover))
369
type = FZ_TRANSITION_UNCOVER;
370
else if (pdf_name_eq(ctx, name, PDF_NAME_Fade))
371
type = FZ_TRANSITION_FADE;
372
else
373
type = FZ_TRANSITION_NONE;
374
page->transition.type = type;
375
}
376
377
fz_rect *
378
pdf_bound_page(fz_context *ctx, pdf_page *page, fz_rect *bounds)
379
{
380
fz_matrix mtx;
381
fz_rect mediabox = page->mediabox;
382
fz_transform_rect(&mediabox, fz_rotate(&mtx, page->rotate));
383
bounds->x0 = bounds->y0 = 0;
384
bounds->x1 = mediabox.x1 - mediabox.x0;
385
bounds->y1 = mediabox.y1 - mediabox.y0;
386
return bounds;
387
}
388
389
fz_link *
390
pdf_load_links(fz_context *ctx, pdf_page *page)
391
{
392
return fz_keep_link(ctx, page->links);
393
}
394
395
static void
396
pdf_drop_page_imp(fz_context *ctx, pdf_page *page)
397
{
398
pdf_document *doc = page->doc;
399
400
if (page == NULL)
401
return;
402
403
pdf_drop_obj(ctx, page->resources);
404
pdf_drop_obj(ctx, page->contents);
405
if (page->links)
406
fz_drop_link(ctx, page->links);
407
if (page->annots)
408
pdf_drop_annot(ctx, page->annots);
409
if (page->deleted_annots)
410
pdf_drop_annot(ctx, page->deleted_annots);
411
if (page->tmp_annots)
412
pdf_drop_annot(ctx, page->tmp_annots);
413
/* doc->focus, when not NULL, refers to one of
414
* the annotations and must be NULLed when the
415
* annotations are destroyed. doc->focus_obj
416
* keeps track of the actual annotation object. */
417
doc->focus = NULL;
418
pdf_drop_obj(ctx, page->me);
419
420
fz_drop_document(ctx, &page->doc->super);
421
}
422
423
void pdf_drop_page(fz_context *ctx, pdf_page *page)
424
{
425
fz_drop_page(ctx, &page->super);
426
}
427
428
static pdf_page *
429
pdf_new_page(fz_context *ctx, pdf_document *doc)
430
{
431
pdf_page *page = fz_new_page(ctx, sizeof(*page));
432
433
page->doc = (pdf_document*) fz_keep_document(ctx, &doc->super);
434
435
page->super.drop_page_imp = (fz_page_drop_page_imp_fn *)pdf_drop_page_imp;
436
page->super.load_links = (fz_page_load_links_fn *)pdf_load_links;
437
page->super.bound_page = (fz_page_bound_page_fn *)pdf_bound_page;
438
page->super.first_annot = (fz_page_first_annot_fn *)pdf_first_annot;
439
page->super.next_annot = (fz_page_next_annot_fn *)pdf_next_annot;
440
page->super.bound_annot = (fz_page_bound_annot_fn *)pdf_bound_annot;
441
page->super.run_page_contents = (fz_page_run_page_contents_fn *)pdf_run_page_contents;
442
page->super.run_annot = (fz_page_run_annot_fn *)pdf_run_annot;
443
page->super.page_presentation = (fz_page_page_presentation_fn *)pdf_page_presentation;
444
445
page->resources = NULL;
446
page->contents = NULL;
447
page->transparency = 0;
448
page->links = NULL;
449
page->annots = NULL;
450
page->annot_tailp = &page->annots;
451
page->deleted_annots = NULL;
452
page->tmp_annots = NULL;
453
page->incomplete = 0;
454
page->me = NULL;
455
456
return page;
457
}
458
459
pdf_page *
460
pdf_load_page(fz_context *ctx, pdf_document *doc, int number)
461
{
462
pdf_page *page;
463
pdf_annot *annot;
464
pdf_obj *pageobj, *pageref, *obj;
465
fz_rect mediabox, cropbox, realbox;
466
float userunit;
467
fz_matrix mat;
468
469
if (doc->file_reading_linearly)
470
{
471
pageref = pdf_progressive_advance(ctx, doc, number);
472
if (pageref == NULL)
473
fz_throw(ctx, FZ_ERROR_TRYLATER, "page %d not available yet", number);
474
}
475
else
476
pageref = pdf_lookup_page_obj(ctx, doc, number);
477
pageobj = pdf_resolve_indirect(ctx, pageref);
478
479
page = pdf_new_page(ctx, doc);
480
page->me = pdf_keep_obj(ctx, pageobj);
481
482
obj = pdf_dict_get(ctx, pageobj, PDF_NAME_UserUnit);
483
if (pdf_is_real(ctx, obj))
484
userunit = pdf_to_real(ctx, obj);
485
else
486
userunit = 1;
487
488
pdf_to_rect(ctx, pdf_lookup_inherited_page_item(ctx, doc, pageobj, PDF_NAME_MediaBox), &mediabox);
489
if (fz_is_empty_rect(&mediabox))
490
{
491
fz_warn(ctx, "cannot find page size for page %d", number + 1);
492
mediabox.x0 = 0;
493
mediabox.y0 = 0;
494
mediabox.x1 = 612;
495
mediabox.y1 = 792;
496
}
497
498
pdf_to_rect(ctx, pdf_lookup_inherited_page_item(ctx, doc, pageobj, PDF_NAME_CropBox), &cropbox);
499
if (!fz_is_empty_rect(&cropbox))
500
fz_intersect_rect(&mediabox, &cropbox);
501
502
page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit;
503
page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit;
504
page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit;
505
page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit;
506
507
if (page->mediabox.x1 - page->mediabox.x0 < 1 || page->mediabox.y1 - page->mediabox.y0 < 1)
508
{
509
fz_warn(ctx, "invalid page size in page %d", number + 1);
510
page->mediabox = fz_unit_rect;
511
}
512
513
page->rotate = pdf_to_int(ctx, pdf_lookup_inherited_page_item(ctx, doc, pageobj, PDF_NAME_Rotate));
514
/* Snap page->rotate to 0, 90, 180 or 270 */
515
if (page->rotate < 0)
516
page->rotate = 360 - ((-page->rotate) % 360);
517
if (page->rotate >= 360)
518
page->rotate = page->rotate % 360;
519
page->rotate = 90*((page->rotate + 45)/90);
520
if (page->rotate > 360)
521
page->rotate = 0;
522
523
fz_pre_rotate(fz_scale(&page->ctm, 1, -1), -page->rotate);
524
realbox = page->mediabox;
525
fz_transform_rect(&realbox, &page->ctm);
526
fz_pre_scale(fz_translate(&mat, -realbox.x0, -realbox.y0), userunit, userunit);
527
fz_concat(&page->ctm, &page->ctm, &mat);
528
529
fz_try(ctx)
530
{
531
obj = pdf_dict_get(ctx, pageobj, PDF_NAME_Annots);
532
if (obj)
533
{
534
page->links = pdf_load_link_annots(ctx, doc, obj, &page->ctm);
535
pdf_load_annots(ctx, doc, page, obj);
536
}
537
}
538
fz_catch(ctx)
539
{
540
if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
541
fz_rethrow(ctx);
542
page->incomplete |= PDF_PAGE_INCOMPLETE_ANNOTS;
543
fz_drop_link(ctx, page->links);
544
page->links = NULL;
545
}
546
547
page->duration = pdf_to_real(ctx, pdf_dict_get(ctx, pageobj, PDF_NAME_Dur));
548
549
obj = pdf_dict_get(ctx, pageobj, PDF_NAME_Trans);
550
page->transition_present = (obj != NULL);
551
if (obj)
552
{
553
pdf_load_transition(ctx, doc, page, obj);
554
}
555
556
// TODO: inherit
557
page->resources = pdf_lookup_inherited_page_item(ctx, doc, pageobj, PDF_NAME_Resources);
558
if (page->resources)
559
pdf_keep_obj(ctx, page->resources);
560
561
obj = pdf_dict_get(ctx, pageobj, PDF_NAME_Contents);
562
fz_try(ctx)
563
{
564
page->contents = pdf_keep_obj(ctx, obj);
565
566
if (pdf_resources_use_blending(ctx, doc, page->resources))
567
page->transparency = 1;
568
else if (pdf_name_eq(ctx, pdf_dict_getp(ctx, pageobj, "Group/S"), PDF_NAME_Transparency))
569
page->transparency = 1;
570
571
for (annot = page->annots; annot && !page->transparency; annot = annot->next)
572
if (annot->ap && pdf_resources_use_blending(ctx, doc, annot->ap->resources))
573
page->transparency = 1;
574
}
575
fz_catch(ctx)
576
{
577
if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
578
{
579
fz_drop_page(ctx, &page->super);
580
fz_rethrow_message(ctx, "cannot load page %d contents (%d 0 R)", number + 1, pdf_to_num(ctx, pageref));
581
}
582
page->incomplete |= PDF_PAGE_INCOMPLETE_CONTENTS;
583
}
584
585
return page;
586
}
587
588
void
589
pdf_delete_page(fz_context *ctx, pdf_document *doc, int at)
590
{
591
pdf_obj *parent, *kids;
592
int i;
593
594
pdf_lookup_page_loc(ctx, doc, at, &parent, &i);
595
kids = pdf_dict_get(ctx, parent, PDF_NAME_Kids);
596
pdf_array_delete(ctx, kids, i);
597
598
while (parent)
599
{
600
int count = pdf_to_int(ctx, pdf_dict_get(ctx, parent, PDF_NAME_Count));
601
pdf_dict_put_drop(ctx, parent, PDF_NAME_Count, pdf_new_int(ctx, doc, count - 1));
602
parent = pdf_dict_get(ctx, parent, PDF_NAME_Parent);
603
}
604
605
doc->page_count = 0; /* invalidate cached value */
606
}
607
608
void
609
pdf_insert_page(fz_context *ctx, pdf_document *doc, pdf_page *page, int at)
610
{
611
int count = pdf_count_pages(ctx, doc);
612
pdf_obj *parent, *kids;
613
pdf_obj *page_ref;
614
int i;
615
616
page_ref = pdf_new_ref(ctx, doc, page->me);
617
618
fz_try(ctx)
619
{
620
if (count == 0)
621
{
622
pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root);
623
parent = pdf_dict_get(ctx, root, PDF_NAME_Pages);
624
if (!parent)
625
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find page tree");
626
627
kids = pdf_dict_get(ctx, parent, PDF_NAME_Kids);
628
if (!kids)
629
fz_throw(ctx, FZ_ERROR_GENERIC, "malformed page tree");
630
631
pdf_array_insert(ctx, kids, page_ref, 0);
632
}
633
else if (at >= count)
634
{
635
if (at == INT_MAX)
636
at = count;
637
638
if (at > count)
639
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot insert page beyond end of page tree");
640
641
/* append after last page */
642
pdf_lookup_page_loc(ctx, doc, count - 1, &parent, &i);
643
kids = pdf_dict_get(ctx, parent, PDF_NAME_Kids);
644
pdf_array_insert(ctx, kids, page_ref, i + 1);
645
}
646
else
647
{
648
/* insert before found page */
649
pdf_lookup_page_loc(ctx, doc, at, &parent, &i);
650
kids = pdf_dict_get(ctx, parent, PDF_NAME_Kids);
651
pdf_array_insert(ctx, kids, page_ref, i);
652
}
653
654
pdf_dict_put(ctx, page->me, PDF_NAME_Parent, parent);
655
656
/* Adjust page counts */
657
while (parent)
658
{
659
int count = pdf_to_int(ctx, pdf_dict_get(ctx, parent, PDF_NAME_Count));
660
pdf_dict_put_drop(ctx, parent, PDF_NAME_Count, pdf_new_int(ctx, doc, count + 1));
661
parent = pdf_dict_get(ctx, parent, PDF_NAME_Parent);
662
}
663
664
}
665
fz_always(ctx)
666
{
667
pdf_drop_obj(ctx, page_ref);
668
}
669
fz_catch(ctx)
670
{
671
fz_rethrow(ctx);
672
}
673
674
doc->page_count = 0; /* invalidate cached value */
675
}
676
677
void
678
pdf_delete_page_range(fz_context *ctx, pdf_document *doc, int start, int end)
679
{
680
while (start < end)
681
pdf_delete_page(ctx, doc, start++);
682
}
683
684
pdf_page *
685
pdf_create_page(fz_context *ctx, pdf_document *doc, fz_rect mediabox, int res, int rotate)
686
{
687
pdf_page *page = NULL;
688
pdf_obj *pageobj;
689
float userunit = 1;
690
fz_matrix ctm, tmp;
691
fz_rect realbox;
692
693
page = pdf_new_page(ctx, doc);
694
695
fz_try(ctx)
696
{
697
page->me = pageobj = pdf_new_dict(ctx, doc, 4);
698
699
pdf_dict_put_drop(ctx, pageobj, PDF_NAME_Type, PDF_NAME_Page);
700
701
page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit;
702
page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit;
703
page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit;
704
page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit;
705
pdf_dict_put_drop(ctx, pageobj, PDF_NAME_MediaBox, pdf_new_rect(ctx, doc, &page->mediabox));
706
707
/* Snap page->rotate to 0, 90, 180 or 270 */
708
if (page->rotate < 0)
709
page->rotate = 360 - ((-page->rotate) % 360);
710
if (page->rotate >= 360)
711
page->rotate = page->rotate % 360;
712
page->rotate = 90*((page->rotate + 45)/90);
713
if (page->rotate > 360)
714
page->rotate = 0;
715
pdf_dict_put_drop(ctx, pageobj, PDF_NAME_Rotate, pdf_new_int(ctx, doc, page->rotate));
716
717
fz_pre_rotate(fz_scale(&ctm, 1, -1), -page->rotate);
718
realbox = page->mediabox;
719
fz_transform_rect(&realbox, &ctm);
720
fz_pre_scale(fz_translate(&tmp, -realbox.x0, -realbox.y0), userunit, userunit);
721
fz_concat(&ctm, &ctm, &tmp);
722
page->ctm = ctm;
723
/* Do not create a Contents, as an empty Contents dict is not
724
* valid. See Bug 694712 */
725
}
726
fz_catch(ctx)
727
{
728
pdf_drop_obj(ctx, page->me);
729
fz_free(ctx, page);
730
fz_rethrow_message(ctx, "Failed to create page");
731
}
732
733
return page;
734
}
735
736