Java使用PDFBox处理PDF的完全指南

 更新时间:2025年07月04日 08:10:31   作者:SimonKing  
在日常开发中,我们可能会遇到PDF的处理,如PDF的内容提取、分割、合并等操作,本文就来和大家介绍一个Apache出品的工具PDFBox,完美解决PDF的解析生成与操作难题,下面我们就来看看具体使用吧

01 引言

在日常开发中,我们可能会遇到PDF的处理,如PDF的内容提取、分割、合并等操作。你们都是用什么工具操作的呢?

今天介绍一款Apache出品的工具PDFBox,作为Apache基金会开源项目,它以轻量级、高扩展性著称,完美解决PDF的解析、生成与操作难题。

官网地址:pdfbox.apache.org/

02 核心功能一览

Apache PDFBox库是用于处理PDF文档的开源 Java 工具。此项目允许创建新的 PDF 文档、作现有文档以及从文档中提取内容的能力。Apache PDFBox 还包括几个命令行实用程序。Apache PDFBox Apache 许可证 v2.0 下发布。

主要有8个功能:

  • PDF文件提取中文本
  • PDF的合并和分割
  • PDF表单中提取数据,或填充PDF表单
  • 验证PDF否符合PDF/A-1b标准
  • 使用标准的Java打印API打印PDF文件
  • PDF文件另存为图像格式
  • 从零开始创建PDF文件,包括嵌入字体和图像
  • PDF文件进行数字签名

03 功能展示

Apache PDFBox 主要提供了8个功能,通过演示几个常用的功能,了解一下Apache PDFBox的魅力。

展示的版本为当期那最新版本3.0.5

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.5</version>
</dependency>

3.1 文本提取

文本提取的关键类:org.apache.pdfbox.text.PDFTextStripper

 @Test
void test01() throws IOException {
    try (PDDocument pdDocument = Loader.loadPDF(ResourceUtils.getFile("classpath:pdf/wyc-fp.pdf"))){
        PDFTextStripper textStripper = new PDFTextStripper();
        String text = textStripper.getText(pdDocument);
        System.out.println(text);
    }
}

因为PDDocument使用完毕之后需要关闭资源,类似JDK中的流。这里使用try-with-resources自动关闭资源。案例提取了一张网 约车发票的信息。

结果展示

3.2 PDF合并

PDF合并的关键类是:org.apache.pdfbox.multipdf.PDFMergerUtility

@Test
void test02() throws IOException {
    PDFMergerUtility pdfMerger = new PDFMergerUtility();
    pdfMerger.addSource(ResourceUtils.getFile("classpath:pdf/wyc-fp.pdf"));
    pdfMerger.addSource(ResourceUtils.getFile("classpath:pdf/wyc-fp2.pdf"));

    // 设置合并后的pdf名称
     pdfMerger.setDestinationFileName("merge-fp.pdf");
//        pdfMerger.setDestinationStream(new FileOutputStream(file));

    pdfMerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly().streamCache);
    System.out.println("PDF文件合并完成");
}

通过addSource()方法,添加要合并的PDF资源。然后设置合并后的PDF名称,也可以通过setDestinationStream()指定合并的PDF保存的位置。

执行结果

默认保存在项目的根路径下面:

3.3 提取图像

提取PDF中图像的关键类:org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject

@Test
void test03() throws Exception {
    try (PDDocument pdDocument = Loader.loadPDF(ResourceUtils.getFile("classpath:pdf/wyc-fp.pdf"));) {
        // 获取第一页:因为只有一页
        PDPage page = pdDocument.getPage(0);

        PDResources resources = page.getResources();
        Iterable<COSName> xObjectNames = resources.getXObjectNames();
        for (COSName xObjectName : xObjectNames) {
            // 判断是否包含图片对象
            if (resources.isImageXObject(xObjectName)) {
                PDImageXObject imageObject = (PDImageXObject) resources.getXObject(xObjectName);
                BufferedImage bImage = imageObject.getImage();
                // 将图像保存为 PNG 格式
                try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                    // 将图片写入输出流里面
                    ImageIO.write(bImage, "png", baos);
                    byte[] imageBytes = baos.toByteArray();
                    String imageFilePath = "image_" + System.currentTimeMillis() + ".png";
                    try (FileOutputStream fos = new FileOutputStream(imageFilePath)) {
                        fos.write(imageBytes);
                        System.out.println("Page Image path: " + imageFilePath);
                    }
                }
            }
        }
    }
}

通过resources.getXObject(xObjectName)获取图像资源,通过ImageIO.write()写到输出流里面

执行结果

可以看出打印和输出的图片名称和图片。提取出了那些图片呢?

这里为了方便截图,将三张图展示在了一起。

3.4 增加签章

增加签章的关键类:org.apache.pdfbox.pdmodel.PDPageContentStream

@Test
void test04() throws Exception {
    PDDocument pdDocument = Loader.loadPDF(ResourceUtils.getFile("classpath:pdf/wyc-fp.pdf"));
    PDImageXObject pdImage = PDImageXObject.createFromFile("src/main/resources/pdf/apache-logo.jpg", pdDocument);
    // 设置logo的宽度和高度
    float imageWidth = 100;
    float imageHeight = 100;

    if (pdDocument != null) {
        PDPage page = pdDocument.getPage(pdDocument.getNumberOfPages() - 1);
        float pageWidth = page.getMediaBox().getWidth();;

        // 计算logo位置:页面右下角
        float x = pageWidth - imageWidth - 20; // 右边距20
        float y = 20; // 下边距20

        // 为最后一页创建一个新的内容流以添加logo
        try (PDPageContentStream contentStream = new PDPageContentStream(pdDocument, page,
                PDPageContentStream.AppendMode.APPEND, true, true)) {
            // 绘制logo图片
            contentStream.drawImage(pdImage, x, y, imageWidth, imageHeight);
        }
        pdDocument.save("logo_" + System.currentTimeMillis() + ".pdf"); // 保存修改后的PDF
    }
}

这里的签章用的是Apachelogo。将签章放在右下角。

执行结果

04 避坑指南

4.1 内存泄露的风险

用完必须关闭文档对象。推荐Try-with-resources

try (PDDocument pdDocument = Loader.loadPDF(file)){
     // ***  
}

4.2 版本差异

2.0.x3.0存在API部分不兼容,如:

// 2.0.x 加载文件
PDDocument.load(file)
    
// 3.0 加载文件
Loader.loadPDF(file)   

4.3 JDK版本要求差异

2.0.x3.0JDK版本最低要求不一样

# 2.0.x 最低要求:JDK1.6

# 3.0 最低要求:JDK1.8

05 小结

Apache PDFBox以其简洁的API设计和强大的底层能力,成为Java开发者处理PDF的首选利器。无论是自动化报表生成还是文档分析系统,它都能提供可靠支持。结合本文的代码示例与避坑指南,可快速构建稳健的PDF处理流程。

以上就是Java使用PDFBox处理PDF的完全指南的详细内容,更多关于Java PDFBox处理PDF的资料请关注脚本之家其它相关文章!

相关文章

  • maven 传递依赖的实现

    maven 传递依赖的实现

    本文主要介绍了Maven中传递依赖的处理方式,如scope=compile影响依赖传递,使用排除不需要的依赖,以及如何通过查看依赖树解决运行时错误,特别是在依赖排除后可能导致的运行时缺少必需包的问题,感兴趣的可以了解一下
    2024-10-10
  • Java数据结构BFS广搜法解决迷宫问题

    Java数据结构BFS广搜法解决迷宫问题

    广搜BFS的基本思想是: 首先访问初始点v并将其标志为已经访问。接着通过邻接关系将邻接点入队。然后每访问过一个顶点则出队。按照顺序,访问每一个顶点的所有未被访问过的顶点直到所有的顶点均被访问过。广度优先遍历类似与层次遍历
    2022-04-04
  • Java实现消消乐中的消除功能

    Java实现消消乐中的消除功能

    这篇文章主要为大家详细介绍了Java实现消消乐中的消除功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • IDEA无法识别相关module模块问题的解决过程

    IDEA无法识别相关module模块问题的解决过程

    这篇文章主要给大家介绍了关于IDEA无法识别相关module模块问题的解决过程,文中通过图文介绍的非常详细,对大家学习或者使用IDEA具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • 线上Java程序占用CPU过高解决方案

    线上Java程序占用CPU过高解决方案

    这篇文章主要介绍了线上Java程序占用CPU过高解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • 详解Java使用sqlite 数据库如何生成db文件

    详解Java使用sqlite 数据库如何生成db文件

    这篇文章主要介绍了详解Java 操作sqllite 数据库如何生成db文件的相关资料,需要的朋友可以参考下
    2017-07-07
  • Windows10系统下JDK1.8环境变量的配置

    Windows10系统下JDK1.8环境变量的配置

    今天带大家学习在Windows10系统下怎么配置JDK1.8环境变量,文中有非常详细的安装及配置教程,对正在学习的小伙伴们很有帮助,需要的朋友可以参考下
    2021-05-05
  • Java 十大排序算法之插入排序刨析

    Java 十大排序算法之插入排序刨析

    插入排序(InsertionSort),一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增 1 的有序表
    2021-11-11
  • Spring Boot中Bean定义方调用方式解析

    Spring Boot中Bean定义方调用方式解析

    这篇文章主要介绍了Spring Boot中Bean定义方调用方式解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Java8中方法引用的使用详解

    Java8中方法引用的使用详解

    这篇文章主要介绍了Java 8 中的方法引用使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12

最新评论