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