filters

pdffonts.cpp
1//========================================================================
2//
3// pdffonts.cpp
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
27static 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
38static void scanFonts(Dict *resDict, PDFDoc *doc);
39static void scanFont(GfxFont *font, PDFDoc *doc);
40
41static int firstPage = 1;
42static int lastPage = 0;
43static char ownerPassword[33] = "";
44static char userPassword[33] = "";
45static char cfgFileName[256] = "";
46static GBool printVersion = gFalse;
47static GBool printHelp = gFalse;
48
49static 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
73static Ref *fonts;
74static int fontsLen;
75static int fontsSize;
76
77int 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, "pdfinfo version %s\n", xpdfVersion);
95 fprintf(stderr, "%s\n", xpdfCopyright);
96 if (!printVersion) {
97 printUsage("pdfinfo", "<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]) {
108 ownerPW = new GString(ownerPassword);
109 } else {
110 ownerPW = NULL;
111 }
112 if (userPassword[0]) {
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
178static void scanFonts(Dict *resDict, PDFDoc *doc) {
179 GfxFontDict *gfxFontDict;
180 GfxFont *font;
181 Object fontDict, xObjDict, xObj, resObj;
182 int i;
183
184 // scan the fonts in this resource dictionary
185 resDict->lookup("Font", &fontDict);
186 if (fontDict.isDict()) {
187 gfxFontDict = new GfxFontDict(doc->getXRef(), fontDict.getDict());
188 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
189 font = gfxFontDict->getFont(i);
190 scanFont(font, doc);
191 }
192 delete gfxFontDict;
193 }
194 fontDict.free();
195
196 // recursively scan any resource dictionaries in objects in this
197 // resource dictionary
198 resDict->lookup("XObject", &xObjDict);
199 if (xObjDict.isDict()) {
200 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
201 xObjDict.dictGetVal(i, &xObj);
202 if (xObj.isStream()) {
203 xObj.streamGetDict()->lookup("Resources", &resObj);
204 if (resObj.isDict()) {
205 scanFonts(resObj.getDict(), doc);
206 }
207 resObj.free();
208 }
209 xObj.free();
210 }
211 }
212 xObjDict.free();
213}
214
215static void scanFont(GfxFont *font, PDFDoc *doc) {
216 Ref fontRef, embRef;
217 Object fontObj, nameObj, toUnicodeObj;
218 GString *name;
219 GBool subset, hasToUnicode;
220 int i;
221
222 fontRef = *font->getID();
223
224 // check for an already-seen font
225 for (i = 0; i < fontsLen; ++i) {
226 if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) {
227 return;
228 }
229 }
230
231 // get the original font name -- the GfxFont class munges substitute
232 // Base-14 font names into proper form, so this code grabs the
233 // original name from the font dictionary; also look for a ToUnicode
234 // map
235 name = NULL;
236 hasToUnicode = gFalse;
237 if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
238 if (fontObj.dictLookup("BaseFont", &nameObj)->isName()) {
239 name = new GString(nameObj.getName());
240 }
241 nameObj.free();
242 hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
243 toUnicodeObj.free();
244 }
245 fontObj.free();
246
247 // check for a font subset name: capital letters followed by a '+'
248 // sign
249 subset = gFalse;
250 if (name) {
251 for (i = 0; i < name->getLength(); ++i) {
252 if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
253 break;
254 }
255 }
256 subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
257 }
258
259 // print the font info
260 printf("%-36s %-12s %-3s %-3s %-3s",
261 name ? name->getCString() : "[none]",
262 fontTypeNames[font->getType()],
263 font->getEmbeddedFontID(&embRef) ? "yes" : "no",
264 subset ? "yes" : "no",
265 hasToUnicode ? "yes" : "no");
266 if (fontRef.gen == 999999) {
267 printf(" [none]\n");
268 } else {
269 printf(" %6d %2d\n", fontRef.num, fontRef.gen);
270 }
271 if (name) {
272 delete name;
273 }
274
275 // add this font to the list
276 if (fontsLen == fontsSize) {
277 fontsSize += 32;
278 fonts = (Ref *)grealloc(fonts, fontsSize * sizeof(Ref));
279 }
280 fonts[fontsLen++] = *font->getID();
281}