为什么pdf仅包含一个字段约为500Kb

时间:2019-04-03 08:11:38

标签: java pdfbox

在这里您可以download pdf使用一个acroform字段,他的大小恰好是427Kb

如果我删除此唯一字段,则文件仅为3Kb,请为什么会发生这种情况? 我尝试使用PDF Debugger进行分析,对我来说似乎没有什么奇怪的。

enter image description here

1 个答案:

答案 0 :(得分:2)

在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默认资源字体。

更新: 以下是一些将Heal替换为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");

您会得到一个例外。

可以在this answer中找到替换字体的更多常规代码。