使用 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),并且 Adob​​e Reader 已经确认嵌入了该字体。但是,脚本 returns ['/ArialMT'] 作为字体,并且为嵌入字体设置了一个空集。此外,看起来没有任何递归对象具有键 {'/FontFile', '/FontFile2', '/FontFile3'}。我已经在其他 PDF 上尝试过它并且它有效,所以它一定与 Google Docs PDF 有一些奇怪之处。让我知道我可以为这个 PDF 文件提供哪些其他调试信息。

我想到的一件事是 Google Docs 可能只嵌入了 14 种标准 PDF 字体中没有的字体。但是,我尝试使用一种奇怪的字体 (pacifico),并且脚本还说明该字体未嵌入,而 Adob​​e 声称它是嵌入的。

我用 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)