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

使用PDFBox直接加密页面导致PDF损坏的技术求助

问题

我们的应用需要处理上传的PDF:提取单个页面、按用户分组,再创建带密码加密的新PDF。但在文档创建过程中直接加密时,生成的PDF会损坏——PDF阅读器虽提示输入密码,却无法打开,提示文件无效或损坏。

相关代码片段如下:

打开原PDF并提取页面

// Open the original PDF
try (PDDocument originalDocument = PDDocument.load(new File("input.pdf"))) {
    // Extract pages and group them per user (example for one user)
    List<PDPage> userPages = new ArrayList<>();
    for (PDPage page : originalDocument.getPages()) {
        // Additional processing can be done here if needed
        userPages.add(page);
    }
    // Proceed to create a new document for the user...
}

创建新PDF并直接加密

try (PDDocument employeeDocument = new PDDocument()) {
    // Attempt 1: Adding pages directly
    for (PDPage page : userPages) {
        employeeDocument.addPage(page);
    }
    
    // Attempt 2: Importing pages as an alternative (currently commented out)
    /*
    for (PDPage page : userPages) {
        employeeDocument.importPage(page);
    }
    */

    Path fullPath = payrollManager.getTempPayrollsPath().resolve(Path.of("user_pdf.pdf"));

    String password = "test";
    AccessPermission accessPermission = new AccessPermission();
    StandardProtectionPolicy spp = new StandardProtectionPolicy(password, password, accessPermission);
    spp.setEncryptionKeyLength(256);
    spp.setPermissions(accessPermission);

    // Apply password protection directly
    employeeDocument.protect(spp);
    employeeDocument.save(fullPath.toFile());
}

补充说明:

  • 移除加密步骤(不调用protect(spp)),生成的PDF可正常打开;
  • 文档关闭后再加密,也能正常工作;
  • 已尝试addPage()和importPage()两种方法,直接加密后PDF仍损坏;
  • 先保存未加密文档再加密的两步法不符合使用场景,需要在创建过程中直接加密。

需解决:如何正确复制或导入页面到新PDDocument,以便在创建过程中直接加密后生成有效的PDF?

解决方案

问题根源是直接复用原文档的PDPage对象会导致新文档与原文档共享资源,加密时无法正确处理这些关联资源,最终生成损坏的PDF。按以下方式修正即可:

关键修正步骤

  • 用copyPagesTo替代直接添加/导入页面:该方法会完整复制页面内容及关联资源(字体、图片等)到新文档,确保页面数据完全独立于原文档。
  • 在原文档生命周期内完成新文档的创建与加密:原文档关闭后其资源会被释放,必须在原文档的try-with-resources块内处理新文档的所有操作。

修正后的完整代码

// 打开原PDF并在其生命周期内处理新文档
try (PDDocument originalDocument = PDDocument.load(new File("input.pdf"))) {
    // 按用户分组记录需要提取的页面索引(示例为全部页面,替换为实际分组逻辑)
    List<Integer> targetPageIndices = new ArrayList<>();
    for (int i = 0; i < originalDocument.getNumberOfPages(); i++) {
        targetPageIndices.add(i);
    }

    // 创建新文档并复制页面
    try (PDDocument employeeDocument = new PDDocument()) {
        // 复制指定页面到新文档,自动处理资源关联
        originalDocument.copyPagesTo(targetPageIndices, employeeDocument);

        // 设置加密策略
        String password = "test";
        AccessPermission accessPermission = new AccessPermission();
        StandardProtectionPolicy spp = new StandardProtectionPolicy(password, password, accessPermission);
        spp.setEncryptionKeyLength(256);
        spp.setPermissions(accessPermission);

        // 应用加密并保存
        employeeDocument.protect(spp);
        Path fullPath = payrollManager.getTempPayrollsPath().resolve(Path.of("user_pdf.pdf"));
        employeeDocument.save(fullPath.toFile());
    }
}

原方法失效原因

  • addPage():直接添加原文档的PDPage对象,新文档与原文档共享页面资源,加密时这些资源未被正确序列化到新文档。
  • importPage():虽创建新页面实例,但未完整复制关联资源,仍存在资源引用问题。
  • 加密时机:若原文档已关闭,页面资源已释放,此时加密会因缺失资源导致PDF损坏。

内容的提问来源于stack exchange,提问作者Lvkas_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:27:37