1/*
2 * Information tool.
3 * Print information about pages of a pdf.
4 */
5
6#include "mupdf/fitz.h"
7#include "mupdf/pdf.h"
8
9#include <stdlib.h>
10#include <stdio.h>
11
12static void
13infousage(void)
14{
15 fprintf(stderr,
16 "usage: mutool pages [options] file.pdf [pages]\n"
17 "\t-p -\tpassword for decryption\n"
18 "\tpages\tcomma separated list of page numbers and ranges\n"
19 );
20 exit(1);
21}
22
23static int
24showbox(fz_context *ctx, fz_output *out, pdf_obj *page, char *text, pdf_obj *name)
25{
26 fz_rect bbox;
27 pdf_obj *obj;
28 int failed = 0;
29
30 fz_try(ctx)
31 {
32 obj = pdf_dict_get(ctx, page, name);
33 if (!pdf_is_array(ctx, obj))
34 break;
35
36 bbox = pdf_to_rect(ctx, obj);
37
38 fz_write_printf(ctx, out, "<%s l=\"%g\" b=\"%g\" r=\"%g\" t=\"%g\" />\n", text, bbox.x0, bbox.y0, bbox.x1, bbox.y1);
39 }
40 fz_catch(ctx)
41 {
42 failed = 1;
43 }
44
45 return failed;
46}
47
48static int
49shownum(fz_context *ctx, fz_output *out, pdf_obj *page, char *text, pdf_obj *name)
50{
51 pdf_obj *obj;
52 int failed = 0;
53
54 fz_try(ctx)
55 {
56 obj = pdf_dict_get(ctx, page, name);
57 if (!pdf_is_number(ctx, obj))
58 break;
59
60 fz_write_printf(ctx, out, "<%s v=\"%g\" />\n", text, pdf_to_real(ctx, obj));
61 }
62 fz_catch(ctx)
63 {
64 failed = 1;
65 }
66
67 return failed;
68}
69
70static int
71showpage(fz_context *ctx, pdf_document *doc, fz_output *out, int page)
72{
73 pdf_obj *pageref;
74 int failed = 0;
75
76 fz_write_printf(ctx, out, "<page pagenum=\"%d\">\n", page);
77 fz_try(ctx)
78 {
79 pageref = pdf_lookup_page_obj(ctx, doc, page-1);
80 if (!pageref)
81 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot retrieve info from page %d", page);
82 }
83 fz_catch(ctx)
84 {
85 fz_write_printf(ctx, out, "Failed to gather information for page %d\n", page);
86 failed = 1;
87 }
88
89 if (!failed)
90 {
91 failed |= showbox(ctx, out, pageref, "MediaBox", PDF_NAME(MediaBox));
92 failed |= showbox(ctx, out, pageref, "CropBox", PDF_NAME(CropBox));
93 failed |= showbox(ctx, out, pageref, "ArtBox", PDF_NAME(ArtBox));
94 failed |= showbox(ctx, out, pageref, "BleedBox", PDF_NAME(BleedBox));
95 failed |= showbox(ctx, out, pageref, "TrimBox", PDF_NAME(TrimBox));
96 failed |= shownum(ctx, out, pageref, "Rotate", PDF_NAME(Rotate));
97 failed |= shownum(ctx, out, pageref, "UserUnit", PDF_NAME(UserUnit));
98 }
99
100 fz_write_printf(ctx, out, "</page>\n");
101
102 return failed;
103}
104
105static int
106showpages(fz_context *ctx, pdf_document *doc, fz_output *out, const char *pagelist)
107{
108 int page, spage, epage;
109 int pagecount;
110 int ret = 0;
111
112 if (!doc)
113 infousage();
114
115 pagecount = pdf_count_pages(ctx, doc);
116 while ((pagelist = fz_parse_page_range(ctx, pagelist, &spage, &epage, pagecount)))
117 {
118 if (spage > epage)
119 page = spage, spage = epage, epage = page;
120 for (page = spage; page <= epage; page++)
121 ret |= showpage(ctx, doc, out, page);
122 }
123
124 return ret;
125}
126
127static int
128pdfpages_pages(fz_context *ctx, fz_output *out, char *filename, char *password, char *argv[], int argc)
129{
130 enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state;
131 int argidx = 0;
132 pdf_document *doc = NULL;
133 int ret = 0;
134
135 state = NO_FILE_OPENED;
136 while (argidx < argc)
137 {
138 if (state == NO_FILE_OPENED || !fz_is_page_range(ctx, argv[argidx]))
139 {
140 if (state == NO_INFO_GATHERED)
141 {
142 showpages(ctx, doc, out, "1-N");
143 }
144
145 pdf_drop_document(ctx, doc);
146
147 filename = argv[argidx];
148 fz_write_printf(ctx, out, "%s:\n", filename);
149 doc = pdf_open_document(ctx, filename);
150 if (pdf_needs_password(ctx, doc))
151 if (!pdf_authenticate_password(ctx, doc, password))
152 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot authenticate password: %s", filename);
153
154 state = NO_INFO_GATHERED;
155 }
156 else
157 {
158 ret |= showpages(ctx, doc, out, argv[argidx]);
159 state = INFO_SHOWN;
160 }
161
162 argidx++;
163 }
164
165 if (state == NO_INFO_GATHERED)
166 showpages(ctx, doc, out, "1-N");
167
168 pdf_drop_document(ctx, doc);
169
170 return ret;
171}
172
173int pdfpages_main(int argc, char **argv)
174{
175 char *filename = "";
176 char *password = "";
177 int c;
178 int ret;
179 fz_context *ctx;
180
181 while ((c = fz_getopt(argc, argv, "p:")) != -1)
182 {
183 switch (c)
184 {
185 case 'p': password = fz_optarg; break;
186 default:
187 infousage();
188 break;
189 }
190 }
191
192 if (fz_optind == argc)
193 infousage();
194
195 ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
196 if (!ctx)
197 {
198 fprintf(stderr, "cannot initialise context\n");
199 exit(1);
200 }
201
202 ret = 0;
203 fz_try(ctx)
204 ret = pdfpages_pages(ctx, fz_stdout(ctx), filename, password, &argv[fz_optind], argc-fz_optind);
205 fz_catch(ctx)
206 ret = 1;
207 fz_drop_context(ctx);
208 return ret;
209}
210