]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/pdffonts.cc
2f17995cea97bdd8bb0db906d8837e944a238a51
[evince.git] / pdf / xpdf / pdffonts.cc
1 //========================================================================
2 //
3 // pdffonts.cc
4 //
5 // Copyright 2001-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 <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] = "\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 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   int exitCode;
88
89   exitCode = 99;
90
91   // parse args
92   ok = parseArgs(argDesc, &argc, argv);
93   if (!ok || argc != 2 || printVersion || printHelp) {
94     fprintf(stderr, "pdffonts version %s\n", xpdfVersion);
95     fprintf(stderr, "%s\n", xpdfCopyright);
96     if (!printVersion) {
97       printUsage("pdffonts", "<PDF-file>", argDesc);
98     }
99     goto err0;
100   }
101   fileName = new GString(argv[1]);
102
103   // read config file
104   globalParams = new GlobalParams(cfgFileName);
105
106   // open PDF file
107   if (ownerPassword[0] != '\001') {
108     ownerPW = new GString(ownerPassword);
109   } else {
110     ownerPW = NULL;
111   }
112   if (userPassword[0] != '\001') {
113     userPW = new GString(userPassword);
114   } else {
115     userPW = NULL;
116   }
117   doc = new PDFDoc(fileName, ownerPW, userPW);
118   if (userPW) {
119     delete userPW;
120   }
121   if (ownerPW) {
122     delete ownerPW;
123   }
124   if (!doc->isOk()) {
125     exitCode = 1;
126     goto err1;
127   }
128
129   // get page range
130   if (firstPage < 1) {
131     firstPage = 1;
132   }
133   if (lastPage < 1 || lastPage > doc->getNumPages()) {
134     lastPage = doc->getNumPages();
135   }
136
137   // scan the fonts
138   printf("name                                 type         emb sub uni object ID\n");
139   printf("------------------------------------ ------------ --- --- --- ---------\n");
140   fonts = NULL;
141   fontsLen = fontsSize = 0;
142   for (pg = firstPage; pg <= lastPage; ++pg) {
143     page = doc->getCatalog()->getPage(pg);
144     if ((resDict = page->getResourceDict())) {
145       scanFonts(resDict, doc);
146     }
147     annots = new Annots(doc->getXRef(), page->getAnnots(&obj1));
148     obj1.free();
149     for (i = 0; i < annots->getNumAnnots(); ++i) {
150       if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
151         obj1.streamGetDict()->lookup("Resources", &obj2);
152         if (obj2.isDict()) {
153           scanFonts(obj2.getDict(), doc);
154         }
155         obj2.free();
156       }
157       obj1.free();
158     }
159     delete annots;
160   }
161
162   exitCode = 0;
163
164   // clean up
165   gfree(fonts);
166  err1:
167   delete doc;
168   delete globalParams;
169  err0:
170
171   // check for memory leaks
172   Object::memCheck(stderr);
173   gMemReport(stderr);
174
175   return exitCode;
176 }
177
178 static void scanFonts(Dict *resDict, PDFDoc *doc) {
179   Object obj1, obj2, xObjDict, xObj, resObj;
180   Ref r;
181   GfxFontDict *gfxFontDict;
182   GfxFont *font;
183   int i;
184
185   // scan the fonts in this resource dictionary
186   gfxFontDict = NULL;
187   resDict->lookupNF("Font", &obj1);
188   if (obj1.isRef()) {
189     obj1.fetch(doc->getXRef(), &obj2);
190     if (obj2.isDict()) {
191       r = obj1.getRef();
192       gfxFontDict = new GfxFontDict(doc->getXRef(), &r, obj2.getDict());
193     }
194     obj2.free();
195   } else if (obj1.isDict()) {
196     gfxFontDict = new GfxFontDict(doc->getXRef(), NULL, obj1.getDict());
197   }
198   if (gfxFontDict) {
199     for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
200       if ((font = gfxFontDict->getFont(i))) {
201         scanFont(font, doc);
202       }
203     }
204     delete gfxFontDict;
205   }
206   obj1.free();
207
208   // recursively scan any resource dictionaries in objects in this
209   // resource dictionary
210   resDict->lookup("XObject", &xObjDict);
211   if (xObjDict.isDict()) {
212     for (i = 0; i < xObjDict.dictGetLength(); ++i) {
213       xObjDict.dictGetVal(i, &xObj);
214       if (xObj.isStream()) {
215         xObj.streamGetDict()->lookup("Resources", &resObj);
216         if (resObj.isDict()) {
217           scanFonts(resObj.getDict(), doc);
218         }
219         resObj.free();
220       }
221       xObj.free();
222     }
223   }
224   xObjDict.free();
225 }
226
227 static void scanFont(GfxFont *font, PDFDoc *doc) {
228   Ref fontRef, embRef;
229   Object fontObj, toUnicodeObj;
230   GString *name;
231   GBool emb, subset, hasToUnicode;
232   int i;
233
234   fontRef = *font->getID();
235
236   // check for an already-seen font
237   for (i = 0; i < fontsLen; ++i) {
238     if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) {
239       return;
240     }
241   }
242
243   // font name
244   name = font->getOrigName();
245
246   // check for an embedded font
247   if (font->getType() == fontType3) {
248     emb = gTrue;
249   } else {
250     emb = font->getEmbeddedFontID(&embRef);
251   }
252
253   // look for a ToUnicode map
254   hasToUnicode = gFalse;
255   if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
256     hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
257     toUnicodeObj.free();
258   }
259   fontObj.free();
260
261   // check for a font subset name: capital letters followed by a '+'
262   // sign
263   subset = gFalse;
264   if (name) {
265     for (i = 0; i < name->getLength(); ++i) {
266       if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
267         break;
268       }
269     }
270     subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
271   }
272
273   // print the font info
274   printf("%-36s %-12s %-3s %-3s %-3s",
275          name ? name->getCString() : "[none]",
276          fontTypeNames[font->getType()],
277          emb ? "yes" : "no",
278          subset ? "yes" : "no",
279          hasToUnicode ? "yes" : "no");
280   if (fontRef.gen >= 100000) {
281     printf(" [none]\n");
282   } else {
283     printf(" %6d %2d\n", fontRef.num, fontRef.gen);
284   }
285
286   // add this font to the list
287   if (fontsLen == fontsSize) {
288     fontsSize += 32;
289     fonts = (Ref *)grealloc(fonts, fontsSize * sizeof(Ref));
290   }
291   fonts[fontsLen++] = *font->getID();
292 }