java - 为什么pdf只包含一个字段大约500Kb

标签 java pdfbox

在这里您可以download pdf具有一个 acroform 字段,其大小恰好为 427Kb

如果我删除这个唯一字段,文件只有 3Kb,为什么会发生这种情况? 我尝试使用 PDF 调试器进行分析,对我来说没有什么奇怪的。

enter image description here

最佳答案

acroform 默认资源中有嵌入的“Arial”字体,请参阅 Root/AcroForm/DR/Font/Arial/FontDescriptor/FontFile2

您或创建该 pdf 的人无缘无故地添加了它。未使用/引用该字体。对于 acroform 默认资源,您可以检查每个字段的/DA 条目(默认外观)是否包含字体名称。

当您以某种方式删除该字段时,您也从 acroForm 默认资源中删除了字体。 (你没有写如何删除它)

这里有一些代码可以做到这一点(空检查大多缺失):

    PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
    PDResources defaultResources = acroForm.getDefaultResources();
    COSDictionary fontDict = (COSDictionary) defaultResources.getCOSObject().getDictionaryObject(COSName.FONT);
    List<String> defaultAppearances = new ArrayList<>();
    List<COSName> fontDeletionList = new ArrayList<>();
    for (PDField field : acroForm.getFieldTree())
    {
        if (field instanceof PDVariableText)
        {
            PDVariableText vtField = (PDVariableText) field;
            defaultAppearances.add(vtField.getDefaultAppearance());
        }
    }
    for (COSName fontName : defaultResources.getFontNames())
    {
        if (COSName.HELV.equals(fontName) || COSName.ZA_DB.equals(fontName))
        {
            // Adobe default, always keep
            continue;
        }
        boolean found = false;
        for (String da : defaultAppearances)
        {
            if (da != null && da.contains("/" + fontName.getName()))
            {
                found = true;
                break;
            }
        }
        System.out.println(fontName + ": " + found);
        if (!found)
        {
            fontDeletionList.add(fontName);
        }
    }
    System.out.println("deletion list: " + fontDeletionList);
    for (COSName fontName : fontDeletionList)
    {
        fontDict.removeItem(fontName);
    }

生成的文件现在大小为 5KB。

我没有检查注释。其中一些还具有/DA 字符串,但尚不清楚在重建丢失的外观流时是否使用 acroform 默认资源字体。

更新: 下面是一些用 Helv 替换 Arial 的附加代码:

for (PDField field : acroForm.getFieldTree())
{
    if (field instanceof PDVariableText)
    {
        PDVariableText vtField = (PDVariableText) field;
        String defaultAppearance = vtField.getDefaultAppearance();
        if (defaultAppearance.startsWith("/Arial"))
        {
            vtField.setDefaultAppearance("/Helv " + defaultAppearance.substring(7));
            vtField.getWidgets().get(0).setAppearance(null); // this removes the font usage
            vtField.setValue(vtField.getValueAsString());
        }
        defaultAppearances.add(vtField.getDefaultAppearance());
    }
}

请注意,这可能不是一个好主意,因为标准 14 种字体只有有限的字符。尝试一下

vtField.setValue("Ayşe");

你会得到一个异常(exception)。

更通用的替换字体的代码可以在 this answer 中找到。 .

关于java - 为什么pdf只包含一个字段大约500Kb,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55490141/

相关文章:

java - 如何逐行阅读pdf

java - Bean 验证模式(开头为)失败

java - 如何使用自定义 TableModel 删除 JTable 中的行

pdf - 使用 Uri 通过 Kotlin 解析 pdf?

java - PDFBOX 具有粗体和普通文本的同一流

java - 将base64编码的pdf转换为文件输入流,而不将文件写入系统

java - 附件损坏签名第 2 部分

java - 这句话是什么意思并且......?

java - 如何使用 JodaTime 获得儒略年?

java - 无法使用JConsole远程连接到weblogic服务器