1 //========================================================================
5 // Copyright 2001-2007 Glyph & Cog, LLC
7 //========================================================================
15 #include "parseargs.h"
18 #include "GlobalParams.h"
27 // NB: this must match the definition of GfxFontType in GfxFont.h.
28 static char *fontTypeNames
[] = {
43 static void scanFonts(Dict
*resDict
, PDFDoc
*doc
);
44 static void scanFont(GfxFont
*font
, PDFDoc
*doc
);
46 static int firstPage
= 1;
47 static int lastPage
= 0;
48 static char ownerPassword
[33] = "\001";
49 static char userPassword
[33] = "\001";
50 static char cfgFileName
[256] = "";
51 static GBool printVersion
= gFalse
;
52 static GBool printHelp
= gFalse
;
54 static ArgDesc argDesc
[] = {
55 {"-f", argInt
, &firstPage
, 0,
56 "first page to examine"},
57 {"-l", argInt
, &lastPage
, 0,
58 "last page to examine"},
59 {"-opw", argString
, ownerPassword
, sizeof(ownerPassword
),
60 "owner password (for encrypted files)"},
61 {"-upw", argString
, userPassword
, sizeof(userPassword
),
62 "user password (for encrypted files)"},
63 {"-cfg", argString
, cfgFileName
, sizeof(cfgFileName
),
64 "configuration file to use in place of .xpdfrc"},
65 {"-v", argFlag
, &printVersion
, 0,
66 "print copyright and version info"},
67 {"-h", argFlag
, &printHelp
, 0,
68 "print usage information"},
69 {"-help", argFlag
, &printHelp
, 0,
70 "print usage information"},
71 {"--help", argFlag
, &printHelp
, 0,
72 "print usage information"},
73 {"-?", argFlag
, &printHelp
, 0,
74 "print usage information"},
82 int main(int argc
, char *argv
[]) {
85 GString
*ownerPW
, *userPW
;
97 ok
= parseArgs(argDesc
, &argc
, argv
);
98 if (!ok
|| argc
!= 2 || printVersion
|| printHelp
) {
99 fprintf(stderr
, "pdffonts version %s\n", xpdfVersion
);
100 fprintf(stderr
, "%s\n", xpdfCopyright
);
102 printUsage("pdffonts", "<PDF-file>", argDesc
);
106 fileName
= new GString(argv
[1]);
109 globalParams
= new GlobalParams(cfgFileName
);
112 if (ownerPassword
[0] != '\001') {
113 ownerPW
= new GString(ownerPassword
);
117 if (userPassword
[0] != '\001') {
118 userPW
= new GString(userPassword
);
122 doc
= new PDFDoc(fileName
, ownerPW
, userPW
);
138 if (lastPage
< 1 || lastPage
> doc
->getNumPages()) {
139 lastPage
= doc
->getNumPages();
143 printf("name type emb sub uni xObject ID\n");
144 printf("------------------------------------ ----------------- --- --- --- ---------\n");
146 fontsLen
= fontsSize
= 0;
147 for (pg
= firstPage
; pg
<= lastPage
; ++pg
) {
148 page
= doc
->getCatalog()->getPage(pg
);
149 if ((resDict
= page
->getResourceDict())) {
150 scanFonts(resDict
, doc
);
152 annots
= new Annots(doc
->getXRef(), doc
->getCatalog(),
153 page
->getAnnots(&obj1
));
155 for (i
= 0; i
< annots
->getNumAnnots(); ++i
) {
156 if (annots
->getAnnot(i
)->getAppearance(&obj1
)->isStream()) {
157 obj1
.streamGetDict()->lookup("Resources", &obj2
);
159 scanFonts(obj2
.getDict(), doc
);
177 // check for memory leaks
178 xObject::memCheck(stderr
);
184 static void scanFonts(Dict
*resDict
, PDFDoc
*doc
) {
185 xObject obj1
, obj2
, xObjDict
, xObj
, resObj
;
187 GfxFontDict
*gfxFontDict
;
191 // scan the fonts in this resource dictionary
193 resDict
->lookupNF("Font", &obj1
);
195 obj1
.fetch(doc
->getXRef(), &obj2
);
198 gfxFontDict
= new GfxFontDict(doc
->getXRef(), &r
, obj2
.getDict());
201 } else if (obj1
.isDict()) {
202 gfxFontDict
= new GfxFontDict(doc
->getXRef(), NULL
, obj1
.getDict());
205 for (i
= 0; i
< gfxFontDict
->getNumFonts(); ++i
) {
206 if ((font
= gfxFontDict
->getFont(i
))) {
214 // recursively scan any resource dictionaries in xObjects in this
215 // resource dictionary
216 resDict
->lookup("XObject", &xObjDict
);
217 if (xObjDict
.isDict()) {
218 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
219 xObjDict
.dictGetVal(i
, &xObj
);
220 if (xObj
.isStream()) {
221 xObj
.streamGetDict()->lookup("Resources", &resObj
);
222 if (resObj
.isDict()) {
223 scanFonts(resObj
.getDict(), doc
);
233 static void scanFont(GfxFont
*font
, PDFDoc
*doc
) {
235 xObject fontObj
, toUnicodeObj
;
237 GBool emb
, subset
, hasToUnicode
;
240 fontRef
= *font
->getID();
242 // check for an already-seen font
243 for (i
= 0; i
< fontsLen
; ++i
) {
244 if (fontRef
.num
== fonts
[i
].num
&& fontRef
.gen
== fonts
[i
].gen
) {
250 name
= font
->getOrigName();
252 // check for an embedded font
253 if (font
->getType() == fontType3
) {
256 emb
= font
->getEmbeddedFontID(&embRef
);
259 // look for a ToUnicode map
260 hasToUnicode
= gFalse
;
261 if (doc
->getXRef()->fetch(fontRef
.num
, fontRef
.gen
, &fontObj
)->isDict()) {
262 hasToUnicode
= fontObj
.dictLookup("ToUnicode", &toUnicodeObj
)->isStream();
267 // check for a font subset name: capital letters followed by a '+'
271 for (i
= 0; i
< name
->getLength(); ++i
) {
272 if (name
->getChar(i
) < 'A' || name
->getChar(i
) > 'Z') {
276 subset
= i
> 0 && i
< name
->getLength() && name
->getChar(i
) == '+';
279 // print the font info
280 printf("%-36s %-17s %-3s %-3s %-3s",
281 name
? name
->getCString() : "[none]",
282 fontTypeNames
[font
->getType()],
284 subset
? "yes" : "no",
285 hasToUnicode
? "yes" : "no");
286 if (fontRef
.gen
>= 100000) {
289 printf(" %6d %2d\n", fontRef
.num
, fontRef
.gen
);
292 // add this font to the list
293 if (fontsLen
== fontsSize
) {
295 fonts
= (Ref
*)greallocn(fonts
, fontsSize
, sizeof(Ref
));
297 fonts
[fontsLen
++] = *font
->getID();