• 开源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文件进行数字签名。

    二、导入依赖

    <dependencies>
        <dependency>
            <groupId>org.apache.pdfboxgroupId>
            <artifactId>pdfboxartifactId>
            <version>2.0.28version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、基础功能

    demo1:读取pdf所有内容

    image-20240215133728958

    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    image-20240214114352374


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

    image-20240215133844340

    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);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    image-20240214114934921


    demo3:添加页眉、页脚

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

    image-20240215140356576

    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(); // 关闭文档
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    效果:

    image-20240215140103828


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

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

    image-20240215141008094

    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(); // 关闭文档
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    效果:

    image-20240215140939521


    demo5:添加图片到右上角

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

    image-20240215141247658

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    效果:

    image-20240215141201348


    参考文章

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

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

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


    资料获取

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

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

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

  • 相关阅读:
    InnoDB存储引擎存储结构详解-实战篇
    Android本地数据存储(SP、SQLite、Room)
    闰秒(leapsecond)和原子钟(Atomic Clock)究竟是什么
    【OpenCV学习】第1课:加载丶修改丶显示丶保存图像
    【数据库专题】一文搞懂数据库分库分表的原理
    私网环境下如何使用云效流水线进行 CI/CD?
    Nginx部署vue项目并在局域网中开放访问(尝鲜)
    基于SuperMap iObjects C++之地形凹凸点提取
    【Vue3 Antdv】Ant Design Vue文字溢出鼠标滑上显示tooltip。不溢出,鼠标滑上不显示tooltip
    ChatGPT生产力|中科院学术ChatGPT优化配置
  • 原文地址:https://blog.csdn.net/cl939974883/article/details/136128236