【PDFBox】PDFBox操作PDF文档之读取指定页面文本内容、读取所有页面文本内容、根据模板文件生成PDF文档

这篇文章,主要介绍PDFBox操作PDF文档之读取指定页面文本内容、读取所有页面文本内容、根据模板文件生成PDF文档。

目录

一、PDFBox操作文本

1.1、读取所有页面文本内容

1.2、读取指定页面文本内容

1.3、写入文本内容

1.4、替换文本内容

(1)自定义PDTextStripper类

(2)创建KeyWordEntity实体类

(3)下载字体文件

(4)创建PDFUtil工具类

(5)运行效果

(6)不足之处


一、PDFBox操作文本

PDFBox操作文本内容,需要使用文本提取器PDTextStripper对象实现,这个PDTextStripper类提供了对文本内容操作的方法,例如:getText()获取文本,writeString()写入字符串等等,下面介绍PDFBox操作文本的几种情况。

1.1、读取所有页面文本内容

一个PDF文档是由多个页面组成的,某一个页面中都可能会包含文本内容,PDTextStripper类提供的【getText()】方法,可以获取到整个PDF文档的文本内容,案例代码如下所示:

package pdfbox.demo.text;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;import java.io.File;
import java.io.IOException;/*** @version 1.0.0* @Date: 2023/7/18 9:03* @Author ZhuYouBin* @Description: 读取PDF文档中所有纯文本内容*/
public class ReadAllText {public static void main(String[] args) throws IOException {// 1、加载指定PDF文档PDDocument document = PDDocument.load(new File("D:\\demo.pdf"));// 2、创建文本提取对象PDFTextStripper stripper = new PDFTextStripper();// 3、获取指定页面的文本内容String text = stripper.getText(document);System.out.println("获取文本内容: " + text);// 4、关闭document.close();}
}

1.2、读取指定页面文本内容

有些情况下,我们可能是需要获取某一个页面中的文本内容,这个时候可以通过PDTextStripper类设置页面边界,也就是设置提取哪些页面中的文本内容,只需要调用【setStartPage()】和【setEndPage()】方法即可,案例代码如下所示:

package pdfbox.demo.text;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;import java.io.File;
import java.io.IOException;/*** @version 1.0.0* @Date: 2023/7/18 9:03* @Author ZhuYouBin* @Description: 读取PDF文档中所有纯文本内容*/
public class ReadPageText {public static void main(String[] args) throws IOException {// 1、加载指定PDF文档PDDocument document = PDDocument.load(new File("D:\\demo.pdf"));// 2、创建文本提取对象PDFTextStripper stripper = new PDFTextStripper();// 指定页面读取内容stripper.setStartPage(0); // 设置起始页面,这里设置成0,就表示读取第一个页面stripper.setEndPage(0); // 设置结束页面,这里设置成0,就表示读取第一个页面// 3、获取指定页面的文本内容String text = stripper.getText(document);System.out.println("获取文本内容: " + text);// 4、关闭document.close();}
}

1.3、写入文本内容

前几篇文章已经介绍过了如何使用PDFBox写入纯文本内容到PDF文档里面,写入内容可以写入单行内容,也可以写入多行文本内容,可以参考文章:

【【PDFBox】PDFBox操作PDF文档之创建PDF文档、加载PDF文档、添加空白页面、删除页面、获取总页数、添加文本内容、PDFBox坐标系】。

1.4、替换文本内容

替换文本内容,PDFBox并没有提供替换文本内容的方法,这里我是采用了某种方式来实现替换文本内容的功能,大致思路:

  • 首先读取文本内容,获取到替换的文本在PDF文档中的页面坐标位置。
  • 获取到替换文本的坐标之后,将这块区域内容写入一个矩形框,矩形背景颜色采用白色,也就是覆盖替换的文本。
  • 在白色矩形区域里面,重新写入替换之后的文本内容。
  • 采用这种思路,就可以大致实现替换指定文本的功能啦。

(1)自定义PDTextStripper类

要想获取到文本的坐标信息,必须自定义一个类,继承自PDTextStripper类,然后重写【writeString()】方法,这个方法有两个参数:

  • 第一个参数是text:表示当前读取到的文本内容。
  • 第二个参数是List<TextPosition>:表示当前文本内容中某一个字符的坐标信息。
package pdfbox.demo.text.keyword;import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import org.apache.pdfbox.util.Matrix;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;/*** @version 1.0.0* @Date: 2023/7/18 10:18* @Author ZhuYouBin* @Description: 自定义文本提取器,获取查找文本的坐标位置*/
public class KeyWordPositionStripper extends PDFTextStripper {/*** 查找的关键字集合*/private final List<String> keyWordList;/*** 查找成功的关键字实体对象集合*/private final List<KeyWordEntity> keyWordEntityList = new ArrayList<>();public KeyWordPositionStripper(List<String> keyWordList) throws IOException {this.keyWordList = keyWordList;}@Overrideprotected void writeString(String text, List<TextPosition> positions) {int size = positions.size();for (String keyWord : keyWordList) {char[] chars = keyWord.toCharArray();for (int i = 0; i < size; i++) {// 获取当前读取的字符String currentChar = positions.get(i).getUnicode();// 当前字符 和 keyWord 关键字进行匹配if (!Objects.equals(currentChar, String.valueOf(chars[0]))) {continue;}int count = 1;int j;for (j = 1; j < chars.length && i + j < size; j++) {currentChar = positions.get(i + j).getUnicode();if (!Objects.equals(currentChar, String.valueOf(chars[j]))) {break;}count++;}// 匹配成功,记录文本的坐标位置if (count == chars.length) {TextPosition startPosition = positions.get(i);TextPosition endPosition = positions.get(i + j < size ? i + j : i + j - 1);// 创建实体对象KeyWordEntity entity = new KeyWordEntity();entity.setKeyWord(keyWord);// 获取起始字符坐标Matrix matrix = startPosition.getTextMatrix();float x = matrix.getTranslateX();float y = matrix.getTranslateY();// 获取结束字符坐标Matrix endMatrix = endPosition.getTextMatrix();float x2 = endMatrix.getTranslateX();// 获取字体大小float fontSizeInPt = startPosition.getFontSizeInPt();entity.setX(x);entity.setY(y - fontSizeInPt / 5);float width = i + j < size ? x2 - x : x2 - x + fontSizeInPt;entity.setWidth(width);entity.setHeight(fontSizeInPt);keyWordEntityList.add(entity);}}}}public List<KeyWordEntity> getKeyWordEntityList() {return keyWordEntityList;}
}

(2)创建KeyWordEntity实体类

创建一个KeyWordEntity实体类,用于表示需要查找的关键字文本,关键字也就是我们需要替换的文本内容,一般在实际开发中,就相当于是模板占位符内容。实体类需要设置关键字名称、文本的坐标信息。

package pdfbox.demo.text.keyword;import java.io.Serializable;/*** @version 1.0.0* @Date: 2023/7/18 11:22* @Author ZhuYouBin* @Description: 查找的关键字*/
public class KeyWordEntity implements Serializable {private String keyWord;private float x;private float y;private float width;private float height;public String getKeyWord() {return keyWord;}public void setKeyWord(String keyWord) {this.keyWord = keyWord;}public float getX() {return x;}public void setX(float x) {this.x = x;}public float getY() {return y;}public void setY(float y) {this.y = y;}public float getWidth() {return width;}public void setWidth(float width) {this.width = width;}public float getHeight() {return height;}public void setHeight(float height) {this.height = height;}
}

(3)下载字体文件

如果你不想使用PDFBox提供的字体,那么你可以使用外部字体文件,字体文件可以去【经典宋体简|经典|字体下载】网站下载。

(4)创建PDFUtil工具类

package pdfbox.demo.text.keyword;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.springframework.core.io.ClassPathResource;import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.List;/*** @version 1.0.0* @Date: 2023/7/18 16:01* @Author ZhuYouBin* @Description: 基于PDFBox的工具类*/
public class PDFUtil {/*** 读取PDF模板文件,替换指定关键字的数据* @param keyWordMap 需要替换的关键字数据,key表示占位符,value表示替换后的内容* @param pdfPath PDF模板文件的路径* @param destPdf 生成的目标PDF文件*/public static void replaceText(Map<String, String> keyWordMap, String pdfPath, String destPdf) throws IOException {if (keyWordMap == null || keyWordMap.keySet().size() <= 0) {return;}Set<String> keyWordSet = keyWordMap.keySet();// 1、读取PDF模板文件PDDocument document = PDDocument.load(new File(pdfPath));// 2、创建自定义文本提取器KeyWordPositionStripper stripper = new KeyWordPositionStripper(new ArrayList<>(keyWordSet));stripper.setSortByPosition(true);// 注意: writeString() 方法必须执行 getText() 方法之后才会执行stripper.getText(document);// 3、获取关键字实体对象List<KeyWordEntity> keyWordEntityList = stripper.getKeyWordEntityList();// 4、替换指定关键字文本内容PDPageContentStream stream = new PDPageContentStream(document, document.getPage(0), PDPageContentStream.AppendMode.APPEND, true);// 5、加载外部字体文件,这里是直接通过File加载,如果你是SpringBoot项目,则可以通过流加载PDType0Font font = PDType0Font.load(document, new File("D:\\simsun.ttf"));// 6、循环替换文本内容for (KeyWordEntity keyWord : keyWordEntityList) {stream.setNonStrokingColor(Color.WHITE);stream.addRect(keyWord.getX(), keyWord.getY(), keyWord.getWidth(), keyWord.getHeight());stream.fill();// 设置画笔颜色stream.setNonStrokingColor(Color.BLACK);// 替换关键字文本内容stream.beginText();stream.setFont(font, 14);stream.newLineAtOffset(keyWord.getX(), keyWord.getY());stream.showText(keyWordMap.get(keyWord.getKeyWord()));stream.endText();}// 关闭内容流stream.close();// 保存替换之后的文档document.save(destPdf);// 关闭文档document.close();}public static void main(String[] args) throws IOException {Map<String, String> keyWordMap = new HashMap<>();keyWordMap.put("{{name}}", "张三");keyWordMap.put("{{age}}", "25");keyWordMap.put("{{sex}}", "男");keyWordMap.put("{{address}}", "福建省厦门市");// 模拟测试PDFUtil.replaceText(keyWordMap, "D:\\pdfbox-template.pdf", "D:\\new-document.pdf");}
}

(5)运行效果

这里的PDF模板文件如下图所示:

使用PDFBox替换模板文件的内容之后,运行结果如下所示:

(6)不足之处

虽然这里可以实现替换文本内容,但是这个代码仍然存在一些不足之处,有以下几点:

  • 1、替换的文本位置无法保证和原文本内容对齐,需要自己根据实际模板,调整相应坐标位置。
  • 2、当替换的文本内容太多,会覆盖后面的文本内容。
  • 3、目前只能够替换指定页面的文本内容。
  • 4、其他不足。。。

到此,PDFBox操作文本就介绍完啦。

综上,这篇文章结束了,主要介绍PDFBox操作PDF文档之读取指定页面文本内容、读取所有页面文本内容、根据模板文件生成PDF文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/29429.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud系列(十六)[分布式搜索引擎篇] - DSL 查询及相关性算分的学习 (部分)

在SpringCloud系列&#xff08;十五&#xff09;[分布式搜索引擎篇] - 结合实际应用场景学习并使用 RestClient 客户端 API这篇文章中我们已经对 RestClient 有了初步的了解, 并且已经将一些数据进行了存储, 但是这并不是我们学习 ElasticSearch 的目的, ElasticSearch 最擅长的…

C#鼠标拖拽,移动图片实例

最近工作需要做一个鼠标可以拖拽移动图片的功能。 写了几个基本功能&#xff0c;勉强能用。这里记录一下。欢迎大神补充。 这个就是完成的功能。 下边的绿色是一个pictureBox&#xff0c;白色框也是一个pictureBox&#xff0c;他们二者是子父级关系。 绿色是父级&#xff0c…

Java 常用的重构技巧指南 v1.0

前段时间&#xff0c;leader 在 review 代码的时候发现了代码中 存在的一部分的问题&#xff0c;导致 代码的复杂度太高了&#xff0c;包括大部分的sql 都是属于慢sql &#xff0c;还是在建立了索引的情况下 , 代码的流程过于臃肿&#xff0c;而且本人编码的习惯&#xff0c;习…

ubuntu打开usb摄像头

文章目录 前言一、识别 usb 摄像头二、安装应用程序显示摄像头捕捉到的视频1、使用应用程序茄子&#xff08;cheese&#xff09;2、运行 cheese 捕捉视频 总结 前言 记录一下解决在 Linux 下打开 usb 摄像头界面黑屏的问题。 一、识别 usb 摄像头 1、保持在 ubuntu 界面&…

(四)「消息队列」之 RabbitMQ 路由(使用 .NET 客户端)

0、引言 先决条件 本教程假设 RabbitMQ 已安装并且正在 本地主机 的标准端口&#xff08;5672&#xff09;上运行。如果您使用了不同的主机、端口或凭证&#xff0c;则要求调整连接设置。 获取帮助 如果您在阅读本教程时遇到问题&#xff0c;可以通过邮件列表或者 RabbitMQ 社区…

ylb-项目简介

1、各模块服务功能 注&#xff1a;其部分实体类、接口、mapper文件由MyBatis逆向工程生成。 2、Maven管理&#xff08;多模块&#xff0c;继承和聚合&#xff09; 2.1 parent模块 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"…

CSS——基础知识及使用

CSS 是什么 CSS是层叠样式表 (Cascading Style Sheets)的简写.CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离。 基本语法规范 选择器 { 一条/N条声明 } 选择器决定针对谁修改 (找谁)声明决定修改啥. (干啥)声明的…

OpenCv之Canny

目录 一、自适应阈值 二、边缘检测Canny 一、自适应阈值 引入前提:在前面的部分我们使用是全局闻值&#xff0c;整幅图像采用同一个数作为闻值。当时这种方法并不适应与所有情况&#xff0c;尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应闻…

记录--再也不用手动改package.json的版本号

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 本文的起因是有在代码仓库发包后&#xff0c;同事问我“为什么package.json 里的版本还是原来的&#xff0c;有没有更新&#xff1f;”&#xff0c;这个时候我意识到&#xff0c;我们完全没有必要在每…

“掌握更多的快速排序技巧:三路划分、双路快排和非递归的深入理解”

快速排序是一种基于分治思想的排序算法&#xff0c;它能够以极快的速度将一个乱序的数组重新排列成有序的序列。不仅如此&#xff0c;快速排序还具有简洁的实现代码和良好的可扩展性&#xff0c;成为最受欢迎的排序算法之一。接下来&#xff0c;让我带你了解一下它的魅力吧&…

接入端口与中继端口

交换机端口是支持 IT 的基本组件&#xff0c;可实现网络通信。这些有线硬件设备负责连接并允许在不同设备和连接到其端口的网络部分之间进行数据传输。由于网络管理员在确保网络连接和可用性方面发挥着关键作用&#xff0c;因此网络管理员必须清楚地了解、映射和查看其网络交换…

【有功功率、无功功率】可再生能源配电馈线的鲁棒经济调度研究[IEEE13节点](Matlab代码实现)

&#x1f4a5;1 概述 "有功功率和无功功率" 是与电力系统中能量传输和功率控制相关的两个重要概念。 有功功率&#xff08;Active Power&#xff09;是指电力系统中传输和消耗能量的功率&#xff0c;也被称为实功功率。它负责提供电力系统中的实际电能需求&#xf…