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

PDFBox 3.0.1复制含图片PDF页面生成新文档时出现损坏问题

PDFBox 3.0.1拆分含图片PDF生成损坏文件的问题解决

问题描述

需要拆分每页含图片的多页PDF,生成若干不超过指定大小(7485760字节)的PDF。原代码在PDFBox 3.0.0中运行正常,但升级到3.0.1后生成的PDF损坏:仅首页显示图片,后续页面无图,打开时弹出警告:There was an error processing a page. There was a problem reading this document (18)。纯文本PDF无此问题,且确认是用于获取单页大小的ByteArrayOutputStream保存操作导致的,移除该操作则恢复正常。

原问题代码:

long currentSize = 0L;
try (PDDocument document = Loader.loadPDF(file)) {
    List<PDDocument> documentList = new ArrayList<>();
    for (int i = 0; i < document.getPages().getCount(); i++) {
        PDDocument sizeCheck = new PDDocument();
        sizeCheck.addPage(document.getPage(i));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        sizeCheck.save(baos);
        long pageSize = baos.size();

        if (currentSize==0L || (currentSize+pageSize) > 7485760L) {
            PDDocument tempDoc = new PDDocument();
            tempDoc.addPage(document.getPage(i));
            documentList.add(tempDoc);
            currentSize=pageSize;
        } else {
            documentList.get(documentList.size() - 1).addPage(document.getPage(i));
            currentSize+=pageSize;
        }
    }

    for (PDDocument doc : documentList) {
        File temp = Files.createTempFile(UUID.randomUUID(), ".pdf").toFile();
        doc.save(temp);
        doc.close();
    }
}

原因分析

PDFBox 3.0.1的内部实现变更导致:直接将原文档的页面添加到临时sizeCheck文档并保存时,会修改原页面关联的图片资源的引用状态(比如资源被标记为已被其他文档占用、或资源的内部指针被修改)。后续将同一页面添加到目标拆分文档时,无法正确读取图片资源,从而导致页面损坏。而3.0.0版本没有这个资源引用的变更逻辑,因此不会出现问题。

解决方案

核心思路是避免临时文档操作影响原页面的资源,可以通过复制页面副本到临时文档的方式实现:

修改后的代码

long currentSize = 0L;
try (PDDocument document = Loader.loadPDF(file)) {
    List<PDDocument> documentList = new ArrayList<>();
    for (int i = 0; i < document.getPages().getCount(); i++) {
        PDPage originalPage = document.getPage(i);
        // 创建临时文档并导入原页面的副本,而非直接引用原页面
        try (PDDocument sizeCheck = new PDDocument()) {
            PDPage pageCopy = sizeCheck.importPage(originalPage);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            sizeCheck.save(baos);
            long pageSize = baos.size();

            if (currentSize == 0L || (currentSize + pageSize) > 7485760L) {
                PDDocument tempDoc = new PDDocument();
                tempDoc.importPage(originalPage);
                documentList.add(tempDoc);
                currentSize = pageSize;
            } else {
                documentList.get(documentList.size() - 1).importPage(originalPage);
                currentSize += pageSize;
            }
        } // 自动关闭sizeCheck临时文档,释放资源
    }

    for (PDDocument doc : documentList) {
        File temp = Files.createTempFile(UUID.randomUUID(), ".pdf").toFile();
        doc.save(temp);
        doc.close();
    }
}

关键修改点

  1. 使用PDDocument.importPage()替代直接addPage():importPage()会创建原页面的副本及关联资源的独立副本,临时文档的保存操作不会影响原文档的页面资源。
  2. 给临时sizeCheck文档添加try-with-resources声明,确保及时关闭释放资源,避免内存泄漏。
  3. 目标拆分文档中同样使用importPage()添加页面,确保每个拆分文档的资源都是独立的,避免跨文档的资源引用冲突。

其他可选方案

  • 若对页面大小的估算精度要求不高,可以通过计算页面中图片资源的字节数加上固定的PDF页面结构开销来估算,无需创建临时文档保存,从根源避免问题。
  • 临时回退到PDFBox 3.0.0版本,但不建议长期使用,需跟进PDFBox官方是否修复该兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:40:58