1
/* $Header: /home/cvsroot/dvipdfmx/src/pdfdoc.c,v 1.76 2011/03/06 03:14:14 chofchof Exp $
3
This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5
Copyright (C) 2008 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata,
6
the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
8
Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
* TODO: Many things...
27
* {begin,end}_{bead,article}, box stack, name tree (not limited to dests)...
46
#include "pdfencrypt.h"
52
#include "pdfresource.h"
54
#include "pdfximage.h"
56
#include "pdflimits.h"
61
#include "jpegimage.h"
65
#define PDFDOC_PAGES_ALLOC_SIZE 128u
66
#define PDFDOC_ARTICLE_ALLOC_SIZE 16
67
#define PDFDOC_BEAD_ALLOC_SIZE 16
69
static int verbose = 0;
71
static char manual_thumb_enabled = 0;
72
static char *thumb_basename = NULL;
75
pdf_doc_enable_manual_thumbnails (void)
78
manual_thumb_enabled = 1;
80
WARN("Manual thumbnail is not supported without the libpng library.");
85
read_thumbnail (const char *thumb_filename)
91
fp = MFOPEN(thumb_filename, FOPEN_RBIN_MODE);
93
WARN("Could not open thumbnail file \"%s\"", thumb_filename);
96
if (!check_for_png(fp) && !check_for_jpeg(fp)) {
97
WARN("Thumbnail \"%s\" not a png/jpeg file!", thumb_filename);
103
xobj_id = pdf_ximage_findresource(thumb_filename, 0, NULL);
105
WARN("Could not read thumbnail file \"%s\".", thumb_filename);
108
image_ref = pdf_ximage_get_reference(xobj_id);
115
pdf_doc_set_verbose (void)
118
pdf_font_set_verbose();
119
pdf_color_set_verbose();
120
pdf_ximage_set_verbose();
123
typedef struct pdf_form
134
struct form_list_node
139
struct form_list_node *prev;
142
#define USE_MY_MEDIABOX (1 << 0)
143
typedef struct pdf_page
159
/* global bop, background, contents, global eop */
160
pdf_obj *content_refs[4];
166
typedef struct pdf_olitem
172
struct pdf_olitem *first;
173
struct pdf_olitem *parent;
175
struct pdf_olitem *next;
178
typedef struct pdf_bead
185
typedef struct pdf_article
196
const char *category;
197
struct ht_table *data;
201
typedef struct pdf_doc
219
long num_entries; /* This is not actually total number of pages. */
233
pdf_article *entries;
236
struct name_dict *names;
239
struct ht_table gotos;
242
int outline_open_depth;
246
struct form_list_node *pending_forms;
252
pdf_doc_init_catalog (pdf_doc *p)
254
p->root.viewerpref = NULL;
255
p->root.pagelabels = NULL;
256
p->root.pages = NULL;
257
p->root.names = NULL;
258
p->root.threads = NULL;
260
p->root.dict = pdf_new_dict();
261
pdf_set_root(p->root.dict);
267
pdf_doc_close_catalog (pdf_doc *p)
271
if (p->root.viewerpref) {
272
tmp = pdf_lookup_dict(p->root.dict, "ViewerPreferences");
274
pdf_add_dict(p->root.dict,
275
pdf_new_name("ViewerPreferences"),
276
pdf_ref_obj (p->root.viewerpref));
277
} else if (PDF_OBJ_DICTTYPE(tmp)) {
278
pdf_merge_dict(p->root.viewerpref, tmp);
279
pdf_add_dict(p->root.dict,
280
pdf_new_name("ViewerPreferences"),
281
pdf_ref_obj (p->root.viewerpref));
282
} else { /* Maybe reference */
283
/* What should I do? */
284
WARN("Could not modify ViewerPreferences.");
286
pdf_release_obj(p->root.viewerpref);
287
p->root.viewerpref = NULL;
290
if (p->root.pagelabels) {
291
tmp = pdf_lookup_dict(p->root.dict, "PageLabels");
293
tmp = pdf_new_dict();
294
pdf_add_dict(tmp, pdf_new_name("Nums"), pdf_link_obj(p->root.pagelabels));
295
pdf_add_dict(p->root.dict,
296
pdf_new_name("PageLabels"), pdf_ref_obj(tmp));
297
pdf_release_obj(tmp);
298
} else { /* Maybe reference */
299
/* What should I do? */
300
WARN("Could not modify PageLabels.");
302
pdf_release_obj(p->root.pagelabels);
303
p->root.pagelabels = NULL;
306
pdf_add_dict(p->root.dict,
307
pdf_new_name("Type"), pdf_new_name("Catalog"));
308
pdf_release_obj(p->root.dict);
315
* Pages are starting at 1.
316
* The page count does not increase until the page is finished.
318
#define LASTPAGE(p) (&(p->pages.entries[p->pages.num_entries]))
319
#define FIRSTPAGE(p) (&(p->pages.entries[0]))
320
#define PAGECOUNT(p) (p->pages.num_entries)
321
#define MAXPAGES(p) (p->pages.max_entries)
324
doc_resize_page_entries (pdf_doc *p, long size)
326
if (size > MAXPAGES(p)) {
329
p->pages.entries = RENEW(p->pages.entries, size, struct pdf_page);
330
for (i = p->pages.max_entries; i < size; i++) {
331
p->pages.entries[i].page_obj = NULL;
332
p->pages.entries[i].page_ref = NULL;
333
p->pages.entries[i].flags = 0;
334
p->pages.entries[i].resources = NULL;
335
p->pages.entries[i].background = NULL;
336
p->pages.entries[i].contents = NULL;
337
p->pages.entries[i].content_refs[0] = NULL; /* global bop */
338
p->pages.entries[i].content_refs[1] = NULL; /* background */
339
p->pages.entries[i].content_refs[2] = NULL; /* page body */
340
p->pages.entries[i].content_refs[3] = NULL; /* global eop */
341
p->pages.entries[i].annots = NULL;
342
p->pages.entries[i].beads = NULL;
344
p->pages.max_entries = size;
351
doc_get_page_entry (pdf_doc *p, unsigned long page_no)
355
if (page_no > 65535ul) {
356
ERROR("Page number %ul too large!", page_no);
357
} else if (page_no == 0) {
358
ERROR("Invalid Page number %ul.", page_no);
361
if (page_no > MAXPAGES(p)) {
362
doc_resize_page_entries(p, page_no + PDFDOC_PAGES_ALLOC_SIZE);
365
page = &(p->pages.entries[page_no - 1]);
370
static void pdf_doc_init_page_tree (pdf_doc *p, double media_width, double media_height);
371
static void pdf_doc_close_page_tree (pdf_doc *p);
373
static void pdf_doc_init_names (pdf_doc *p, int check_gotos);
374
static void pdf_doc_close_names (pdf_doc *p);
376
static void pdf_doc_add_goto (pdf_obj *annot_dict);
378
static void pdf_doc_init_docinfo (pdf_doc *p);
379
static void pdf_doc_close_docinfo (pdf_doc *p);
381
static void pdf_doc_init_articles (pdf_doc *p);
382
static void pdf_doc_close_articles (pdf_doc *p);
383
static void pdf_doc_init_bookmarks (pdf_doc *p, int bm_open_depth);
384
static void pdf_doc_close_bookmarks (pdf_doc *p);
387
pdf_doc_set_bop_content (const char *content, unsigned length)
394
pdf_release_obj(p->pages.bop);
399
p->pages.bop = pdf_new_stream(STREAM_COMPRESS);
400
pdf_add_stream(p->pages.bop, content, length);
409
pdf_doc_set_eop_content (const char *content, unsigned length)
414
pdf_release_obj(p->pages.eop);
419
p->pages.eop = pdf_new_stream(STREAM_COMPRESS);
420
pdf_add_stream(p->pages.eop, content, length);
428
#ifndef HAVE_TM_GMTOFF
429
#ifndef HAVE_TIMEZONE
431
/* auxiliary function to compute timezone offset on
432
systems that do not support the tm_gmtoff in struct tm,
433
or have a timezone variable. Such as i386-solaris. */
436
compute_timezone_offset()
438
const time_t now = time(NULL);
443
localtime_r(&now, &local);
445
return (mktime(&local) - mktime(&tm));
448
#endif /* HAVE_TIMEZONE */
449
#endif /* HAVE_TM_GMTOFF */
455
asn_date (char *date_string)
462
bd_time = localtime(¤t_time);
464
#ifdef HAVE_TM_GMTOFF
465
tz_offset = bd_time->tm_gmtoff;
467
# ifdef HAVE_TIMEZONE
468
tz_offset = -timezone;
470
tz_offset = compute_timezone_offset();
471
# endif /* HAVE_TIMEZONE */
472
#endif /* HAVE_TM_GMTOFF */
474
sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d%c%02ld'%02ld'",
475
bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday,
476
bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec,
477
(tz_offset > 0) ? '+' : '-', labs(tz_offset) / 3600,
478
(labs(tz_offset) / 60) % 60);
480
return strlen(date_string);
484
pdf_doc_init_docinfo (pdf_doc *p)
486
p->info = pdf_new_dict();
487
pdf_set_info(p->info);
493
pdf_doc_close_docinfo (pdf_doc *p)
495
pdf_obj *docinfo = p->info;
498
* Excerpt from PDF Reference 4th ed., sec. 10.2.1.
500
* Any entry whose value is not known should be omitted from the dictionary,
501
* rather than included with an empty string as its value.
505
* Note: Although viewer applications can store custom metadata in the document
506
* information dictionary, it is inappropriate to store private content or
507
* structural information there; such information should be stored in the
508
* document catalog instead (see Section 3.6.1, Document Catalog ).
510
const char *keys[] = {
511
"Title", "Author", "Subject", "Keywords", "Creator", "Producer",
512
"CreationDate", "ModDate", /* Date */
519
for (i = 0; keys[i] != NULL; i++) {
520
value = pdf_lookup_dict(docinfo, keys[i]);
522
if (!PDF_OBJ_STRINGTYPE(value)) {
523
WARN("\"%s\" in DocInfo dictionary not string type.", keys[i]);
524
pdf_remove_dict(docinfo, keys[i]);
525
WARN("\"%s\" removed from DocInfo.", keys[i]);
526
} else if (pdf_string_length(value) == 0) {
527
/* The hyperref package often uses emtpy strings. */
528
pdf_remove_dict(docinfo, keys[i]);
533
banner = NEW(strlen(PACKAGE)+strlen(VERSION)+4, char);
534
sprintf(banner, "%s (%s)", PACKAGE, VERSION);
535
pdf_add_dict(docinfo,
536
pdf_new_name("Producer"),
537
pdf_new_string(banner, strlen(banner)));
540
if (!pdf_lookup_dict(docinfo, "CreationDate")) {
544
pdf_add_dict(docinfo,
545
pdf_new_name ("CreationDate"),
546
pdf_new_string(now, strlen(now)));
549
pdf_release_obj(docinfo);
556
pdf_doc_get_page_resources (pdf_doc *p, const char *category)
559
pdf_page *currentpage;
562
if (!p || !category) {
566
if (p->pending_forms) {
567
if (p->pending_forms->form.resources) {
568
res_dict = p->pending_forms->form.resources;
570
res_dict = p->pending_forms->form.resources = pdf_new_dict();
573
currentpage = LASTPAGE(p);
574
if (currentpage->resources) {
575
res_dict = currentpage->resources;
577
res_dict = currentpage->resources = pdf_new_dict();
580
resources = pdf_lookup_dict(res_dict, category);
582
resources = pdf_new_dict();
583
pdf_add_dict(res_dict, pdf_new_name(category), resources);
590
pdf_doc_add_page_resource (const char *category,
591
const char *resource_name, pdf_obj *resource_ref)
597
if (!PDF_OBJ_INDIRECTTYPE(resource_ref)) {
598
WARN("Passed non indirect reference...");
599
resource_ref = pdf_ref_obj(resource_ref); /* leak */
601
resources = pdf_doc_get_page_resources(p, category);
602
duplicate = pdf_lookup_dict(resources, resource_name);
603
if (duplicate && pdf_compare_reference(duplicate, resource_ref)) {
604
WARN("Conflicting page resource found (page: %ld, category: %s, name: %s).",
605
pdf_doc_current_page_number(), category, resource_name);
607
pdf_release_obj(resource_ref);
609
pdf_add_dict(resources, pdf_new_name(resource_name), resource_ref);
616
doc_flush_page (pdf_doc *p, pdf_page *page, pdf_obj *parent_ref)
618
pdf_obj *contents_array;
621
pdf_add_dict(page->page_obj,
622
pdf_new_name("Type"), pdf_new_name("Page"));
623
pdf_add_dict(page->page_obj,
624
pdf_new_name("Parent"), parent_ref);
627
* Clipping area specified by CropBox is affected by MediaBox which
628
* might be inherit from parent node. If MediaBox of the root node
629
* does not have enough size to cover all page's imaging area, using
630
* CropBox here gives incorrect result.
632
if (page->flags & USE_MY_MEDIABOX) {
635
mediabox = pdf_new_array();
636
pdf_add_array(mediabox,
637
pdf_new_number(ROUND(page->cropbox.llx, 0.01)));
638
pdf_add_array(mediabox,
639
pdf_new_number(ROUND(page->cropbox.lly, 0.01)));
640
pdf_add_array(mediabox,
641
pdf_new_number(ROUND(page->cropbox.urx, 0.01)));
642
pdf_add_array(mediabox,
643
pdf_new_number(ROUND(page->cropbox.ury, 0.01)));
644
pdf_add_dict(page->page_obj, pdf_new_name("MediaBox"), mediabox);
648
contents_array = pdf_new_array();
649
if (page->content_refs[0]) { /* global bop */
650
pdf_add_array(contents_array, page->content_refs[0]);
652
} else if (p->pages.bop &&
653
pdf_stream_length(p->pages.bop) > 0) {
654
pdf_add_array(contents_array, pdf_ref_obj(p->pages.bop));
657
if (page->content_refs[1]) { /* background */
658
pdf_add_array(contents_array, page->content_refs[1]);
661
if (page->content_refs[2]) { /* page body */
662
pdf_add_array(contents_array, page->content_refs[2]);
665
if (page->content_refs[3]) { /* global eop */
666
pdf_add_array(contents_array, page->content_refs[3]);
668
} else if (p->pages.eop &&
669
pdf_stream_length(p->pages.eop) > 0) {
670
pdf_add_array(contents_array, pdf_ref_obj(p->pages.eop));
675
WARN("Page with empty content found!!!");
677
page->content_refs[0] = NULL;
678
page->content_refs[1] = NULL;
679
page->content_refs[2] = NULL;
680
page->content_refs[3] = NULL;
682
pdf_add_dict(page->page_obj,
683
pdf_new_name("Contents"), contents_array);
687
pdf_add_dict(page->page_obj,
688
pdf_new_name("Annots"), pdf_ref_obj(page->annots));
689
pdf_release_obj(page->annots);
692
pdf_add_dict(page->page_obj,
693
pdf_new_name("B"), pdf_ref_obj(page->beads));
694
pdf_release_obj(page->beads);
696
pdf_release_obj(page->page_obj);
697
pdf_release_obj(page->page_ref);
699
page->page_obj = NULL;
700
page->page_ref = NULL;
708
#define PAGE_CLUSTER 4
710
build_page_tree (pdf_doc *p,
711
pdf_page *firstpage, long num_pages,
714
pdf_obj *self, *self_ref, *kids;
717
self = pdf_new_dict();
719
* This is a slight kludge which allow the subtree dictionary
720
* generated by this routine to be merged with the real
721
* page_tree dictionary, while keeping the indirect object
724
self_ref = parent_ref ? pdf_ref_obj(self) : pdf_ref_obj(p->root.pages);
726
pdf_add_dict(self, pdf_new_name("Type"), pdf_new_name("Pages"));
727
pdf_add_dict(self, pdf_new_name("Count"), pdf_new_number((double) num_pages));
729
if (parent_ref != NULL)
730
pdf_add_dict(self, pdf_new_name("Parent"), parent_ref);
732
kids = pdf_new_array();
733
if (num_pages > 0 && num_pages <= PAGE_CLUSTER) {
734
for (i = 0; i < num_pages; i++) {
737
page = firstpage + i;
739
page->page_ref = pdf_ref_obj(page->page_obj);
740
pdf_add_array (kids, pdf_link_obj(page->page_ref));
741
doc_flush_page(p, page, pdf_link_obj(self_ref));
743
} else if (num_pages > 0) {
744
for (i = 0; i < PAGE_CLUSTER; i++) {
747
start = (i*num_pages)/PAGE_CLUSTER;
748
end = ((i+1)*num_pages)/PAGE_CLUSTER;
749
if (end - start > 1) {
752
subtree = build_page_tree(p, firstpage + start, end - start,
753
pdf_link_obj(self_ref));
754
pdf_add_array(kids, pdf_ref_obj(subtree));
755
pdf_release_obj(subtree);
759
page = firstpage + start;
761
page->page_ref = pdf_ref_obj(page->page_obj);
762
pdf_add_array (kids, pdf_link_obj(page->page_ref));
763
doc_flush_page(p, page, pdf_link_obj(self_ref));
767
pdf_add_dict(self, pdf_new_name("Kids"), kids);
768
pdf_release_obj(self_ref);
774
pdf_doc_init_page_tree (pdf_doc *p, double media_width, double media_height)
777
* Create empty page tree.
778
* The docroot.pages is kept open until the document is closed.
779
* This allows the user to write to pages if he so choses.
781
p->root.pages = pdf_new_dict();
783
p->pages.num_entries = 0;
784
p->pages.max_entries = 0;
785
p->pages.entries = NULL;
790
p->pages.mediabox.llx = 0.0;
791
p->pages.mediabox.lly = 0.0;
792
p->pages.mediabox.urx = media_width;
793
p->pages.mediabox.ury = media_height;
799
pdf_doc_close_page_tree (pdf_doc *p)
801
pdf_obj *page_tree_root;
806
* Do consistency check on forward references to pages.
808
for (page_no = PAGECOUNT(p) + 1; page_no <= MAXPAGES(p); page_no++) {
811
page = doc_get_page_entry(p, page_no);
812
if (page->page_obj) {
813
WARN("Nonexistent page #%ld refered.", page_no);
814
pdf_release_obj(page->page_ref);
815
page->page_ref = NULL;
817
if (page->page_obj) {
818
WARN("Entry for a nonexistent page #%ld created.", page_no);
819
pdf_release_obj(page->page_obj);
820
page->page_obj = NULL;
823
WARN("Annotation attached to a nonexistent page #%ld.", page_no);
824
pdf_release_obj(page->annots);
828
WARN("Article beads attached to a nonexistent page #%ld.", page_no);
829
pdf_release_obj(page->beads);
832
if (page->resources) {
833
pdf_release_obj(page->resources);
834
page->resources = NULL;
839
* Connect page tree to root node.
841
page_tree_root = build_page_tree(p, FIRSTPAGE(p), PAGECOUNT(p), NULL);
842
pdf_merge_dict (p->root.pages, page_tree_root);
843
pdf_release_obj(page_tree_root);
845
/* They must be after build_page_tree() */
847
pdf_add_stream (p->pages.bop, "\n", 1);
848
pdf_release_obj(p->pages.bop);
852
pdf_add_stream (p->pages.eop, "\n", 1);
853
pdf_release_obj(p->pages.eop);
857
/* Create media box at root node and let the other pages inherit it. */
858
mediabox = pdf_new_array();
859
pdf_add_array(mediabox, pdf_new_number(ROUND(p->pages.mediabox.llx, 0.01)));
860
pdf_add_array(mediabox, pdf_new_number(ROUND(p->pages.mediabox.lly, 0.01)));
861
pdf_add_array(mediabox, pdf_new_number(ROUND(p->pages.mediabox.urx, 0.01)));
862
pdf_add_array(mediabox, pdf_new_number(ROUND(p->pages.mediabox.ury, 0.01)));
863
pdf_add_dict(p->root.pages, pdf_new_name("MediaBox"), mediabox);
865
pdf_add_dict(p->root.dict,
866
pdf_new_name("Pages"),
867
pdf_ref_obj (p->root.pages));
868
pdf_release_obj(p->root.pages);
869
p->root.pages = NULL;
871
RELEASE(p->pages.entries);
872
p->pages.entries = NULL;
873
p->pages.num_entries = 0;
874
p->pages.max_entries = 0;
880
* From PDFReference15_v6.pdf (p.119 and p.834)
882
* MediaBox rectangle (Required; inheritable)
884
* The media box defines the boundaries of the physical medium on which the
885
* page is to be printed. It may include any extended area surrounding the
886
* finished page for bleed, printing marks, or other such purposes. It may
887
* also include areas close to the edges of the medium that cannot be marked
888
* because of physical limitations of the output device. Content falling
889
* outside this boundary can safely be discarded without affecting the
890
* meaning of the PDF file.
892
* CropBox rectangle (Optional; inheritable)
894
* The crop box defines the region to which the contents of the page are to be
895
* clipped (cropped) when displayed or printed. Unlike the other boxes, the
896
* crop box has no defined meaning in terms of physical page geometry or
897
* intended use; it merely imposes clipping on the page contents. However,
898
* in the absence of additional information (such as imposition instructions
899
* specified in a JDF or PJTF job ticket), the crop box will determine how
900
* the page's contents are to be positioned on the output medium. The default
901
* value is the page's media box.
903
* BleedBox rectangle (Optional; PDF 1.3)
905
* The bleed box (PDF 1.3) defines the region to which the contents of the
906
* page should be clipped when output in a production environment. This may
907
* include any extra "bleed area" needed to accommodate the physical
908
* limitations of cutting, folding, and trimming equipment. The actual printed
909
* page may include printing marks that fall outside the bleed box.
910
* The default value is the page's crop box.
912
* TrimBox rectangle (Optional; PDF 1.3)
914
* The trim box (PDF 1.3) defines the intended dimensions of the finished page
915
* after trimming. It may be smaller than the media box, to allow for
916
* production-related content such as printing instructions, cut marks, or
917
* color bars. The default value is the page's crop box.
919
* ArtBox rectangle (Optional; PDF 1.3)
921
* The art box (PDF 1.3) defines the extent of the page's meaningful content
922
* (including potential white space) as intended by the page's creator.
923
* The default value is the page's crop box.
925
* Rotate integer (Optional; inheritable)
927
* The number of degrees by which the page should be rotated clockwise when
928
* displayed or printed. The value must be a multiple of 90. Default value: 0.
932
pdf_doc_get_page (pdf_file *pf, long page_no, long *count_p,
933
pdf_rect *bbox, pdf_obj **resources_p) {
934
pdf_obj *page_tree = NULL;
935
pdf_obj *resources = NULL, *box = NULL, *rotate = NULL;
938
catalog = pdf_file_get_catalog(pf);
940
page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages"));
942
if (!PDF_OBJ_DICTTYPE(page_tree))
947
pdf_obj *tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count"));
948
if (!PDF_OBJ_NUMBERTYPE(tmp)) {
950
pdf_release_obj(tmp);
953
count = pdf_number_value(tmp);
954
pdf_release_obj(tmp);
957
if (page_no <= 0 || page_no > count) {
958
WARN("Page %ld does not exist.", page_no);
964
* Seek correct page. Get MediaBox, CropBox and Resources.
965
* (Note that these entries can be inherited.)
968
pdf_obj *media_box = NULL, *crop_box = NULL, *kids, *tmp;
969
int depth = PDF_OBJ_MAX_DEPTH;
970
long page_idx = page_no-1, kids_length = 1, i = 0;
972
while (--depth && i != kids_length) {
973
if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) {
975
pdf_release_obj(media_box);
979
if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) {
981
pdf_release_obj(crop_box);
985
if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) {
987
pdf_release_obj(rotate);
991
if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) {
993
pdf_release_obj(resources);
997
kids = pdf_deref_obj(pdf_lookup_dict(page_tree, "Kids"));
1000
else if (!PDF_OBJ_ARRAYTYPE(kids)) {
1001
pdf_release_obj(kids);
1004
kids_length = pdf_array_length(kids);
1006
for (i = 0; i < kids_length; i++) {
1009
pdf_release_obj(page_tree);
1010
page_tree = pdf_deref_obj(pdf_get_array(kids, i));
1011
if (!PDF_OBJ_DICTTYPE(page_tree))
1014
tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count"));
1015
if (PDF_OBJ_NUMBERTYPE(tmp)) {
1017
count = pdf_number_value(tmp);
1018
pdf_release_obj(tmp);
1023
pdf_release_obj(tmp);
1027
if (page_idx < count)
1033
pdf_release_obj(kids);
1036
if (!depth || kids_length == i) {
1038
pdf_release_obj(media_box);
1040
pdf_release_obj(crop_box);
1047
if (!(box = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox"))) &&
1048
!(box = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox"))) &&
1049
!(box = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox"))) &&
1055
pdf_release_obj(media_box);
1058
if (!PDF_OBJ_ARRAYTYPE(box) || pdf_array_length(box) != 4 ||
1059
!PDF_OBJ_DICTTYPE(resources))
1062
if (PDF_OBJ_NUMBERTYPE(rotate)) {
1063
if (pdf_number_value(rotate))
1064
WARN("<< /Rotate %d >> found. (Not supported yet)",
1065
(int) pdf_number_value(rotate));
1066
pdf_release_obj(rotate);
1074
for (i = 4; i--; ) {
1076
pdf_obj *tmp = pdf_deref_obj(pdf_get_array(box, i));
1077
if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1078
pdf_release_obj(tmp);
1081
x = pdf_number_value(tmp);
1083
case 0: bbox->llx = x; break;
1084
case 1: bbox->lly = x; break;
1085
case 2: bbox->urx = x; break;
1086
case 3: bbox->ury = x; break;
1088
pdf_release_obj(tmp);
1092
pdf_release_obj(box);
1095
*resources_p = resources;
1097
pdf_release_obj(resources);
1102
WARN("Cannot parse document. Broken PDF file?");
1105
pdf_release_obj(box);
1107
pdf_release_obj(rotate);
1109
pdf_release_obj(resources);
1111
pdf_release_obj(page_tree);
1116
#ifndef BOOKMARKS_OPEN_DEFAULT
1117
#define BOOKMARKS_OPEN_DEFAULT 0
1120
static int clean_bookmarks (pdf_olitem *item);
1121
static int flush_bookmarks (pdf_olitem *item,
1122
pdf_obj *parent_ref,
1123
pdf_obj *parent_dict);
1126
pdf_doc_init_bookmarks (pdf_doc *p, int bm_open_depth)
1130
#define MAX_OUTLINE_DEPTH 256u
1131
p->opt.outline_open_depth =
1132
((bm_open_depth >= 0) ?
1133
bm_open_depth : MAX_OUTLINE_DEPTH - bm_open_depth);
1135
p->outlines.current_depth = 1;
1137
item = NEW(1, pdf_olitem);
1141
item->parent = NULL;
1144
p->outlines.current = item;
1145
p->outlines.first = item;
1151
clean_bookmarks (pdf_olitem *item)
1158
pdf_release_obj(item->dict);
1160
clean_bookmarks(item->first);
1170
flush_bookmarks (pdf_olitem *node,
1171
pdf_obj *parent_ref, pdf_obj *parent_dict)
1176
pdf_obj *this_ref, *prev_ref, *next_ref;
1180
this_ref = pdf_ref_obj(node->dict);
1181
pdf_add_dict(parent_dict,
1182
pdf_new_name("First"), pdf_link_obj(this_ref));
1185
for (item = node, prev_ref = NULL;
1186
item && item->dict; item = item->next) {
1187
if (item->first && item->first->dict) {
1188
count = flush_bookmarks(item->first, this_ref, item->dict);
1189
if (item->is_open) {
1190
pdf_add_dict(item->dict,
1191
pdf_new_name("Count"),
1192
pdf_new_number(count));
1195
pdf_add_dict(item->dict,
1196
pdf_new_name("Count"),
1197
pdf_new_number(-count));
1200
pdf_add_dict(item->dict,
1201
pdf_new_name("Parent"),
1202
pdf_link_obj(parent_ref));
1204
pdf_add_dict(item->dict,
1205
pdf_new_name("Prev"),
1208
if (item->next && item->next->dict) {
1209
next_ref = pdf_ref_obj(item->next->dict);
1210
pdf_add_dict(item->dict,
1211
pdf_new_name("Next"),
1212
pdf_link_obj(next_ref));
1217
pdf_release_obj(item->dict);
1220
prev_ref = this_ref;
1221
this_ref = next_ref;
1225
pdf_add_dict(parent_dict,
1226
pdf_new_name("Last"),
1227
pdf_link_obj(prev_ref));
1229
pdf_release_obj(prev_ref);
1230
pdf_release_obj(node->dict);
1237
pdf_doc_bookmarks_up (void)
1240
pdf_olitem *parent, *item;
1242
item = p->outlines.current;
1243
if (!item || !item->parent) {
1244
WARN("Can't go up above the bookmark root node!");
1247
parent = item->parent;
1248
item = parent->next;
1249
if (!parent->next) {
1250
parent->next = item = NEW(1, pdf_olitem);
1255
item->parent = parent->parent;
1257
p->outlines.current = item;
1258
p->outlines.current_depth--;
1264
pdf_doc_bookmarks_down (void)
1267
pdf_olitem *item, *first;
1269
item = p->outlines.current;
1271
pdf_obj *tcolor, *action;
1273
WARN("Empty bookmark node!");
1274
WARN("You have tried to jump more than 1 level.");
1276
item->dict = pdf_new_dict();
1278
#define TITLE_STRING "<No Title>"
1279
pdf_add_dict(item->dict,
1280
pdf_new_name("Title"),
1281
pdf_new_string(TITLE_STRING, strlen(TITLE_STRING)));
1283
tcolor = pdf_new_array();
1284
pdf_add_array(tcolor, pdf_new_number(1.0));
1285
pdf_add_array(tcolor, pdf_new_number(0.0));
1286
pdf_add_array(tcolor, pdf_new_number(0.0));
1287
pdf_add_dict (item->dict,
1288
pdf_new_name("C"), pdf_link_obj(tcolor));
1289
pdf_release_obj(tcolor);
1291
pdf_add_dict (item->dict,
1292
pdf_new_name("F"), pdf_new_number(1.0));
1294
#define JS_CODE "app.alert(\"The author of this document made this bookmark item empty!\", 3, 0)"
1295
action = pdf_new_dict();
1296
pdf_add_dict(action,
1297
pdf_new_name("S"), pdf_new_name("JavaScript"));
1298
pdf_add_dict(action,
1299
pdf_new_name("JS"), pdf_new_string(JS_CODE, strlen(JS_CODE)));
1300
pdf_add_dict(item->dict,
1301
pdf_new_name("A"), pdf_link_obj(action));
1302
pdf_release_obj(action);
1305
item->first = first = NEW(1, pdf_olitem);
1308
first->parent = item;
1310
first->first = NULL;
1312
p->outlines.current = first;
1313
p->outlines.current_depth++;
1319
pdf_doc_bookmarks_depth (void)
1323
return p->outlines.current_depth;
1327
pdf_doc_bookmarks_add (pdf_obj *dict, int is_open)
1330
pdf_olitem *item, *next;
1334
item = p->outlines.current;
1337
item = NEW(1, pdf_olitem);
1338
item->parent = NULL;
1339
p->outlines.first = item;
1340
} else if (item->dict) { /* go to next item */
1344
#define BMOPEN(b,p) (((b) < 0) ? (((p)->outlines.current_depth > (p)->opt.outline_open_depth) ? 0 : 1) : (b))
1347
item->dict = pdf_link_obj(dict);
1351
item->is_open = BMOPEN(is_open, p);
1353
item->next = next = NEW(1, pdf_olitem);
1355
next->parent = item->parent;
1360
p->outlines.current = item;
1362
pdf_doc_add_goto(dict);
1368
pdf_doc_close_bookmarks (pdf_doc *p)
1370
pdf_obj *catalog = p->root.dict;
1373
pdf_obj *bm_root, *bm_root_ref;
1375
item = p->outlines.first;
1377
bm_root = pdf_new_dict();
1378
bm_root_ref = pdf_ref_obj(bm_root);
1379
count = flush_bookmarks(item, bm_root_ref, bm_root);
1380
pdf_add_dict(bm_root,
1381
pdf_new_name("Count"),
1382
pdf_new_number(count));
1383
pdf_add_dict(catalog,
1384
pdf_new_name("Outlines"),
1386
pdf_release_obj(bm_root);
1388
clean_bookmarks(item);
1390
p->outlines.first = NULL;
1391
p->outlines.current = NULL;
1392
p->outlines.current_depth = 0;
1398
static const char *name_dict_categories[] = {
1399
"Dests", "AP", "JavaScript", "Pages",
1400
"Templates", "IDS", "URLS", "EmbeddedFiles",
1401
"AlternatePresentations", "Renditions"
1403
#define NUM_NAME_CATEGORY (sizeof(name_dict_categories)/sizeof(name_dict_categories[0]))
1406
pdf_doc_init_names (pdf_doc *p, int check_gotos)
1410
p->root.names = NULL;
1412
p->names = NEW(NUM_NAME_CATEGORY + 1, struct name_dict);
1413
for (i = 0; i < NUM_NAME_CATEGORY; i++) {
1414
p->names[i].category = name_dict_categories[i];
1415
p->names[i].data = strcmp(name_dict_categories[i], "Dests") ?
1416
NULL : pdf_new_name_tree();
1418
* We need a non-null entry for PDF destinations in order to find
1419
* broken links even if no destination is defined in the DVI file.
1422
p->names[NUM_NAME_CATEGORY].category = NULL;
1423
p->names[NUM_NAME_CATEGORY].data = NULL;
1425
p->check_gotos = check_gotos;
1426
ht_init_table(&p->gotos, (void (*) (void *)) pdf_release_obj);
1432
pdf_doc_add_names (const char *category,
1433
const void *key, int keylen, pdf_obj *value)
1438
for (i = 0; p->names[i].category != NULL; i++) {
1439
if (!strcmp(p->names[i].category, category)) {
1443
if (p->names[i].category == NULL) {
1444
WARN("Unknown name dictionary category \"%s\".", category);
1447
if (!p->names[i].data) {
1448
p->names[i].data = pdf_new_name_tree();
1451
return pdf_names_add_object(p->names[i].data, key, keylen, value);
1455
pdf_doc_add_goto (pdf_obj *annot_dict)
1457
pdf_obj *subtype = NULL, *A = NULL, *S = NULL, *D = NULL, *D_new, *dict;
1458
const char *dest, *key;
1460
if (!pdoc.check_gotos)
1464
* An annotation dictionary coming from an annotation special
1465
* must have a "Subtype". An annotation dictionary coming from
1466
* an outline special has none.
1468
subtype = pdf_deref_obj(pdf_lookup_dict(annot_dict, "Subtype"));
1470
if (PDF_OBJ_UNDEFINED(subtype))
1472
else if (!PDF_OBJ_NAMETYPE(subtype))
1474
else if (strcmp(pdf_name_value(subtype), "Link"))
1480
D = pdf_deref_obj(pdf_lookup_dict(annot_dict, key));
1481
if (PDF_OBJ_UNDEFINED(D))
1484
A = pdf_deref_obj(pdf_lookup_dict(annot_dict, "A"));
1486
if (PDF_OBJ_UNDEFINED(A))
1488
else if (D || !PDF_OBJ_DICTTYPE(A))
1491
S = pdf_deref_obj(pdf_lookup_dict(A, "S"));
1492
if (PDF_OBJ_UNDEFINED(S))
1494
else if (!PDF_OBJ_NAMETYPE(S))
1496
else if (strcmp(pdf_name_value(S), "GoTo"))
1501
D = pdf_deref_obj(pdf_lookup_dict(A, key));
1505
if (PDF_OBJ_STRINGTYPE(D))
1506
dest = (char *) pdf_string_value(D);
1508
/* Names as destinations are not supported by dvipdfmx */
1509
else if (PDF_OBJ_NAMETYPE(D))
1510
dest = pdf_name_value(D);
1512
else if (PDF_OBJ_ARRAYTYPE(D))
1514
else if (PDF_OBJ_UNDEFINED(D))
1519
D_new = ht_lookup_table(&pdoc.gotos, dest, strlen(dest));
1523
/* We use hexadecimal notation for our numeric destinations.
1524
* Other bases (e.g., 10+26 or 10+2*26) would be more efficient.
1526
sprintf(buf, "%lx", ht_table_size(&pdoc.gotos));
1527
D_new = pdf_new_string(buf, strlen(buf));
1528
ht_append_table(&pdoc.gotos, dest, strlen(dest), D_new);
1532
pdf_obj *key_obj = pdf_new_name(key);
1533
if (!pdf_add_dict(dict, key_obj, pdf_link_obj(D_new)))
1534
pdf_release_obj(key_obj);
1539
pdf_release_obj(subtype);
1550
WARN("Unknown PDF annotation format. Output file may be broken.");
1554
WARN("Cannot optimize PDF annotations. Output file may be broken."
1555
" Please restart with option \"-C 0x10\"\n");
1560
warn_undef_dests (struct ht_table *dests, struct ht_table *gotos)
1562
struct ht_iter iter;
1564
if (ht_set_iter(gotos, &iter) < 0)
1569
char *key = ht_iter_getkey(&iter, &keylen);
1570
if (!ht_lookup_table(dests, key, keylen)) {
1571
char *dest = NEW(keylen+1, char);
1572
memcpy(dest, key, keylen);
1574
WARN("PDF destination \"%s\" not defined.", dest);
1577
} while (ht_iter_next(&iter) >= 0);
1579
ht_clear_iter(&iter);
1583
pdf_doc_close_names (pdf_doc *p)
1588
for (i = 0; p->names[i].category != NULL; i++) {
1589
if (p->names[i].data) {
1590
struct ht_table *data = p->names[i].data;
1594
if (!pdoc.check_gotos || strcmp(p->names[i].category, "Dests"))
1595
name_tree = pdf_names_create_tree(data, &count, NULL);
1597
name_tree = pdf_names_create_tree(data, &count, &pdoc.gotos);
1599
if (verbose && count < data->count)
1600
MESG("\nRemoved %ld unused PDF destinations\n", data->count-count);
1602
if (count < pdoc.gotos.count)
1603
warn_undef_dests(data, &pdoc.gotos);
1608
p->root.names = pdf_new_dict();
1609
pdf_add_dict(p->root.names,
1610
pdf_new_name(p->names[i].category),
1611
pdf_ref_obj(name_tree));
1612
pdf_release_obj(name_tree);
1614
pdf_delete_name_tree(&p->names[i].data);
1618
if (p->root.names) {
1619
tmp = pdf_lookup_dict(p->root.dict, "Names");
1621
pdf_add_dict(p->root.dict,
1622
pdf_new_name("Names"),
1623
pdf_ref_obj (p->root.names));
1624
} else if (PDF_OBJ_DICTTYPE(tmp)) {
1625
pdf_merge_dict(p->root.names, tmp);
1626
pdf_add_dict(p->root.dict,
1627
pdf_new_name("Names"),
1628
pdf_ref_obj (p->root.names));
1629
} else { /* Maybe reference */
1630
/* What should I do? */
1631
WARN("Could not modify Names dictionary.");
1633
pdf_release_obj(p->root.names);
1634
p->root.names = NULL;
1640
ht_clear_table(&p->gotos);
1647
pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect,
1648
pdf_obj *annot_dict, int new_annot)
1652
pdf_obj *rect_array;
1653
double annot_grow = p->opt.annot_grow;
1655
pdf_rect mediabox, annbox;
1657
page = doc_get_page_entry(p, page_no);
1659
page->annots = pdf_new_array();
1661
pdf_doc_get_mediabox(page_no, &mediabox);
1662
pdf_dev_get_coord(&xpos, &ypos);
1663
annbox.llx = rect->llx - xpos; annbox.lly = rect->lly - ypos;
1664
annbox.urx = rect->urx - xpos; annbox.ury = rect->ury - ypos;
1666
if (annbox.llx < mediabox.llx || annbox.urx > mediabox.urx ||
1667
annbox.lly < mediabox.lly || annbox.ury > mediabox.ury) {
1668
WARN("Annotation out of page boundary.");
1669
WARN("Current page's MediaBox: [%g %g %g %g]",
1670
mediabox.llx, mediabox.lly, mediabox.urx, mediabox.ury);
1671
WARN("Annotation: [%g %g %g %g]",
1672
annbox.llx, annbox.lly, annbox.urx, annbox.ury);
1673
WARN("Maybe incorrect paper size specified.");
1675
if (annbox.llx > annbox.urx || annbox.lly > annbox.ury) {
1676
WARN("Rectangle with negative width/height: [%g %g %g %g]",
1677
annbox.llx, annbox.lly, annbox.urx, annbox.ury);
1680
rect_array = pdf_new_array();
1681
pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.llx - annot_grow, 0.001)));
1682
pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.lly - annot_grow, 0.001)));
1683
pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.urx + annot_grow, 0.001)));
1684
pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.ury + annot_grow, 0.001)));
1685
pdf_add_dict (annot_dict, pdf_new_name("Rect"), rect_array);
1687
pdf_add_array(page->annots, pdf_ref_obj(annot_dict));
1690
pdf_doc_add_goto(annot_dict);
1697
* PDF Article Thread
1700
pdf_doc_init_articles (pdf_doc *p)
1702
p->root.threads = NULL;
1704
p->articles.num_entries = 0;
1705
p->articles.max_entries = 0;
1706
p->articles.entries = NULL;
1712
pdf_doc_begin_article (const char *article_id, pdf_obj *article_info)
1715
pdf_article *article;
1717
if (article_id == NULL || strlen(article_id) == 0)
1718
ERROR("Article thread without internal identifier.");
1720
if (p->articles.num_entries >= p->articles.max_entries) {
1721
p->articles.max_entries += PDFDOC_ARTICLE_ALLOC_SIZE;
1722
p->articles.entries = RENEW(p->articles.entries,
1723
p->articles.max_entries, struct pdf_article);
1725
article = &(p->articles.entries[p->articles.num_entries]);
1727
article->id = NEW(strlen(article_id)+1, char);
1728
strcpy(article->id, article_id);
1729
article->info = article_info;
1730
article->num_beads = 0;
1731
article->max_beads = 0;
1732
article->beads = NULL;
1734
p->articles.num_entries++;
1741
pdf_doc_end_article (const char *article_id)
1748
find_bead (pdf_article *article, const char *bead_id)
1754
for (i = 0; i < article->num_beads; i++) {
1755
if (!strcmp(article->beads[i].id, bead_id)) {
1756
bead = &(article->beads[i]);
1765
pdf_doc_add_bead (const char *article_id,
1766
const char *bead_id, long page_no, const pdf_rect *rect)
1769
pdf_article *article;
1774
ERROR("No article identifier specified.");
1778
for (i = 0; i < p->articles.num_entries; i++) {
1779
if (!strcmp(p->articles.entries[i].id, article_id)) {
1780
article = &(p->articles.entries[i]);
1785
ERROR("Specified article thread that doesn't exist.");
1789
bead = bead_id ? find_bead(article, bead_id) : NULL;
1791
if (article->num_beads >= article->max_beads) {
1792
article->max_beads += PDFDOC_BEAD_ALLOC_SIZE;
1793
article->beads = RENEW(article->beads,
1794
article->max_beads, struct pdf_bead);
1795
for (i = article->num_beads; i < article->max_beads; i++) {
1796
article->beads[i].id = NULL;
1797
article->beads[i].page_no = -1;
1800
bead = &(article->beads[article->num_beads]);
1802
bead->id = NEW(strlen(bead_id)+1, char);
1803
strcpy(bead->id, bead_id);
1807
article->num_beads++;
1809
bead->rect.llx = rect->llx;
1810
bead->rect.lly = rect->lly;
1811
bead->rect.urx = rect->urx;
1812
bead->rect.ury = rect->ury;
1813
bead->page_no = page_no;
1819
make_article (pdf_doc *p,
1820
pdf_article *article,
1821
const char **bead_ids, int num_beads,
1822
pdf_obj *article_info)
1825
pdf_obj *first, *prev, *last;
1831
art_dict = pdf_new_dict();
1832
first = prev = last = NULL;
1834
* The bead_ids represents logical order of beads in an article thread.
1835
* If bead_ids is not given, we create an article thread in the order of
1838
n = bead_ids ? num_beads : article->num_beads;
1839
for (i = 0; i < n; i++) {
1842
bead = bead_ids ? find_bead(article, bead_ids[i]) : &(article->beads[i]);
1843
if (!bead || bead->page_no < 0) {
1846
last = pdf_new_dict();
1850
pdf_new_name("T"), pdf_ref_obj(art_dict));
1853
pdf_new_name("N"), pdf_ref_obj(last));
1855
pdf_new_name("V"), pdf_ref_obj(prev));
1856
/* We must link first to last. */
1858
pdf_release_obj(prev);
1861
/* Realize bead now. */
1866
page = doc_get_page_entry(p, bead->page_no);
1868
page->beads = pdf_new_array();
1870
pdf_add_dict(last, pdf_new_name("P"), pdf_link_obj(page->page_ref));
1871
rect = pdf_new_array();
1872
pdf_add_array(rect, pdf_new_number(ROUND(bead->rect.llx, 0.01)));
1873
pdf_add_array(rect, pdf_new_number(ROUND(bead->rect.lly, 0.01)));
1874
pdf_add_array(rect, pdf_new_number(ROUND(bead->rect.urx, 0.01)));
1875
pdf_add_array(rect, pdf_new_number(ROUND(bead->rect.ury, 0.01)));
1876
pdf_add_dict (last, pdf_new_name("R"), rect);
1877
pdf_add_array(page->beads, pdf_ref_obj(last));
1883
if (first && last) {
1885
pdf_new_name("N"), pdf_ref_obj(first));
1887
pdf_new_name("V"), pdf_ref_obj(last));
1888
if (first != last) {
1889
pdf_release_obj(last);
1891
pdf_add_dict(art_dict,
1892
pdf_new_name("F"), pdf_ref_obj(first));
1893
/* If article_info is supplied, we override article->info. */
1895
pdf_add_dict(art_dict,
1896
pdf_new_name("I"), article_info);
1897
} else if (article->info) {
1898
pdf_add_dict(art_dict,
1899
pdf_new_name("I"), pdf_ref_obj(article->info));
1900
pdf_release_obj(article->info);
1901
article->info = NULL; /* We do not write as object reference. */
1903
pdf_release_obj(first);
1905
pdf_release_obj(art_dict);
1913
clean_article (pdf_article *article)
1918
if (article->beads) {
1921
for (i = 0; i < article->num_beads; i++) {
1922
if (article->beads[i].id)
1923
RELEASE(article->beads[i].id);
1925
RELEASE(article->beads);
1926
article->beads = NULL;
1930
RELEASE(article->id);
1932
article->num_beads = 0;
1933
article->max_beads = 0;
1939
pdf_doc_close_articles (pdf_doc *p)
1943
for (i = 0; i < p->articles.num_entries; i++) {
1944
pdf_article *article;
1946
article = &(p->articles.entries[i]);
1947
if (article->beads) {
1950
art_dict = make_article(p, article, NULL, 0, NULL);
1951
if (!p->root.threads) {
1952
p->root.threads = pdf_new_array();
1954
pdf_add_array(p->root.threads, pdf_ref_obj(art_dict));
1955
pdf_release_obj(art_dict);
1957
clean_article(article);
1959
RELEASE(p->articles.entries);
1960
p->articles.entries = NULL;
1961
p->articles.num_entries = 0;
1962
p->articles.max_entries = 0;
1964
if (p->root.threads) {
1965
pdf_add_dict(p->root.dict,
1966
pdf_new_name("Threads"),
1967
pdf_ref_obj (p->root.threads));
1968
pdf_release_obj(p->root.threads);
1969
p->root.threads = NULL;
1975
/* page_no = 0 for root page tree node. */
1977
pdf_doc_set_mediabox (unsigned page_no, const pdf_rect *mediabox)
1983
p->pages.mediabox.llx = mediabox->llx;
1984
p->pages.mediabox.lly = mediabox->lly;
1985
p->pages.mediabox.urx = mediabox->urx;
1986
p->pages.mediabox.ury = mediabox->ury;
1988
page = doc_get_page_entry(p, page_no);
1989
page->cropbox.llx = mediabox->llx;
1990
page->cropbox.lly = mediabox->lly;
1991
page->cropbox.urx = mediabox->urx;
1992
page->cropbox.ury = mediabox->ury;
1993
page->flags |= USE_MY_MEDIABOX;
2000
pdf_doc_get_mediabox (unsigned page_no, pdf_rect *mediabox)
2006
mediabox->llx = p->pages.mediabox.llx;
2007
mediabox->lly = p->pages.mediabox.lly;
2008
mediabox->urx = p->pages.mediabox.urx;
2009
mediabox->ury = p->pages.mediabox.ury;
2011
page = doc_get_page_entry(p, page_no);
2012
if (page->flags & USE_MY_MEDIABOX) {
2013
mediabox->llx = page->cropbox.llx;
2014
mediabox->lly = page->cropbox.lly;
2015
mediabox->urx = page->cropbox.urx;
2016
mediabox->ury = page->cropbox.ury;
2018
mediabox->llx = p->pages.mediabox.llx;
2019
mediabox->lly = p->pages.mediabox.lly;
2020
mediabox->urx = p->pages.mediabox.urx;
2021
mediabox->ury = p->pages.mediabox.ury;
2029
pdf_doc_current_page_resources (void)
2033
pdf_page *currentpage;
2035
if (p->pending_forms) {
2036
if (p->pending_forms->form.resources) {
2037
resources = p->pending_forms->form.resources;
2039
resources = p->pending_forms->form.resources = pdf_new_dict();
2042
currentpage = LASTPAGE(p);
2043
if (currentpage->resources) {
2044
resources = currentpage->resources;
2046
resources = currentpage->resources = pdf_new_dict();
2054
pdf_doc_get_dictionary (const char *category)
2057
pdf_obj *dict = NULL;
2061
if (!strcmp(category, "Names")) {
2063
p->root.names = pdf_new_dict();
2064
dict = p->root.names;
2065
} else if (!strcmp(category, "Pages")) {
2067
p->root.pages = pdf_new_dict();
2068
dict = p->root.pages;
2069
} else if (!strcmp(category, "Catalog")) {
2071
p->root.dict = pdf_new_dict();
2072
dict = p->root.dict;
2073
} else if (!strcmp(category, "Info")) {
2075
p->info = pdf_new_dict();
2077
} else if (!strcmp(category, "@THISPAGE")) {
2078
/* Sorry for this... */
2079
pdf_page *currentpage;
2081
currentpage = LASTPAGE(p);
2082
dict = currentpage->page_obj;
2086
ERROR("Document dict. \"%s\" not exist. ", category);
2093
pdf_doc_current_page_number (void)
2097
return (long) (PAGECOUNT(p) + 1);
2101
pdf_doc_ref_page (unsigned long page_no)
2106
page = doc_get_page_entry(p, page_no);
2107
if (!page->page_obj) {
2108
page->page_obj = pdf_new_dict();
2109
page->page_ref = pdf_ref_obj(page->page_obj);
2112
return pdf_link_obj(page->page_ref);
2116
pdf_doc_get_reference (const char *category)
2118
pdf_obj *ref = NULL;
2123
page_no = pdf_doc_current_page_number();
2124
if (!strcmp(category, "@THISPAGE")) {
2125
ref = pdf_doc_ref_page(page_no);
2126
} else if (!strcmp(category, "@PREVPAGE")) {
2128
ERROR("Reference to previous page, but no pages have been completed yet.");
2130
ref = pdf_doc_ref_page(page_no - 1);
2131
} else if (!strcmp(category, "@NEXTPAGE")) {
2132
ref = pdf_doc_ref_page(page_no + 1);
2136
ERROR("Reference to \"%s\" not exist. ", category);
2143
pdf_doc_new_page (pdf_doc *p)
2145
pdf_page *currentpage;
2147
if (PAGECOUNT(p) >= MAXPAGES(p)) {
2148
doc_resize_page_entries(p, MAXPAGES(p) + PDFDOC_PAGES_ALLOC_SIZE);
2152
* This is confusing. pdf_doc_finish_page() have increased page count!
2154
currentpage = LASTPAGE(p);
2155
/* Was this page already instantiated by a forward reference to it? */
2156
if (!currentpage->page_ref) {
2157
currentpage->page_obj = pdf_new_dict();
2158
currentpage->page_ref = pdf_ref_obj(currentpage->page_obj);
2161
currentpage->background = NULL;
2162
currentpage->contents = pdf_new_stream(STREAM_COMPRESS);
2163
currentpage->resources = pdf_new_dict();
2165
currentpage->annots = NULL;
2166
currentpage->beads = NULL;
2171
/* This only closes contents and resources. */
2173
pdf_doc_finish_page (pdf_doc *p)
2175
pdf_page *currentpage;
2177
if (p->pending_forms) {
2178
ERROR("A pending form XObject at the end of page.");
2181
currentpage = LASTPAGE(p);
2182
if (!currentpage->page_obj)
2183
currentpage->page_obj = pdf_new_dict();
2186
* Make Contents array.
2190
* Global BOP content stream.
2191
* pdf_ref_obj() returns reference itself when the object is
2192
* indirect reference, not reference to the indirect reference.
2193
* We keep bop itself but not reference to it since it is
2194
* expected to be small.
2197
pdf_stream_length(p->pages.bop) > 0) {
2198
currentpage->content_refs[0] = pdf_ref_obj(p->pages.bop);
2200
currentpage->content_refs[0] = NULL;
2203
* Current page background content stream.
2205
if (currentpage->background) {
2206
if (pdf_stream_length(currentpage->background) > 0) {
2207
currentpage->content_refs[1] = pdf_ref_obj(currentpage->background);
2208
pdf_add_stream (currentpage->background, "\n", 1);
2210
pdf_release_obj(currentpage->background);
2211
currentpage->background = NULL;
2213
currentpage->content_refs[1] = NULL;
2216
/* Content body of current page */
2217
currentpage->content_refs[2] = pdf_ref_obj(currentpage->contents);
2218
pdf_add_stream (currentpage->contents, "\n", 1);
2219
pdf_release_obj(currentpage->contents);
2220
currentpage->contents = NULL;
2223
* Global EOP content stream.
2226
pdf_stream_length(p->pages.eop) > 0) {
2227
currentpage->content_refs[3] = pdf_ref_obj(p->pages.eop);
2229
currentpage->content_refs[3] = NULL;
2235
if (currentpage->resources) {
2238
* ProcSet is obsolete in PDF-1.4 but recommended for compatibility.
2241
procset = pdf_new_array ();
2242
pdf_add_array(procset, pdf_new_name("PDF"));
2243
pdf_add_array(procset, pdf_new_name("Text"));
2244
pdf_add_array(procset, pdf_new_name("ImageC"));
2245
pdf_add_array(procset, pdf_new_name("ImageB"));
2246
pdf_add_array(procset, pdf_new_name("ImageI"));
2247
pdf_add_dict(currentpage->resources, pdf_new_name("ProcSet"), procset);
2249
pdf_add_dict(currentpage->page_obj,
2250
pdf_new_name("Resources"),
2251
pdf_ref_obj(currentpage->resources));
2252
pdf_release_obj(currentpage->resources);
2253
currentpage->resources = NULL;
2256
if (manual_thumb_enabled) {
2257
char *thumb_filename;
2260
thumb_filename = NEW(strlen(thumb_basename)+7, char);
2261
sprintf(thumb_filename, "%s.%ld",
2262
thumb_basename, (p->pages.num_entries % 99999) + 1L);
2263
thumb_ref = read_thumbnail(thumb_filename);
2264
RELEASE(thumb_filename);
2266
pdf_add_dict(currentpage->page_obj, pdf_new_name("Thumb"), thumb_ref);
2269
p->pages.num_entries++;
2275
static pdf_color bgcolor;
2278
pdf_doc_set_bgcolor (const pdf_color *color)
2281
pdf_color_copycolor(&bgcolor, color);
2282
else { /* as clear... */
2283
pdf_color_white(&bgcolor);
2288
doc_fill_page_background (pdf_doc *p)
2290
pdf_page *currentpage;
2293
pdf_obj *saved_content;
2295
cm = pdf_dev_get_param(PDF_DEV_PARAM_COLORMODE);
2296
if (!cm || pdf_color_is_white(&bgcolor)) {
2300
pdf_doc_get_mediabox(pdf_doc_current_page_number(), &r);
2302
currentpage = LASTPAGE(p);
2303
ASSERT(currentpage);
2305
if (!currentpage->background)
2306
currentpage->background = pdf_new_stream(STREAM_COMPRESS);
2308
saved_content = currentpage->contents;
2309
currentpage->contents = currentpage->background;
2312
pdf_dev_set_nonstrokingcolor(&bgcolor);
2313
pdf_dev_rectfill(r.llx, r.lly, r.urx - r.llx, r.ury - r.lly);
2316
currentpage->contents = saved_content;
2322
pdf_doc_begin_page (double scale, double x_origin, double y_origin)
2327
M.a = scale; M.b = 0.0;
2328
M.c = 0.0 ; M.d = scale;
2332
/* pdf_doc_new_page() allocates page content stream. */
2333
pdf_doc_new_page(p);
2340
pdf_doc_end_page (void)
2345
doc_fill_page_background(p);
2347
pdf_doc_finish_page(p);
2353
pdf_doc_add_page_content (const char *buffer, unsigned length)
2356
pdf_page *currentpage;
2358
if (p->pending_forms) {
2359
pdf_add_stream(p->pending_forms->form.contents, buffer, length);
2361
currentpage = LASTPAGE(p);
2362
pdf_add_stream(currentpage->contents, buffer, length);
2368
static char *doccreator = NULL; /* Ugh */
2371
pdf_open_document (const char *filename,
2373
double media_width, double media_height,
2374
double annot_grow_amount, int bookmark_open_depth,
2379
pdf_out_init(filename, do_encryption);
2381
pdf_doc_init_catalog(p);
2383
p->opt.annot_grow = annot_grow_amount;
2384
p->opt.outline_open_depth = bookmark_open_depth;
2386
pdf_init_resources();
2389
/* Thumbnail want this to be initialized... */
2392
pdf_doc_init_docinfo(p);
2394
pdf_add_dict(p->info,
2395
pdf_new_name("Creator"),
2396
pdf_new_string(doccreator, strlen(doccreator)));
2397
RELEASE(doccreator); doccreator = NULL;
2400
pdf_doc_init_bookmarks(p, bookmark_open_depth);
2401
pdf_doc_init_articles (p);
2402
pdf_doc_init_names (p, check_gotos);
2403
pdf_doc_init_page_tree(p, media_width, media_height);
2405
pdf_doc_set_bgcolor(NULL);
2407
if (do_encryption) {
2408
pdf_obj *encrypt = pdf_encrypt_obj();
2409
pdf_set_encrypt(encrypt);
2410
pdf_release_obj(encrypt);
2412
pdf_set_id(pdf_enc_id_array());
2414
/* Create a default name for thumbnail image files */
2415
if (manual_thumb_enabled) {
2416
if (strlen(filename) > 4 &&
2417
!strncmp(".pdf", filename + strlen(filename) - 4, 4)) {
2418
thumb_basename = NEW(strlen(filename)-4+1, char);
2419
strncpy(thumb_basename, filename, strlen(filename)-4);
2420
thumb_basename[strlen(filename)-4] = 0;
2422
thumb_basename = NEW(strlen(filename)+1, char);
2423
strcpy(thumb_basename, filename);
2427
p->pending_forms = NULL;
2433
pdf_doc_set_creator (const char *creator)
2439
doccreator = NEW(strlen(creator)+1, char);
2440
strcpy(doccreator, creator); /* Ugh */
2445
pdf_close_document (void)
2450
* Following things were kept around so user can add dictionary items.
2452
pdf_doc_close_articles (p);
2453
pdf_doc_close_names (p);
2454
pdf_doc_close_bookmarks(p);
2455
pdf_doc_close_page_tree(p);
2456
pdf_doc_close_docinfo (p);
2458
pdf_doc_close_catalog (p);
2464
pdf_close_resources(); /* Should be at last. */
2469
RELEASE(thumb_basename);
2475
* All this routine does is give the form a name and add a unity scaling matrix.
2476
* It fills in required fields. The caller must initialize the stream.
2479
pdf_doc_make_xform (pdf_obj *xform,
2481
pdf_tmatrix *matrix,
2485
pdf_obj *xform_dict;
2488
xform_dict = pdf_stream_dict(xform);
2489
pdf_add_dict(xform_dict,
2490
pdf_new_name("Type"), pdf_new_name("XObject"));
2491
pdf_add_dict(xform_dict,
2492
pdf_new_name("Subtype"), pdf_new_name("Form"));
2493
pdf_add_dict(xform_dict,
2494
pdf_new_name("FormType"), pdf_new_number(1.0));
2497
ERROR("No BoundingBox supplied.");
2499
tmp = pdf_new_array();
2500
pdf_add_array(tmp, pdf_new_number(ROUND(bbox->llx, .001)));
2501
pdf_add_array(tmp, pdf_new_number(ROUND(bbox->lly, .001)));
2502
pdf_add_array(tmp, pdf_new_number(ROUND(bbox->urx, .001)));
2503
pdf_add_array(tmp, pdf_new_number(ROUND(bbox->ury, .001)));
2504
pdf_add_dict(xform_dict, pdf_new_name("BBox"), tmp);
2507
tmp = pdf_new_array();
2508
pdf_add_array(tmp, pdf_new_number(ROUND(matrix->a, .00001)));
2509
pdf_add_array(tmp, pdf_new_number(ROUND(matrix->b, .00001)));
2510
pdf_add_array(tmp, pdf_new_number(ROUND(matrix->c, .00001)));
2511
pdf_add_array(tmp, pdf_new_number(ROUND(matrix->d, .00001)));
2512
pdf_add_array(tmp, pdf_new_number(ROUND(matrix->e, .001 )));
2513
pdf_add_array(tmp, pdf_new_number(ROUND(matrix->f, .001 )));
2514
pdf_add_dict(xform_dict, pdf_new_name("Matrix"), tmp);
2518
pdf_merge_dict(xform_dict, attrib);
2521
pdf_add_dict(xform_dict, pdf_new_name("Resources"), resources);
2527
* begin_form_xobj creates an xobject with its "origin" at
2528
* xpos and ypos that is clipped to the specified bbox. Note
2529
* that the origin is not the lower left corner of the bbox.
2532
pdf_doc_begin_grabbing (const char *ident,
2533
double ref_x, double ref_y, const pdf_rect *cropbox)
2538
struct form_list_node *fnode;
2541
pdf_dev_push_gstate();
2543
fnode = NEW(1, struct form_list_node);
2545
fnode->prev = p->pending_forms;
2546
fnode->q_depth = pdf_dev_current_depth();
2547
form = &fnode->form;
2550
* The reference point of an Xobject is at the lower left corner
2551
* of the bounding box. Since we would like to have an arbitrary
2552
* reference point, we use a transformation matrix, translating
2553
* the reference point to (0,0).
2556
form->matrix.a = 1.0; form->matrix.b = 0.0;
2557
form->matrix.c = 0.0; form->matrix.d = 1.0;
2558
form->matrix.e = -ref_x;
2559
form->matrix.f = -ref_y;
2561
form->cropbox.llx = ref_x + cropbox->llx;
2562
form->cropbox.lly = ref_y + cropbox->lly;
2563
form->cropbox.urx = ref_x + cropbox->urx;
2564
form->cropbox.ury = ref_y + cropbox->ury;
2566
form->contents = pdf_new_stream(STREAM_COMPRESS);
2567
form->resources = pdf_new_dict();
2569
pdf_ximage_init_form_info(&info);
2571
info.matrix.a = 1.0; info.matrix.b = 0.0;
2572
info.matrix.c = 0.0; info.matrix.d = 1.0;
2573
info.matrix.e = -ref_x;
2574
info.matrix.f = -ref_y;
2576
info.bbox.llx = cropbox->llx;
2577
info.bbox.lly = cropbox->lly;
2578
info.bbox.urx = cropbox->urx;
2579
info.bbox.ury = cropbox->ury;
2581
/* Use reference since content itself isn't available yet. */
2582
xobj_id = pdf_ximage_defineresource(ident,
2583
PDF_XOBJECT_TYPE_FORM,
2584
&info, pdf_ref_obj(form->contents));
2586
p->pending_forms = fnode;
2589
* Make sure the object is self-contained by adding the
2590
* current font and color to the object stream.
2592
pdf_dev_reset_fonts();
2593
pdf_dev_reset_color(1); /* force color operators to be added to stream */
2599
pdf_doc_end_grabbing (pdf_obj *attrib)
2604
struct form_list_node *fnode;
2606
if (!p->pending_forms) {
2607
WARN("Tried to close a nonexistent form XOject.");
2611
fnode = p->pending_forms;
2612
form = &fnode->form;
2614
pdf_dev_grestore_to(fnode->q_depth);
2617
* ProcSet is obsolete in PDF-1.4 but recommended for compatibility.
2619
procset = pdf_new_array();
2620
pdf_add_array(procset, pdf_new_name("PDF"));
2621
pdf_add_array(procset, pdf_new_name("Text"));
2622
pdf_add_array(procset, pdf_new_name("ImageC"));
2623
pdf_add_array(procset, pdf_new_name("ImageB"));
2624
pdf_add_array(procset, pdf_new_name("ImageI"));
2625
pdf_add_dict (form->resources, pdf_new_name("ProcSet"), procset);
2627
pdf_doc_make_xform(form->contents,
2628
&form->cropbox, &form->matrix,
2629
pdf_ref_obj(form->resources), attrib);
2630
pdf_release_obj(form->resources);
2631
pdf_release_obj(form->contents);
2632
if (attrib) pdf_release_obj(attrib);
2634
p->pending_forms = fnode->prev;
2636
pdf_dev_pop_gstate();
2638
pdf_dev_reset_fonts();
2639
pdf_dev_reset_color(0);
2650
pdf_obj *annot_dict;
2652
} breaking_state = {0, 0, NULL, {0.0, 0.0, 0.0, 0.0}};
2657
breaking_state.rect.llx = breaking_state.rect.lly = HUGE_VAL;
2658
breaking_state.rect.urx = breaking_state.rect.ury = -HUGE_VAL;
2659
breaking_state.dirty = 0;
2663
pdf_doc_begin_annot (pdf_obj *dict)
2665
breaking_state.annot_dict = dict;
2666
breaking_state.broken = 0;
2671
pdf_doc_end_annot (void)
2673
pdf_doc_break_annot();
2674
breaking_state.annot_dict = NULL;
2678
pdf_doc_break_annot (void)
2680
if (breaking_state.dirty) {
2681
pdf_obj *annot_dict;
2684
annot_dict = pdf_new_dict();
2685
pdf_merge_dict(annot_dict, breaking_state.annot_dict);
2686
pdf_doc_add_annot(pdf_doc_current_page_number(), &(breaking_state.rect),
2687
annot_dict, !breaking_state.broken);
2688
pdf_release_obj(annot_dict);
2690
breaking_state.broken = 1;
2696
pdf_doc_expand_box (const pdf_rect *rect)
2698
breaking_state.rect.llx = MIN(breaking_state.rect.llx, rect->llx);
2699
breaking_state.rect.lly = MIN(breaking_state.rect.lly, rect->lly);
2700
breaking_state.rect.urx = MAX(breaking_state.rect.urx, rect->urx);
2701
breaking_state.rect.ury = MAX(breaking_state.rect.ury, rect->ury);
2702
breaking_state.dirty = 1;
2706
/* This should be number tree */
2708
pdf_doc_set_pagelabel (long pg_start,
2710
const void *prefix, int prfx_len, long start)
2713
pdf_obj *label_dict;
2715
if (!p->root.pagelabels)
2716
p->root.pagelabels = pdf_new_array();
2718
label_dict = pdf_new_dict();
2719
if (!type || type[0] == '\0') /* Set back to default. */
2720
pdf_add_dict(label_dict, pdf_new_name("S"), pdf_new_name("D"));
2723
pdf_add_dict(label_dict, pdf_new_name("S"), pdf_new_name(type));
2724
if (prefix && prfx_len > 0)
2725
pdf_add_dict(label_dict,
2727
pdf_new_string(prefix, prfx_len));
2729
pdf_add_dict(label_dict,
2730
pdf_new_name("St"), pdf_new_number(start));
2733
pdf_add_array(p->root.pagelabels, pdf_new_number(pg_start));
2734
pdf_add_array(p->root.pagelabels, label_dict);