使用 PyPDF2 检测 Google Docs 生成的 PDF 文件中的非嵌入字体
Use PyPDF2 to detect non-embedded fonts in PDF file generated by Google Docs
我希望有人能帮我写一个 Python 函数来检测文件中没有嵌入文件中的任何字体。我尝试使用链接 here 的脚本,它可以检测文档字体,但它不检测嵌入的字体。为了方便起见,我粘贴了下面的脚本:
import sys
from PyPDF2 import PdfFileReader
fontkeys = set(["/FontFile", "/FontFile2", "/FontFile3"])
def walk(obj, fnt, emb):
if "/BaseFont" in obj:
fnt.add(obj["/BaseFont"])
elif "/FontName" in obj and fontkeys.intersection(set(obj)):
emb.add(obj["/FontName"])
for k in obj:
if hasattr(obj[k], "keys"):
walk(obj[k], fnt, emb)
return fnt, emb
if __name__ == "__main__":
file_name = sys.argv[1]
reader = PdfFileReader(file_name)
fonts = set()
embedded = set()
for page in reader.pages:
obj = page.getObject()
f, e = walk(obj["/Resources"], fonts, embedded)
fonts = fonts.union(f)
embedded = embedded.union(e)
unembedded = fonts - embedded
print("Font List")
print(sorted(list(fonts)))
if unembedded:
print("\nUnembedded Fonts")
print(unembedded)
例如,我从 Google Docs 下载了一个带有 Arial 字体的 PDF(输入一些内容,另存为 PDF),并且 Adobe Reader 已经确认嵌入了该字体。但是,脚本 returns ['/ArialMT'] 作为字体,并且为嵌入字体设置了一个空集。此外,看起来没有任何递归对象具有键 {'/FontFile', '/FontFile2', '/FontFile3'}
。我已经在其他 PDF 上尝试过它并且它有效,所以它一定与 Google Docs PDF 有一些奇怪之处。让我知道我可以为这个 PDF 文件提供哪些其他调试信息。
我想到的一件事是 Google Docs 可能只嵌入了 14 种标准 PDF 字体中没有的字体。但是,我尝试使用一种奇怪的字体 (pacifico),并且脚本还说明该字体未嵌入,而 Adobe 声称它是嵌入的。
我用 this PDF 试了一下,脚本正确地指出嵌入了这 14 种字体。
问题在于此脚本不处理列表。例如,在 Google Docs 示例中,在 PDF 对象中,您会看到以下结构:
{'/Encoding': '/Identity-H', '/Type': '/Font', '/BaseFont': '/Pacifico-Regular', '/ToUnicode': IndirectObject(9, 0), '/DescendantFonts': [IndirectObject(16, 0)], '/Subtype': '/Type0'}
键 DescendantFonts
映射到一个值列表,如果您更深入地递归,它将包含字体文件的键。您还必须修改脚本以测试数组,例如:
if type(obj) == PyPDF2.generic.ArrayObject: # You can also do ducktyping here
for i in obj:
if hasattr(i, 'keys'):
walk(i, all_fonts, embedded_fonts)
我希望有人能帮我写一个 Python 函数来检测文件中没有嵌入文件中的任何字体。我尝试使用链接 here 的脚本,它可以检测文档字体,但它不检测嵌入的字体。为了方便起见,我粘贴了下面的脚本:
import sys
from PyPDF2 import PdfFileReader
fontkeys = set(["/FontFile", "/FontFile2", "/FontFile3"])
def walk(obj, fnt, emb):
if "/BaseFont" in obj:
fnt.add(obj["/BaseFont"])
elif "/FontName" in obj and fontkeys.intersection(set(obj)):
emb.add(obj["/FontName"])
for k in obj:
if hasattr(obj[k], "keys"):
walk(obj[k], fnt, emb)
return fnt, emb
if __name__ == "__main__":
file_name = sys.argv[1]
reader = PdfFileReader(file_name)
fonts = set()
embedded = set()
for page in reader.pages:
obj = page.getObject()
f, e = walk(obj["/Resources"], fonts, embedded)
fonts = fonts.union(f)
embedded = embedded.union(e)
unembedded = fonts - embedded
print("Font List")
print(sorted(list(fonts)))
if unembedded:
print("\nUnembedded Fonts")
print(unembedded)
例如,我从 Google Docs 下载了一个带有 Arial 字体的 PDF(输入一些内容,另存为 PDF),并且 Adobe Reader 已经确认嵌入了该字体。但是,脚本 returns ['/ArialMT'] 作为字体,并且为嵌入字体设置了一个空集。此外,看起来没有任何递归对象具有键 {'/FontFile', '/FontFile2', '/FontFile3'}
。我已经在其他 PDF 上尝试过它并且它有效,所以它一定与 Google Docs PDF 有一些奇怪之处。让我知道我可以为这个 PDF 文件提供哪些其他调试信息。
我想到的一件事是 Google Docs 可能只嵌入了 14 种标准 PDF 字体中没有的字体。但是,我尝试使用一种奇怪的字体 (pacifico),并且脚本还说明该字体未嵌入,而 Adobe 声称它是嵌入的。
我用 this PDF 试了一下,脚本正确地指出嵌入了这 14 种字体。
问题在于此脚本不处理列表。例如,在 Google Docs 示例中,在 PDF 对象中,您会看到以下结构:
{'/Encoding': '/Identity-H', '/Type': '/Font', '/BaseFont': '/Pacifico-Regular', '/ToUnicode': IndirectObject(9, 0), '/DescendantFonts': [IndirectObject(16, 0)], '/Subtype': '/Type0'}
键 DescendantFonts
映射到一个值列表,如果您更深入地递归,它将包含字体文件的键。您还必须修改脚本以测试数组,例如:
if type(obj) == PyPDF2.generic.ArrayObject: # You can also do ducktyping here
for i in obj:
if hasattr(i, 'keys'):
walk(i, all_fonts, embedded_fonts)