]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/pdffonts.cc
Synched with Xpdf 1.01
[evince.git] / pdf / xpdf / pdffonts.cc
1 //========================================================================
2 //
3 // pdffonts.cc
4 //
5 // Copyright 2001-2002 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 <math.h>
15 #include "parseargs.h"
16 #include "GString.h"
17 #include "gmem.h"
18 #include "GlobalParams.h"
19 #include "Error.h"
20 #include "Object.h"
21 #include "Dict.h"
22 #include "GfxFont.h"
23 #include "Annot.h"
24 #include "PDFDoc.h"
25 #include "config.h"
26
27 static char *fontTypeNames[] = {
28   "unknown",
29   "Type 1",
30   "Type 1C",
31   "Type 3",
32   "TrueType",
33   "CID Type 0",
34   "CID Type 0C",
35   "CID TrueType"
36 };
37
38 static void scanFonts(Dict *resDict, PDFDoc *doc);
39 static void scanFont(GfxFont *font, PDFDoc *doc);
40
41 static int firstPage = 1;
42 static int lastPage = 0;
43 static char ownerPassword[33] = "";
44 static char userPassword[33] = "";
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 examine"},
52   {"-l",      argInt,      &lastPage,      0,
53    "last page to examine"},
54   {"-opw",    argString,   ownerPassword,  sizeof(ownerPassword),
55    "owner password (for encrypted files)"},
56   {"-upw",    argString,   userPassword,   sizeof(userPassword),
57    "user password (for encrypted files)"},
58   {"-cfg",        argString,      cfgFileName,    sizeof(cfgFileName),
59    "configuration file to use in place of .xpdfrc"},
60   {"-v",      argFlag,     &printVersion,  0,
61    "print copyright and version info"},
62   {"-h",      argFlag,     &printHelp,     0,
63    "print usage information"},
64   {"-help",   argFlag,     &printHelp,     0,
65    "print usage information"},
66   {"--help",  argFlag,     &printHelp,     0,
67    "print usage information"},
68   {"-?",      argFlag,     &printHelp,     0,
69    "print usage information"},
70   {NULL}
71 };
72
73 static Ref *fonts;
74 static int fontsLen;
75 static int fontsSize;
76
77 int main(int argc, char *argv[]) {
78   PDFDoc *doc;
79   GString *fileName;
80   GString *ownerPW, *userPW;
81   GBool ok;
82   Page *page;
83   Dict *resDict;
84   Annots *annots;
85   Object obj1, obj2;
86   int pg, i;
87
88   // parse args
89   ok = parseArgs(argDesc, &argc, argv);
90   if (!ok || argc != 2 || printVersion || printHelp) {
91     fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
92     fprintf(stderr, "%s\n", xpdfCopyright);
93     if (!printVersion) {
94       printUsage("pdfinfo", "<PDF-file>", argDesc);
95     }
96     exit(1);
97   }
98   fileName = new GString(argv[1]);
99
100   // read config file
101   globalParams = new GlobalParams(cfgFileName);
102
103   // open PDF file
104   if (ownerPassword[0]) {
105     ownerPW = new GString(ownerPassword);
106   } else {
107     ownerPW = NULL;
108   }
109   if (userPassword[0]) {
110     userPW = new GString(userPassword);
111   } else {
112     userPW = NULL;
113   }
114   doc = new PDFDoc(fileName, ownerPW, userPW);
115   if (userPW) {
116     delete userPW;
117   }
118   if (ownerPW) {
119     delete ownerPW;
120   }
121   if (!doc->isOk()) {
122     exit(1);
123   }
124
125   // get page range
126   if (firstPage < 1) {
127     firstPage = 1;
128   }
129   if (lastPage < 1 || lastPage > doc->getNumPages()) {
130     lastPage = doc->getNumPages();
131   }
132
133   // scan the fonts
134   printf("name                                 type         emb sub uni object ID\n");
135   printf("------------------------------------ ------------ --- --- --- ---------\n");
136   fonts = NULL;
137   fontsLen = fontsSize = 0;
138   for (pg = firstPage; pg <= lastPage; ++pg) {
139     page = doc->getCatalog()->getPage(pg);
140     if ((resDict = page->getResourceDict())) {
141       scanFonts(resDict, doc);
142     }
143     annots = new Annots(doc->getXRef(), page->getAnnots(&obj1));
144     obj1.free();
145     for (i = 0; i < annots->getNumAnnots(); ++i) {
146       if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
147         obj1.streamGetDict()->lookup("Resources", &obj2);
148         if (obj2.isDict()) {
149           scanFonts(obj2.getDict(), doc);
150         }
151         obj2.free();
152       }
153       obj1.free();
154     }
155     delete annots;
156   }
157
158   // clean up
159   gfree(fonts);
160   delete doc;
161   delete globalParams;
162
163   // check for memory leaks
164   Object::memCheck(stderr);
165   gMemReport(stderr);
166
167   return 0;
168 }
169
170 static void scanFonts(Dict *resDict, PDFDoc *doc) {
171   GfxFontDict *gfxFontDict;
172   GfxFont *font;
173   Object fontDict, xObjDict, xObj, resObj;
174   int i;
175
176   // scan the fonts in this resource dictionary
177   resDict->lookup("Font", &fontDict);
178   if (fontDict.isDict()) {
179     gfxFontDict = new GfxFontDict(doc->getXRef(), fontDict.getDict());
180     for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
181       font = gfxFontDict->getFont(i);
182       scanFont(font, doc);
183     }
184     delete gfxFontDict;
185   }
186   fontDict.free();
187
188   // recursively scan any resource dictionaries in objects in this
189   // resource dictionary
190   resDict->lookup("XObject", &xObjDict);
191   if (xObjDict.isDict()) {
192     for (i = 0; i < xObjDict.dictGetLength(); ++i) {
193       xObjDict.dictGetVal(i, &xObj);
194       if (xObj.isStream()) {
195         xObj.streamGetDict()->lookup("Resources", &resObj);
196         if (resObj.isDict()) {
197           scanFonts(resObj.getDict(), doc);
198         }
199         resObj.free();
200       }
201       xObj.free();
202     }
203   }
204   xObjDict.free();
205 }
206
207 static void scanFont(GfxFont *font, PDFDoc *doc) {
208   Ref fontRef, embRef;
209   Object fontObj, nameObj, toUnicodeObj;
210   GString *name;
211   GBool subset, hasToUnicode;
212   int i;
213
214   fontRef = *font->getID();
215
216   // check for an already-seen font
217   for (i = 0; i < fontsLen; ++i) {
218     if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) {
219       return;
220     }
221   }
222
223   // get the original font name -- the GfxFont class munges substitute
224   // Base-14 font names into proper form, so this code grabs the
225   // original name from the font dictionary; also look for a ToUnicode
226   // map
227   name = NULL;
228   hasToUnicode = gFalse;
229   if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
230     if (fontObj.dictLookup("BaseFont", &nameObj)->isName()) {
231       name = new GString(nameObj.getName());
232     }
233     nameObj.free();
234     hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
235     toUnicodeObj.free();
236   }
237   fontObj.free();
238
239   // check for a font subset name: capital letters followed by a '+'
240   // sign
241   subset = gFalse;
242   if (name) {
243     for (i = 0; i < name->getLength(); ++i) {
244       if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
245         break;
246       }
247     }
248     subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
249   }
250
251   // print the font info
252   printf("%-36s %-12s %-3s %-3s %-3s %6d %2d\n",
253          name ? name->getCString() : "[none]",
254          fontTypeNames[font->getType()],
255          font->getEmbeddedFontID(&embRef) ? "yes" : "no",
256          subset ? "yes" : "no",
257          hasToUnicode ? "yes" : "no",
258          fontRef.num, fontRef.gen);
259   if (name) {
260     delete name;
261   }
262
263   // add this font to the list
264   if (fontsLen == fontsSize) {
265     fontsSize += 32;
266     fonts = (Ref *)grealloc(fonts, fontsSize * sizeof(Ref));
267   }
268   fonts[fontsLen++] = *font->getID();
269 }