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

使用iTextPDF移除PDF空白页致文件损坏,基于指定代码实现字节数组IO

解决iTextPDF(低版本)处理字节数组移除PDF空白页时文件损坏的问题

嘿,我看你在用旧版iText(就是com.lowagie.text那个包,也就是iText 2.x)处理字节数组输入输出、移除PDF空白页的时候碰到了文件损坏的问题。结合你提到的两个参考实现,我整理了修复后的完整代码,顺便给你讲讲容易踩坑的地方:

为啥会出现文件损坏?

大概率是这几个原因:

  • 字节流没正确关闭或刷新,导致部分数据没写入输出流
  • Document和PdfCopy的生命周期没管好,比如没调用close()完成文档的最终写入
  • 读取PDF页面时没正确处理资源,导致写入新PDF时缺了必要的信息

修复后的完整代码

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;

public class RemoveBlankPageFromPDF {

    public static byte[] removeBlankPages(byte[] inputPdfBytes) throws IOException, DocumentException {
        // 把输入字节数组转成流,方便iText读取
        ByteArrayInputStream inputStream = new ByteArrayInputStream(inputPdfBytes);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        
        PdfReader reader = null;
        Document document = null;
        PdfCopy copy = null;
        
        try {
            reader = new PdfReader(inputStream);
            document = new Document();
            // 用PdfCopy来复制非空白页面,比直接写更稳妥
            copy = new PdfCopy(document, outputStream);
            
            document.open();
            
            int totalPages = reader.getNumberOfPages();
            for (int pageNum = 1; pageNum <= totalPages; pageNum++) {
                // 先判断当前页是不是空白页
                if (!isBlankPage(reader, pageNum)) {
                    PdfImportedPage page = copy.getImportedPage(reader, pageNum);
                    copy.addPage(page);
                }
            }
        } finally {
            // 一定要按顺序关资源!先关document,它会触发copy完成写入
            if (document != null && document.isOpen()) {
                document.close();
            }
            // 再关reader,释放PDF资源
            if (reader != null) {
                reader.close();
            }
            inputStream.close();
        }
        
        // 把处理后的流转成字节数组返回
        return outputStream.toByteArray();
    }

    // 参考你提到的实现,写的空白页判断逻辑,也可以根据需求调整
    private static boolean isBlankPage(PdfReader reader, int pageNum) throws IOException {
        // 先拿裁剪框,没有的话用媒体框
        com.lowagie.text.Rectangle pageRect = reader.getCropBox(pageNum);
        if (pageRect == null) {
            pageRect = reader.getMediaBox(pageNum);
        }
        
        // 简单判断:页面内容里有没有文本(BT标记)或者图形(BMC标记)
        // 如果需要更精确的判断,比如扫描像素,可以替换成你参考的像素扫描逻辑
        String pageContent = reader.getPageContent(pageNum);
        return !pageContent.contains("BT") && !pageContent.contains("BMC");
    }
}

几个必须注意的点

  • 资源关闭顺序:绝对不能乱!先关Document,因为它会让PdfCopy把所有缓存的数据写入输出流;然后关PdfReader释放PDF资源;最后关输入流。顺序错了很容易导致文件不完整。
  • 空白页判断逻辑:我这里用的是简单的标记判断,如果你需要更精准的(比如有些空白页可能有隐形内容),可以把isBlankPage方法替换成你参考的两个实现里的像素扫描逻辑。
  • 字节流处理:全程用ByteArrayInputStream和ByteArrayOutputStream,不需要操作本地文件,完全基于内存处理字节数组,符合你的需求。
  • 旧版iText的坑:你用的是com.lowagie.text包,也就是iText 2.x,这个版本和后来的iText 7.x API完全不一样,要是以后升级版本,代码得大改。

怎么用?

举个简单的例子:

public static void main(String[] args) {
    try {
        // 假设inputBytes是你拿到的原始PDF字节数组
        byte[] inputBytes = ...;
        // 调用方法移除空白页
        byte[] processedPdfBytes = RemoveBlankPageFromPDF.removeBlankPages(inputBytes);
        // 接下来你就可以把processedPdfBytes存文件或者返回给调用方啦
    } catch (IOException | DocumentException e) {
        e.printStackTrace();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:33:23