开源PDF工具 Apache PDFBox 认识及使用(知识点+案例)

文章目录

前言

博主介绍:✌目前全网粉丝2W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。

涵盖技术内容:Java后端、算法、分布式微服务、中间件、前端、运维、ROS等。

博主所有博客文件目录索引:博客目录索引(持续更新)

视频平台:b站-Coder长路


源码获取

项目源码:GiteeGithub

本篇文档的视频系列讲解:Java实现自动化pdf打水印工具 开源PDF工具PDFBoxWord、Word转PDF开源工具Documents4j


一、认识PDFBox

Apache PDFBox库是一个开源的Java工具,专门用于处理PDF文档。它允许用户创建全新的PDF文件,编辑现有的PDF文档,以及从PDF文件中提取内容。

功能:创建、渲染、打印、合并、拆分、加密、解密、签名等多种操作PDF文件的功能,包括一个命令行工具,可以用于执行各种PDF处理任务。支持文本提取和搜索,以及将PDF转换为其他格式,如图片和文本。

应用场景:广泛应用于企业和开发者构建PDF处理相关的应用程序和工具。

Apache PDFBox具备以下主要功能:

  • 从PDF文件中提取Unicode文本。
  • 将单个PDF文件拆分成多个文件,或将多个PDF文件合并成一个。
  • 从PDF表单中提取数据,或填写PDF表单。
  • 验证PDF文件是否符合PDF/A-1b标准。
  • 使用标准的Java打印API打印PDF文件。
  • 将PDF文件另存为图像格式,如PNG或JPEG。
  • 从零开始创建PDF文件,包括嵌入字体和图像。
  • 对PDF文件进行数字签名。

二、导入依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.apache.pdfbox</groupId>
        <artifactId>pdfbox</artifactId>
        <version>2.0.28</version>
    </dependency>
</dependencies>

三、基础功能

demo1:读取pdf所有内容

java 复制代码
package com.changlu.demos;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;

import java.io.File;
import java.net.URLDecoder;

/**
 * @Description:
 * @Author: changlu
 * @Date: 1:28 PM
 */
public class Demo1 {
    public static void main(String[] args) throws Exception{
        //读取resources目录下input.pdf文件
        String inputFile = URLDecoder.decode(Demo1.class.getClassLoader().getResource("input.pdf").getFile(), "UTF-8");
        PDDocument pdDocument = PDDocument.load(new File(inputFile));
        PDFTextStripper pdfTextStripper = new PDFTextStripper();
        //读取pdf中所有的文件
        String fullText = pdfTextStripper.getText(pdDocument);
        System.out.println(fullText);
    }
}

demo2:读取所有页内容(分页)

java 复制代码
package com.changlu;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;

import java.io.InputStream;

/**
 * @Description:
 * @Author: changlu
 * @Date: 11:19 AM
 */
public class Main {
    public static void main(String[] args) throws Exception{
        //读取resources目录下input.pdf文件
        InputStream is = Main.class.getClassLoader().getResourceAsStream("input.pdf");
        PDDocument pdDocument = PDDocument.load(is);
        PDFTextStripper pdfTextStripper = new PDFTextStripper();
        //读取所有的分页
        for (int i = 1; i <= pdDocument.getNumberOfPages(); i++) {
            //设置起始-结束页  这里设置指定某页
            pdfTextStripper.setStartPage(i);
            pdfTextStripper.setEndPage(i);
            //读取每一页
            String pageText = pdfTextStripper.getText(pdDocument);
            System.out.println(String.format("第%s页读取内容:", i));
            System.out.println(pageText);
        }
    }
}

demo3:添加页眉、页脚

要求:页眉页脚居中显示。

java 复制代码
package com.changlu.demos;

import com.changlu.Main;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @Description: 添加页眉、页脚
 * @Author: changlu
 * @Date: 1:38 PM
 */
public class Demo3 {
    public static void main(String[] args) throws Exception{
        //读取resources目录下input.pdf文件
        InputStream is = Main.class.getClassLoader().getResourceAsStream("input.pdf");
        PDDocument pdDocument = PDDocument.load(is);

        //自定义字体 C:\Users\93997\Desktop\watermark tools\watermarkTools\target\classes\ttfs
        //URLDecoder.decode() 方法来解码 URL 编码的路径,将 %20 转换回空格
        String fontFile = URLDecoder.decode(Main.class.getClassLoader().getResource(File.separator + "ttfs" + File.separator + "Alibaba_PuHuiTi_2.0_65_Medium_65_Medium.ttf").getFile(), "UTF-8");
        PDType0Font font = PDType0Font.load(pdDocument, new File(fontFile));
        float fontSize = 10; // 设置字体大小为12

        // 设置透明度状态对象
        PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
        graphicsState.setNonStrokingAlphaConstant(0.2f);
        graphicsState.setAlphaSourceFlag(true);
        graphicsState.setStrokingAlphaConstant(0.2f);

        //设置新的页眉
        String headerText = "咨询专转本默默学课程联系官方报名处QQ:3503851091,更多资料可加群828303961";
        String footerText = "江苏专转本公众号:专转本智慧树";

        //遍历原先的pdf文档
        for (PDPage page : pdDocument.getPages()) {
            float pageWidth = page.getMediaBox().getWidth();
            //计算页眉的居中位置
            float headerTextWidth = font.getStringWidth(headerText) / 1000 * fontSize;
            float headerCenteredX = (pageWidth - headerTextWidth) / 2; // 计算水平居中位置
            //计算页脚的居中位置
            float footerTextWidth = font.getStringWidth(footerText) / 1000 * fontSize;
            float footerCenteredX = (pageWidth - footerTextWidth) / 2; // 计算水平居中位置

            // 创建用于页眉的内容流
            PDPageContentStream headerContentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true, true);
            headerContentStream.beginText(); // 开始文本操作
            headerContentStream.setFont(font, fontSize); // 设置字体和字号
            headerContentStream.newLineAtOffset(headerCenteredX, page.getMediaBox().getHeight() - 30); // 设置文本起始位置
            headerContentStream.showText(headerText); // 绘制页眉内容
            headerContentStream.endText(); // 结束文本操作
            headerContentStream.close(); // 关闭内容流

            // 添加页脚
            PDPageContentStream footerContentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true, true);
            footerContentStream.beginText(); // 开始文本操作
            footerContentStream.setFont(font, fontSize); // 设置字体和字号
            footerContentStream.newLineAtOffset(footerCenteredX, 30); // 设置文本起始位置
            footerContentStream.showText(footerText); // 绘制页脚内容
            footerContentStream.endText(); // 结束文本操作
            footerContentStream.close(); // 关闭内容流
        }

        //目标目录 Thread.currentThread().getContextClassLoader().getResource("").getPath()  当前工程目录路径
        //String targetPDFPath = URLDecoder.decode(Demo3.class.getClassLoader().getResource("resources").getPath() + File.separator + "output.pdf", "UTF-8");
//        String targetPDFPath = URLDecoder.decode(Main.class.getClassLoader().getResource("output.pdf").getFile(), "UTF-8");
        String targetPDFPath = "F:\\00核心知识、成果、视频产出区\\技术视频\\2024.2.15 自制默默学打水印工具 watermark tools\\watermarkTools\\src\\main\\resources\\output.pdf";
        File outputFile = new File(targetPDFPath);
        // 若是文件存在先进行删除
        Files.deleteIfExists(Paths.get(outputFile.toURI()));
        // 保存修改后的文档
        pdDocument.save(outputFile);
        System.out.println("转换任务:" + targetPDFPath + " 成功!");
        // 关闭文档
        pdDocument.close(); // 关闭文档
    }
}

效果:


demo4:添加居中45°文字水印

要求:对pdf每页都添加上旋转45°水印,透明度为20%。

java 复制代码
package com.changlu.demos;

import com.changlu.Main;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;

import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @Description: Apache PDFBox案例:对pdf每页都添加上旋转45°水印。
 * @Author: changlu
 * @Date: 1:38 PM
 */
public class Demo4 {
    public static void main(String[] args) throws Exception{
        //读取resources目录下input.pdf文件
        InputStream is = Main.class.getClassLoader().getResourceAsStream("input.pdf");
        PDDocument pdDocument = PDDocument.load(is);

        //自定义字体 C:\Users\93997\Desktop\watermark tools\watermarkTools\target\classes\ttfs
        //URLDecoder.decode() 方法来解码 URL 编码的路径,将 %20 转换回空格
        String fontFile = URLDecoder.decode(Main.class.getClassLoader().getResource(File.separator + "ttfs" + File.separator + "Alibaba_PuHuiTi_2.0_65_Medium_65_Medium.ttf").getFile(), "UTF-8");
        PDType0Font font = PDType0Font.load(pdDocument, new File(fontFile));

        // 设置透明度状态对象
        PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
        graphicsState.setNonStrokingAlphaConstant(0.2f);
        graphicsState.setAlphaSourceFlag(true);
        graphicsState.setStrokingAlphaConstant(0.2f);

        //设置水印名
        String waterText = "江苏专转本网课报名vx:mmxchanglu";

        //遍历原先的pdf文档
        for (PDPage page : pdDocument.getPages()) {
            float pageWidth = page.getMediaBox().getWidth();
            float pageHeight = page.getMediaBox().getHeight();
            //添加水印   要求:旋转45°,不透明度30%
            float waterTextWidth = font.getStringWidth(waterText) / 1000 * 30;
            float waterCenteredX = (pageWidth - waterTextWidth) / 2;
            float waterCenteredY = pageHeight / 2;
            //创建一个水印内容流
            PDPageContentStream waterContentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true, true);
            waterContentStream.beginText();
            waterContentStream.setFont(font, 30);
            // 设置不透明度
            waterContentStream.setNonStrokingColor(0, 0, 0); // black color
            waterContentStream.setStrokingColor(0, 0, 0); // black color
            waterContentStream.setGraphicsStateParameters(graphicsState);//设置透明度
            //设置旋转文本 45° 对于tx、ty是以左下角为偏移位置中心来进行旋转角度
            waterContentStream.setTextRotation(Math.toRadians(45), 400, -50);
            //设置文本
            waterContentStream.newLineAtOffset(waterCenteredX, waterCenteredY);
            waterContentStream.showText(waterText);
            waterContentStream.endText();
            waterContentStream.close();
        }

        //目标目录 Thread.currentThread().getContextClassLoader().getResource("").getPath()  当前工程目录路径
        String targetPDFPath = "F:\\00核心知识、成果、视频产出区\\技术视频\\2024.2.15 自制默默学打水印工具 watermark tools\\watermarkTools\\src\\main\\resources\\output.pdf";
        File outputFile = new File(targetPDFPath);
        // 若是文件存在先进行删除
        Files.deleteIfExists(Paths.get(outputFile.toURI()));
        // 保存修改后的文档
        pdDocument.save(outputFile);
        System.out.println("转换任务:" + targetPDFPath + " 成功!");
        // 关闭文档
        pdDocument.close(); // 关闭文档
    }
}

效果:


demo5:添加图片到右上角

要求:将图片缩小25%后插入到右上角。

java 复制代码
package com.changlu.demos;

import com.changlu.Main;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;

import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @Description: Apache PDFBox案例:将图片缩小25%后插入到右上角。
 * @Author: changlu
 * @Date: 1:38 PM
 */
public class Demo5 {
    public static void main(String[] args) throws Exception{
        //读取resources目录下input.pdf文件
        InputStream is = Main.class.getClassLoader().getResourceAsStream("input.pdf");
        PDDocument pdDocument = PDDocument.load(is);

        //自定义字体 C:\Users\93997\Desktop\watermark tools\watermarkTools\target\classes\ttfs
        //URLDecoder.decode() 方法来解码 URL 编码的路径,将 %20 转换回空格
        String fontFile = URLDecoder.decode(Main.class.getClassLoader().getResource(File.separator + "ttfs" + File.separator + "Alibaba_PuHuiTi_2.0_65_Medium_65_Medium.ttf").getFile(), "UTF-8");
        PDType0Font font = PDType0Font.load(pdDocument, new File(fontFile));

        //遍历原先的pdf文档
        for (PDPage page : pdDocument.getPages()) {
            float pageWidth = page.getMediaBox().getWidth();
            float pageHeight = page.getMediaBox().getHeight();
            //添加图片水印
            //创建一个水印内容流
            PDPageContentStream imageContentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true, true);
            // 创建图像对象
//            PDImageXObject image = PDImageXObject.createFromFile("C:\\Users\\93997\\Desktop\\watermark tools\\watermarkTools\\src\\main\\resources\\images\\ConsultationGroupQRCode.jpg", pdDocument);
            String pictureFile = URLDecoder.decode(Main.class.getClassLoader().getResource(File.separator + "images" + File.separator + "ConsultationGroupQRCode.jpg").getFile(), "UTF-8");
            PDImageXObject image = PDImageXObject.createFromFile(pictureFile, pdDocument);
            // 计算图像的宽度和高度(缩小比例为0.3)
            float imageWidth = (float) (image.getWidth() * 0.25);
            float imageHeight = (float) (image.getHeight() * 0.25);
            //具体图片位置
            float imageX = pageWidth - imageWidth - 10;
            float imageY = pageHeight - imageHeight - 10;

            // 在指定位置绘制图像
            imageContentStream.drawImage(image, imageX, imageY, imageWidth, imageHeight);
            imageContentStream.close();
        }

        //目标目录 Thread.currentThread().getContextClassLoader().getResource("").getPath()  当前工程目录路径
        String targetPDFPath = "F:\\00核心知识、成果、视频产出区\\技术视频\\2024.2.15 自制默默学打水印工具 watermark tools\\watermarkTools\\src\\main\\resources\\output.pdf";
        File outputFile = new File(targetPDFPath);
        // 若是文件存在先进行删除
        Files.deleteIfExists(Paths.get(outputFile.toURI()));
        // 保存修改后的文档
        pdDocument.save(outputFile);
        System.out.println("转换任务:" + targetPDFPath + " 成功!");
        // 关闭文档
        pdDocument.close(); // 关闭文档
    }
}

效果:


参考文章

[1]. 使用 Apache PDFBox 操作PDF文件

[2]. Java使用pdfbox将已有的pdf添加页眉

[3]. 基于pdfbox实现的pdf添加文字水印工具


资料获取

大家点赞、收藏、关注、评论啦~

精彩专栏推荐订阅:在下方专栏👇🏻

更多博客与资料可查看👇🏻获取联系方式👇🏻,🍅文末获取开发资源及更多资源博客获取🍅

相关推荐
Rense15 小时前
开源RK3588 AI Module7,并与Jetson Nano生态兼容的低功耗AI模块
人工智能·开源
程序员皮皮林9 小时前
开源PDF工具 Apache PDFBox 认识及使用(知识点+案例)
java·pdf·开源·apache
前端-文龙刚9 小时前
小程序给对象赋值(双向绑定)方法之一
服务器·小程序·apache
weixin_419349799 小时前
Python pdf转换为html
python·pdf
易我科技12 小时前
PDF里怎么直接编辑文字?简单操作指南
pdf
小安运维日记12 小时前
Linux云计算 |【第三阶段】PROJECT1-DAY1
linux·运维·云计算·apache
MinIO官方账号13 小时前
从 HDFS 迁移到 MinIO 企业对象存储
人工智能·分布式·postgresql·架构·开源
giszz16 小时前
【开源大模型生态9】百度的文心大模型
人工智能·开源
棱镜七彩17 小时前
供方软件供应链安全保障要求及开源场景对照自评表(下)
安全·开源
华为云开源18 小时前
openGemini 社区人才培养计划:助力成长,培养新一代云原生数据库人才
数据库·云原生·开源