合并PDF出现OOM异常

  • 优化方法一:使用PdfSmartCopy类代替PdfCopy类。这个类可以在合并PDF文件时,检测并消除重复的对象,从而减少内存的占用。您可以参考以下代码示例:
java 复制代码
//创建一个Document对象
Document document = new Document();

//创建一个PdfSmartCopy对象
PdfSmartCopy copy = new PdfSmartCopy(document, new FileOutputStream("output.pdf"));

//打开Document对象
document.open();

//创建一个PdfReader对象
PdfReader reader = null;

//遍历要合并的PDF文件
for (String file : files) {
    //加载PDF文件
    reader = new PdfReader(file);

    //获取PDF文件的总页数
    int n = reader.getNumberOfPages();

    //遍历每一页,添加到PdfSmartCopy对象中
    for (int page = 0; page < n;) {
        copy.addPage(copy.getImportedPage(reader, ++page));
    }
}

//关闭PdfReader对象
reader.close();

//关闭Document对象
document.close();

//创建一个PdfStamper对象
PdfStamper stamper = new PdfStamper(new PdfReader("output.pdf"), new FileOutputStream("output.pdf"));

//获取总页数
int pageCount = stamper.getReader().getNumberOfPages();

//遍历每一页,添加页码
for (int i = 1; i <= pageCount; i++) {
    //获取当前页
    PdfContentByte content = stamper.getOverContent(i);

    //设置字体和颜色
    content.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED), 12);
    content.setRGBColorFill(0, 0, 0);

    //获取当前页的宽度和高度
    Rectangle pageSize = stamper.getReader().getPageSize(i);
    float width = pageSize.getWidth();
    float height = pageSize.getHeight();

    //计算页码的位置
    float x = width / 2;
    float y = 10;

    //添加页码
    content.beginText();
    content.showTextAligned(PdfContentByte.ALIGN_CENTER, "第" + i + "页,共" + pageCount + "页", x, y, 0);
    content.endText();
}

//关闭PdfStamper对象
stamper.close();
  • 优化方法二:使用PdfWriter类代替PdfCopy类。这个类可以在合并PDF文件时,直接将每一页写入到输出流中,而不需要将整个文档加载到内存中。可以参考以下代码示例:
java 复制代码
//创建一个Document对象
Document document = new Document();

//创建一个PdfWriter对象
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("output.pdf"));

//打开Document对象
document.open();

//创建一个PdfImportedPage对象
PdfImportedPage page = null;

//创建一个PdfReader对象
PdfReader reader = null;

//遍历要合并的PDF文件
for (String file : files) {
    //加载PDF文件
    reader = new PdfReader(file);

    //获取PDF文件的总页数
    int n = reader.getNumberOfPages();

    //遍历每一页,添加到PdfWriter对象中
    for (int i = 1; i <= n; i++) {
        //获取当前页的宽度和高度
        Rectangle pageSize = reader.getPageSizeWithRotation(i);
        float width = pageSize.getWidth();
        float height = pageSize.getHeight();

        //设置Document对象的页面大小
        document.setPageSize(pageSize);

        //创建一个新的页面
        document.newPage();

        //导入当前页
        page = writer.getImportedPage(reader, i);

        //将当前页添加到PdfWriter对象中
        writer.addPageDictEntry(PdfName.ROTATE, pageSize.getRotationAsPageDictEntry());
        writer.addDirectImageSimple(page);
        writer.getCurrentPage().add(page);

        //创建一个PdfContentByte对象
        PdfContentByte content = writer.getDirectContent();

        //设置字体和颜色
        content.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED), 12);
        content.setRGBColorFill(0, 0, 0);

        //计算页码的位置
        float x = width / 2;
        float y = 10;

        //添加页码
        content.beginText();
        content.showTextAligned(PdfContentByte.ALIGN_CENTER, "第" + i + "页,共" + pageCount + "页", x, y, 0);
        content.endText();
    }
}

//关闭PdfReader对象
reader.close();

//关闭Document对象
document.close();
  • 优化方法三:使用PdfReader类的partial和selectPages方法。这些方法可以在加载PDF文件时,只读取需要的页面,而不需要将整个文档加载到内存中。可以参考以下代码示例:
java 复制代码
//创建一个Document对象
Document document = new Document();

//创建一个PdfCopy对象
PdfCopy copy = new PdfCopy(document, new FileOutputStream("output.pdf"));

//打开Document对象
document.open();

//创建一个PdfReader对象
PdfReader reader = null;

//遍历要合并的PDF文件
for (String file : files) {
    //设置partial为true,只读取需要的页面
    reader = new PdfReader(new RandomAccessFileOrArray(file), null);
    reader.consolidateNamedDestinations();
    reader.partial = true;

    //获取PDF文件的总页数
    int n = reader.getNumberOfPages();

    //创建一个List对象,存储需要的页面
    List<Integer> pages = new ArrayList<Integer>();

    //遍历每一页,添加到List对象中
    for (int i = 1; i <= n; i++) {
        pages.add(i);
    }

    //使用selectPages方法,只选择需要的页面
    reader.selectPages(pages);

    //将选择的页面添加到PdfCopy对象中
    for (int i = 0; i < pages.size(); ) {
        copy.addPage(copy.getImportedPage(reader, ++i));
    }
}

//关闭PdfReader对象
reader.close();

//关闭Document对象
document.close();

//创建一个PdfStamper对象
PdfStamper stamper = new PdfStamper(new PdfReader("output.pdf"), new FileOutputStream("output.pdf"));

//获取总页数
int pageCount = stamper.getReader().getNumberOfPages();

//遍历每一页,添加页码
for (int i = 1; i <= pageCount; i++) {
    //获取当前页
    PdfContentByte content = stamper.getOverContent(i);

    //设置字体和颜色
    content.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED), 12);
    content.setRGBColorFill(0, 0, 0);

    //获取当前页的宽度和高度
    Rectangle pageSize = stamper.getReader().getPageSize(i);
    float width = pageSize.getWidth();
    float height = pageSize.getHeight();

    //计算页码的位置
    float x = width / 2;
    float y = 10;

    //添加页码
    content.beginText();
    content.showTextAligned(PdfContentByte.ALIGN_CENTER, "第" + i + "页,共" + pageCount + "页", x, y, 0);
    content.endText();
}

//关闭PdfStamper对象
stamper.close();

java - How to avoid OutOfMemoryError when merging PDFs using iText? - Stack Overflow

java - How to merge pdf files without loading all the documents in memory? - Stack Overflow

java - How to merge pdf files without loading all the documents in memory? - Stack Overflow

相关推荐
heartbeat..几秒前
深入理解 JVM:从核心原理到实战应用
java·jvm·jdk·学习笔记
独自破碎E2 分钟前
数组列表中的最大距离
java
猿小羽4 分钟前
基于 Spring AI 与 Streamable HTTP 构建 MCP Server 实践
java·llm·spring ai·mcp·streamable http
大模型微调Online7 分钟前
深度复盘:Qwen3-4B-Instruct-2507微调实战——打造“快思考、强执行”的 ReAct IoT Agent
java·后端·struts
铁蛋AI编程实战9 分钟前
Agentic AI/GPT-4o替代/Spring AI 2.0/国产大模型轻量化
java·人工智能·spring
weixin_7042660510 分钟前
Maven入门:构建与依赖管理全解析
java·maven
cyforkk10 分钟前
14、Java 基础硬核复习:数据结构与集合源码的核心逻辑与面试考点
java·数据结构·面试
零度@14 分钟前
专为 Java 开发者 整理的《Python编程:从入门到实践》前8章核心内容
java·开发语言·windows·python
一嘴一个橘子16 分钟前
idea Could not autowire. No beans of ‘xxxMapper‘ type found
java
海边的Kurisu17 分钟前
苍穹外卖日记 | Day9 用户端历史订单模块、商家端订单管理模块、用户下单功能优化
java·苍穹外卖