You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PDFBox 3.0导入页面后字体缺失及文档损坏问题求助

PDFBox 3.0导入含嵌入字体的PDF页面到PDF/A时字体缺失及文档损坏问题

问题背景

在PDFBox 2.0中,通过以下代码可将含嵌入字体的PDF页面导入到PDF/A文档并正确复制字体资源,生成的文档包含所需嵌入字体:

PDDocument targetDoc = Loader.loadPDF(targetDocBytes);
PDPage sourcePage = Loader.loadPDF(data).getPage(0);
final var copiedPage = targetDoc.importPage(sourcePage);
copiedPage.setResources(sourcePage.getResources());

但升级到PDFBox 3.0.1后,执行相同操作生成的文档在Adobe Acrobat中显示损坏,且通过PDFBox PreflightParser检测出大量错误。

错误信息

1.4 Trailer Syntax error, /XRef cross reference streams are not allowed
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.1.3 Invalid Font definition, BCDFEE+Roboto-Regular: FontFile entry is missing from FontDescriptor
3.1.14 Invalid Font definition, Unknown font type: XML
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.3.1 Glyph error, The character code 0 in the font program "BCDEEE+Calibri" is missing from the Character Encoding
3.1.8 Invalid Font definition
3.1.2 Invalid Font definition, BCDGEE+TimesNewRomanPS-BoldMT: some mandatory fields are missing from the FontDescriptor: Type, ItalicAngle, FontBBox, Ascent, FontName, StemV, Flags, CapHeight, Descent.
3.1.3 Invalid Font definition, null: FontFile entry is missing from FontDescriptor
3.3.2 Glyph error, invalid font dictionary ==> 

完整测试用例

@Test
void importPageWithFonts_validateFontInfo() throws IOException {
    // given
    final var targetDocBytes = IOUtils.toByteArray(PdfUtilitiesTest.class.getClassLoader().getResourceAsStream("empty.pdf"));

    String[] additionalFiles = new String[]{
        "roboto-14.pdf",
    };
    PDDocument targetDoc = Loader.loadPDF(targetDocBytes);


    // when
    for (String fileName : Arrays.asList(additionalFiles)) {
        byte[] data = IOUtils.toByteArray(PdfUtilitiesTest.class.getClassLoader().getResourceAsStream(fileName));
        // verify source is valid
        PDPage sourcePage = Loader.loadPDF(data).getPage(0);
        final var copiedPage = targetDoc.importPage(sourcePage);
        copiedPage.setResources(sourcePage.getResources());
        targetDoc.save(Files.createTempFile("merged-fonts", ".pdf").toFile());
    }
    Path tmpFile = Files.createTempFile("fscd-merged", ".pdf");
    targetDoc.save(tmpFile.toFile(), CompressParameters.DEFAULT_COMPRESSION);


    // then
    // font errors, e.g. Invalid Font definition, BCDFEE+Roboto-Regular: FontFile entry is missing from FontDescriptor
    assertFontsAreValid(tmpFile);
}

private static void assertFontsAreValid(Path tmpFile) throws IOException {
    PreflightParser parser = new PreflightParser(tmpFile.toFile());
    final var documentToVerify = (PreflightDocument) parser.parse();
    // Get validation result
    final var result = documentToVerify.validate();
    final var resultString = result.getErrorsList().stream()
        .filter(err -> !err.getErrorCode()
            .matches("7\\.11\\.2|3\\.1\\.11|2\\.1\\.2|2\\.2\\.1|2\\.4\\.3")) // filter findings from the source documents
        .map(err -> err.getErrorCode() + " " + err.getDetails()).collect(Collectors.joining("\n"));
    assertTrue(resultString.isBlank(), resultString);
}

解决方案

1. 移除直接覆盖页面资源的代码

PDFBox 3.0中importPage方法已自动处理页面资源的复制,直接调用setResources(sourcePage.getResources())会导致资源对象仍关联到源文档,未被正确导入到目标文档的COS结构中。删除该行代码即可避免资源引用异常。

2. 禁用交叉引用流以符合PDF/A规范

PDF/A不允许使用交叉引用流,保存文档时需显式禁用:

targetDoc.save(tmpFile.toFile(), new SaveOptions()
    .setUseXRefStream(false)
    .setCompressParameters(CompressParameters.DEFAULT_COMPRESSION));

3. 手动确保字体资源正确导入(可选)

若importPage未自动处理字体资源,可手动遍历并导入字体到目标文档:

PDResources sourceResources = sourcePage.getResources();
PDResources targetResources = copiedPage.getResources();

for (COSName fontName : sourceResources.getFontNames()) {
    PDFont sourceFont = sourceResources.getFont(fontName);
    PDFont importedFont = targetDoc.importFont(sourceFont);
    targetResources.put(fontName, importedFont);
}

4. 完善PDF/A文档结构

确保目标文档具备PDF/A所需的基础结构,比如添加输出Intent:

PDOutputIntent outputIntent = new PDOutputIntent(targetDoc, "sRGB IEC61966-2.1");
outputIntent.setInfo("sRGB IEC61966-2.1");
outputIntent.setOutputCondition("sRGB IEC61966-2.1");
outputIntent.setOutputConditionIdentifier("sRGB");
outputIntent.setRegistryName("http://www.color.org");
targetDoc.getDocumentCatalog().addOutputIntent(outputIntent);

修正后的核心代码

PDDocument targetDoc = Loader.loadPDF(targetDocBytes);
try (PDDocument sourceDoc = Loader.loadPDF(data)) {
    PDPage sourcePage = sourceDoc.getPage(0);
    PDPage copiedPage = targetDoc.importPage(sourcePage);
    
    // 手动导入字体资源(按需使用)
    PDResources sourceResources = sourcePage.getResources();
    PDResources targetResources = copiedPage.getResources();
    for (COSName fontName : sourceResources.getFontNames()) {
        PDFont sourceFont = sourceResources.getFont(fontName);
        PDFont importedFont = targetDoc.importFont(sourceFont);
        targetResources.put(fontName, importedFont);
    }
    
    // 添加PDF/A输出Intent
    PDOutputIntent outputIntent = new PDOutputIntent(targetDoc, "sRGB IEC61966-2.1");
    outputIntent.setInfo("sRGB IEC61966-2.1");
    outputIntent.setOutputCondition("sRGB IEC61966-2.1");
    outputIntent.setOutputConditionIdentifier("sRGB");
    outputIntent.setRegistryName("http://www.color.org");
    targetDoc.getDocumentCatalog().addOutputIntent(outputIntent);
    
    // 保存为PDF/A兼容文档
    Path tmpFile = Files.createTempFile("fscd-merged", ".pdf");
    targetDoc.save(tmpFile.toFile(), new SaveOptions()
        .setUseXRefStream(false)
        .setCompressParameters(CompressParameters.DEFAULT_COMPRESSION));
} finally {
    targetDoc.close();
}

内容的提问来源于stack exchange,提问作者karma-works

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:17:22