]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/pdfinfo.cc
4a50fee2afe6f928b96bce2309847c5ee315f577
[evince.git] / pdf / xpdf / pdfinfo.cc
1 //========================================================================
2 //
3 // pdfinfo.cc
4 //
5 // Copyright 1998-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stddef.h>
13 #include <string.h>
14 #include <time.h>
15 #include <math.h>
16 #include "parseargs.h"
17 #include "GString.h"
18 #include "gmem.h"
19 #include "GlobalParams.h"
20 #include "Object.h"
21 #include "Stream.h"
22 #include "Array.h"
23 #include "Dict.h"
24 #include "XRef.h"
25 #include "Catalog.h"
26 #include "Page.h"
27 #include "PDFDoc.h"
28 #include "CharTypes.h"
29 #include "UnicodeMap.h"
30 #include "Error.h"
31 #include "config.h"
32
33 static void printInfoString(Dict *infoDict, char *key, char *text,
34                             UnicodeMap *uMap);
35 static void printInfoDate(Dict *infoDict, char *key, char *text);
36 static void printBox(char *text, PDFRectangle *box);
37
38 static int firstPage = 1;
39 static int lastPage = 0;
40 static GBool printBoxes = gFalse;
41 static GBool printMetadata = gFalse;
42 static char textEncName[128] = "";
43 static char ownerPassword[33] = "\001";
44 static char userPassword[33] = "\001";
45 static char cfgFileName[256] = "";
46 static GBool printVersion = gFalse;
47 static GBool printHelp = gFalse;
48
49 static ArgDesc argDesc[] = {
50   {"-f",      argInt,      &firstPage,        0,
51    "first page to convert"},
52   {"-l",      argInt,      &lastPage,         0,
53    "last page to convert"},
54   {"-box",    argFlag,     &printBoxes,       0,
55    "print the page bounding boxes"},
56   {"-meta",   argFlag,     &printMetadata,    0,
57    "print the document metadata (XML)"},
58   {"-enc",    argString,   textEncName,    sizeof(textEncName),
59    "output text encoding name"},
60   {"-opw",    argString,   ownerPassword,  sizeof(ownerPassword),
61    "owner password (for encrypted files)"},
62   {"-upw",    argString,   userPassword,   sizeof(userPassword),
63    "user password (for encrypted files)"},
64   {"-cfg",        argString,      cfgFileName,    sizeof(cfgFileName),
65    "configuration file to use in place of .xpdfrc"},
66   {"-v",      argFlag,     &printVersion,  0,
67    "print copyright and version info"},
68   {"-h",      argFlag,     &printHelp,     0,
69    "print usage information"},
70   {"-help",   argFlag,     &printHelp,     0,
71    "print usage information"},
72   {"--help",  argFlag,     &printHelp,     0,
73    "print usage information"},
74   {"-?",      argFlag,     &printHelp,     0,
75    "print usage information"},
76   {NULL}
77 };
78
79 int main(int argc, char *argv[]) {
80   PDFDoc *doc;
81   GString *fileName;
82   GString *ownerPW, *userPW;
83   UnicodeMap *uMap;
84   Page *page;
85   Object info;
86   char buf[256];
87   double w, h, wISO, hISO;
88   FILE *f;
89   GString *metadata;
90   GBool ok;
91   int exitCode;
92   int pg, i;
93   GBool multiPage;
94
95   exitCode = 99;
96
97   // parse args
98   ok = parseArgs(argDesc, &argc, argv);
99   if (!ok || argc != 2 || printVersion || printHelp) {
100     fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
101     fprintf(stderr, "%s\n", xpdfCopyright);
102     if (!printVersion) {
103       printUsage("pdfinfo", "<PDF-file>", argDesc);
104     }
105     goto err0;
106   }
107   fileName = new GString(argv[1]);
108
109   // read config file
110   globalParams = new GlobalParams(cfgFileName);
111   if (textEncName[0]) {
112     globalParams->setTextEncoding(textEncName);
113   }
114
115   // get mapping to output encoding
116   if (!(uMap = globalParams->getTextEncoding())) {
117     error(-1, "Couldn't get text encoding");
118     delete fileName;
119     goto err1;
120   }
121
122   // open PDF file
123   if (ownerPassword[0] != '\001') {
124     ownerPW = new GString(ownerPassword);
125   } else {
126     ownerPW = NULL;
127   }
128   if (userPassword[0] != '\001') {
129     userPW = new GString(userPassword);
130   } else {
131     userPW = NULL;
132   }
133   doc = new PDFDoc(fileName, ownerPW, userPW);
134   if (userPW) {
135     delete userPW;
136   }
137   if (ownerPW) {
138     delete ownerPW;
139   }
140   if (!doc->isOk()) {
141     exitCode = 1;
142     goto err2;
143   }
144
145   // get page range
146   if (firstPage < 1) {
147     firstPage = 1;
148   }
149   if (lastPage == 0) {
150     multiPage = gFalse;
151     lastPage = 1;
152   } else {
153     multiPage = gTrue;
154   }
155   if (lastPage < 1 || lastPage > doc->getNumPages()) {
156     lastPage = doc->getNumPages();
157   }
158
159   // print doc info
160   doc->getDocInfo(&info);
161   if (info.isDict()) {
162     printInfoString(info.getDict(), "Title",        "Title:          ", uMap);
163     printInfoString(info.getDict(), "Subject",      "Subject:        ", uMap);
164     printInfoString(info.getDict(), "Keywords",     "Keywords:       ", uMap);
165     printInfoString(info.getDict(), "Author",       "Author:         ", uMap);
166     printInfoString(info.getDict(), "Creator",      "Creator:        ", uMap);
167     printInfoString(info.getDict(), "Producer",     "Producer:       ", uMap);
168     printInfoDate(info.getDict(),   "CreationDate", "CreationDate:   ");
169     printInfoDate(info.getDict(),   "ModDate",      "ModDate:        ");
170   }
171   info.free();
172
173   // print tagging info
174   printf("Tagged:         %s\n",
175          doc->getStructTreeRoot()->isDict() ? "yes" : "no");
176
177   // print page count
178   printf("Pages:          %d\n", doc->getNumPages());
179
180   // print encryption info
181   printf("Encrypted:      ");
182   if (doc->isEncrypted()) {
183     printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
184            doc->okToPrint(gTrue) ? "yes" : "no",
185            doc->okToCopy(gTrue) ? "yes" : "no",
186            doc->okToChange(gTrue) ? "yes" : "no",
187            doc->okToAddNotes(gTrue) ? "yes" : "no");
188   } else {
189     printf("no\n");
190   }
191
192   // print page size
193   for (pg = firstPage; pg <= lastPage; ++pg) {
194     w = doc->getPageWidth(pg);
195     h = doc->getPageHeight(pg);
196     if (multiPage) {
197       printf("Page %4d size: %g x %g pts", pg, w, h);
198     } else {
199       printf("Page size:      %g x %g pts", w, h);
200     }
201     if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) ||
202         (fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) {
203       printf(" (letter)");
204     } else {
205       hISO = sqrt(sqrt(2.0)) * 7200 / 2.54;
206       wISO = hISO / sqrt(2.0);
207       for (i = 0; i <= 6; ++i) {
208         if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) ||
209             (fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) {
210           printf(" (A%d)", i);
211           break;
212         }
213         hISO = wISO;
214         wISO /= sqrt(2.0);
215       }
216     }
217     printf("\n");
218   } 
219
220   // print the boxes
221   if (printBoxes) {
222     if (multiPage) {
223       for (pg = firstPage; pg <= lastPage; ++pg) {
224         page = doc->getCatalog()->getPage(pg);
225         sprintf(buf, "Page %4d MediaBox: ", pg);
226         printBox(buf, page->getMediaBox());
227         sprintf(buf, "Page %4d CropBox:  ", pg);
228         printBox(buf, page->getCropBox());
229         sprintf(buf, "Page %4d BleedBox: ", pg);
230         printBox(buf, page->getBleedBox());
231         sprintf(buf, "Page %4d TrimBox:  ", pg);
232         printBox(buf, page->getTrimBox());
233         sprintf(buf, "Page %4d ArtBox:   ", pg);
234         printBox(buf, page->getArtBox());
235       }
236     } else {
237       page = doc->getCatalog()->getPage(firstPage);
238       printBox("MediaBox:       ", page->getMediaBox());
239       printBox("CropBox:        ", page->getCropBox());
240       printBox("BleedBox:       ", page->getBleedBox());
241       printBox("TrimBox:        ", page->getTrimBox());
242       printBox("ArtBox:         ", page->getArtBox());
243     }
244   }
245
246   // print file size
247 #ifdef VMS
248   f = fopen(fileName->getCString(), "rb", "ctx=stm");
249 #else
250   f = fopen(fileName->getCString(), "rb");
251 #endif
252   if (f) {
253 #if HAVE_FSEEKO
254     fseeko(f, 0, SEEK_END);
255     printf("File size:      %u bytes\n", (Guint)ftello(f));
256 #elif HAVE_FSEEK64
257     fseek64(f, 0, SEEK_END);
258     printf("File size:      %u bytes\n", (Guint)ftell64(f));
259 #else
260     fseek(f, 0, SEEK_END);
261     printf("File size:      %d bytes\n", (int)ftell(f));
262 #endif
263     fclose(f);
264   }
265
266   // print linearization info
267   printf("Optimized:      %s\n", doc->isLinearized() ? "yes" : "no");
268
269   // print PDF version
270   printf("PDF version:    %.1f\n", doc->getPDFVersion());
271
272   // print the metadata
273   if (printMetadata && (metadata = doc->readMetadata())) {
274     fputs("Metadata:\n", stdout);
275     fputs(metadata->getCString(), stdout);
276     fputc('\n', stdout);
277     delete metadata;
278   }
279
280   exitCode = 0;
281
282   // clean up
283  err2:
284   uMap->decRefCnt();
285   delete doc;
286  err1:
287   delete globalParams;
288  err0:
289
290   // check for memory leaks
291   Object::memCheck(stderr);
292   gMemReport(stderr);
293
294   return exitCode;
295 }
296
297 static void printInfoString(Dict *infoDict, char *key, char *text,
298                             UnicodeMap *uMap) {
299   Object obj;
300   GString *s1;
301   GBool isUnicode;
302   Unicode u;
303   char buf[8];
304   int i, n;
305
306   if (infoDict->lookup(key, &obj)->isString()) {
307     fputs(text, stdout);
308     s1 = obj.getString();
309     if ((s1->getChar(0) & 0xff) == 0xfe &&
310         (s1->getChar(1) & 0xff) == 0xff) {
311       isUnicode = gTrue;
312       i = 2;
313     } else {
314       isUnicode = gFalse;
315       i = 0;
316     }
317     while (i < obj.getString()->getLength()) {
318       if (isUnicode) {
319         u = ((s1->getChar(i) & 0xff) << 8) |
320             (s1->getChar(i+1) & 0xff);
321         i += 2;
322       } else {
323         u = s1->getChar(i) & 0xff;
324         ++i;
325       }
326       n = uMap->mapUnicode(u, buf, sizeof(buf));
327       fwrite(buf, 1, n, stdout);
328     }
329     fputc('\n', stdout);
330   }
331   obj.free();
332 }
333
334 static void printInfoDate(Dict *infoDict, char *key, char *text) {
335   Object obj;
336   char *s;
337   int year, mon, day, hour, min, sec;
338   struct tm tmStruct;
339   char buf[256];
340
341   if (infoDict->lookup(key, &obj)->isString()) {
342     fputs(text, stdout);
343     s = obj.getString()->getCString();
344     if (s[0] == 'D' && s[1] == ':') {
345       s += 2;
346     }
347     if (sscanf(s, "%4d%2d%2d%2d%2d%2d",
348                &year, &mon, &day, &hour, &min, &sec) == 6) {
349       tmStruct.tm_year = year - 1900;
350       tmStruct.tm_mon = mon - 1;
351       tmStruct.tm_mday = day;
352       tmStruct.tm_hour = hour;
353       tmStruct.tm_min = min;
354       tmStruct.tm_sec = sec;
355       tmStruct.tm_wday = -1;
356       tmStruct.tm_yday = -1;
357       tmStruct.tm_isdst = -1;
358       // compute the tm_wday and tm_yday fields
359       if (mktime(&tmStruct) != (time_t)-1 &&
360           strftime(buf, sizeof(buf), "%c", &tmStruct)) {
361         fputs(buf, stdout);
362       } else {
363         fputs(s, stdout);
364       }
365     } else {
366       fputs(s, stdout);
367     }
368     fputc('\n', stdout);
369   }
370   obj.free();
371 }
372
373 static void printBox(char *text, PDFRectangle *box) {
374   printf("%s%8.2f %8.2f %8.2f %8.2f\n",
375          text, box->x1, box->y1, box->x2, box->y2);
376 }