最新 生成pdf文字和表格
生成pdf文字和表格
先看效果
介绍
java项目,使用apache的pdfbox工具,可分页,自定义列
依赖
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.22</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>fontbox</artifactId><version>2.0.22</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>xmpbox</artifactId><version>2.0.22</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>preflight</artifactId><version>2.0.22</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox-tools</artifactId><version>2.0.22</version>
</dependency>
基本使用的api
创建一个页面
String filePath = "D:\\imgTest\\test.pdf";PDDocument document = new PDDocument();PDPage page = new PDPage();document.addPage(page);document.save(new File(filePath));
执行后就可以在 D:\imgTest 目录下看到test.pdf 打开后有一个空白页
写入文字
PDDocument document = new PDDocument();PDFont font = PDType0Font.load(document,new File("D://imgtest/font/simfang.ttf"));PDPage page = new PDPage();PDPageContentStream contentStream = new PDPageContentStream(document, page);contentStream.beginText();contentStream.setFont(font,20.0f);contentStream.showText("写入文字");contentStream.endText();contentStream.close();document.addPage(page);document.save(new File(filePath));
但是可以看到文字在最后显示
文字从顶部写入
计算出page高度 文字高度 然后就得到了书写的位置
contentStream.newLineAtOffset(0,pageHeight - fontHeight);
PDDocument document = new PDDocument();PDFont font = PDType0Font.load(document,new File("D://imgtest/font/simfang.ttf"));PDPage page = new PDPage();float pageWidth = page.getMediaBox().getWidth();float pageHeight = page.getMediaBox().getHeight();float fontSize = 20.0f;float fontHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;float fontWidth = font.getAverageFontWidth() / 1000 * fontSize;PDPageContentStream contentStream = new PDPageContentStream(document, page);contentStream.beginText();contentStream.setFont(font,fontSize);contentStream.setLeading(10.0f);contentStream.newLineAtOffset(0,pageHeight - fontHeight);contentStream.showText("写入文字");contentStream.endText();contentStream.close();document.addPage(page);document.save(new File(filePath));
写入多行文字并自动换行
如果写入一段文字的时候,要自动换行,
现在我们知道一个文字的宽度,可以算出一行总共可以写多少文字,这样就知道多少行了然后每行写入就可以了
代码
PDDocument document = new PDDocument();PDFont font = PDType0Font.load(document,new File("D://imgtest/font/simfang.ttf"));PDPage page = new PDPage();float pageWidth = page.getMediaBox().getWidth();float pageHeight = page.getMediaBox().getHeight();float fontSize = 20.0f;float fontHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;float fontWidth = font.getAverageFontWidth() / 1000 * fontSize;int lineNum = (int)Math.floor(pageWidth/fontWidth);String text = "初升的太阳照耀大地,北部战区空军某雷达站营区披上了一层金色的外衣。祖国东极,一年中最冷的季节,这样的光,给人以希望和温暖。" +" 6时55分,上等兵孙野推开雷达方舱的大门,揉了揉酸痛的双眼,沐浴着第一缕阳光,脑海中浮现一句熟悉的歌词:“我把太阳迎进祖国。”迎接阳光,这是雷达兵最自豪的时刻。\n" +" 这一刻,一级军士长王传星带着“徒弟”走进方舱值班。在这位技术骨干心中,雷达兵的眼睛,就是祖国的眼睛,使命重如泰山,须臾不可懈怠。雷达屏幕上,闪烁的光标汇在一起,那是他和战友们心头永远的璀璨。\n" +" 这一刻,驾驶员刘磊再次出发踏上征程。一次次驾车行驶在熟悉的山路上,他陪伴着战友,也了解了很多不为人知的故事。守护着他们的坚强与坚韧,见证着他们的笑与泪,这位老兵决心成为战友身边和煦的光。\n" +" 这一刻,年轻骨干李航宇和李玉溪全副武装来到了曙光初照的训练场,备战即将来临的上级比武。为了心中的目标,他们把班长当作标杆;为了成为像班长那样的“光”,他们一往无前,奋力冲锋。\n" +" “我把太阳迎进祖国,太阳把光热洒给万里山河,我持枪向太阳致以军礼,请它也带上我的光、我的热……”\n" +" 新年来临,在这个边防雷达站,许多官兵都在守望中找到了属于自己的光。为梦想而追光,他们有怎样的收获和成长,又有怎样的期待和展望?请看来自祖国东极某雷达站的报道。\n" +" 下连之初,班长就曾对孙野说,雷达站驻地太阳升起的时间,比他的家乡福建早了一个多小时。作为东极雷达兵,每当阳光照耀大地,他们感受更多的是肩头的责任。\n" +" “阳光在哪里,坚守就在哪里。”在雷达站官兵心中,头上的阳光很暖,肩上的责任很重,脚下的路很长";PDPageContentStream contentStream = new PDPageContentStream(document, page);contentStream.beginText();contentStream.setFont(font,fontSize);contentStream.setLeading(fontHeight);List<String> textList = handleText(text,lineNum);contentStream.newLineAtOffset(0,pageHeight - fontHeight);for(int i=0;i<textList.size();i++){log.info(textList.get(i));contentStream.showText(textList.get(i));contentStream.newLine();}contentStream.endText();contentStream.close();document.addPage(page);document.save(new File(filePath));
注意换行写入使用的方法
contentStream.beginText();
contentStream.setFont(font,fontSize);
contentStream.setLeading(fontHeight);for ...{contentStream.showText(内容);contentStream.newLine();}
文字内容基本就是这样了,可以根据自己的方式添加padding 和 margin 也就是在pageWidth pageHeight 上进行调整
自己可以试试
表格
画一条横线和竖线
PDDocument document = new PDDocument();PDPage page = new PDPage();float pageWidth = page.getMediaBox().getWidth();float pageHeight = page.getMediaBox().getHeight();PDPageContentStream contentStream = new PDPageContentStream(document, page);contentStream.moveTo(0, pageHeight/2);//横线contentStream.lineTo(pageWidth, pageHeight/2);//横线contentStream.stroke();//横线contentStream.moveTo(pageWidth/2, pageHeight);//竖线contentStream.lineTo(pageWidth/2, 0);//竖线contentStream.stroke();//竖线contentStream.close();document.addPage(page);document.save(new File(filePath));
画一个简单的表格(10 X 5 的表格)
11 条横线 6条数线
这个只是为了画格子,长度和宽度都是自定的,如果写入文字的话就得考虑文字超出的问题,格子的长度和高度就不能是自定义的了
PDDocument document = new PDDocument();PDPage page = new PDPage();float pageWidth = page.getMediaBox().getWidth();float pageHeight = page.getMediaBox().getHeight();PDPageContentStream contentStream = new PDPageContentStream(document, page);float rowNum = (pageHeight - 20) / 10;float colNum = (pageWidth - 20) / 6;for (int i = 0; i <= 11; i++) {float row = pageHeight - 10 - i * rowNum;contentStream.moveTo(10, row);contentStream.lineTo(pageWidth - 10, row);contentStream.stroke();}for (int i = 0; i <= 6; i++) {float col = pageWidth - 10 - i * colNum;contentStream.moveTo(col, 10);contentStream.lineTo(col, pageHeight - 10);contentStream.stroke();}contentStream.close();document.addPage(page);document.save(new File(filePath));
表格中写入文字
考虑一个问题,先画表格还是先写文字
其实都可以
主要的问题是要考虑 一行中,每个列 文字的长度,如果换行的话 文字的高度和最高的那一列,找到这个最高值就知道这一行最下面边的位置了
完整代码
因为内容比较多,单独封装了一个类
@Slf4j
class Table {private float fontWidth;private float fontHeight;private float pageHeight;private float pageWidth;private PDPageContentStream contentStream;private PDFont font;private float padding = 2f;private float pageMargin = 10f;private float fontSize = 20.0f;private String[] header;private int[] cellSpan;private PDPage page;private float courY;private float leading = 20f;private List<String[]> contexts;private float[] cellWidth;private float[] courXPosion;public Table(PDPage page, PDPageContentStream contentStream, PDFont font, int[] cellSpan, String[] header, List<String[]> contexts) {this.contentStream = contentStream;this.page = page;this.font = font;this.pageWidth = this.page.getMediaBox().getWidth();this.pageHeight = this.page.getMediaBox().getHeight();this.fontHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000f * fontSize;this.fontWidth = font.getAverageFontWidth() / 1000f * fontSize;this.courY = pageHeight - pageMargin;this.header = header;this.cellSpan = cellSpan;this.contexts = contexts;courXPosion = new float[header.length + 1];cellWidth = new float[header.length];courXPosion[0] = pageMargin;for (int i = 0; i < cellSpan.length; i++) {float width = (pageWidth - pageMargin * 2) * (cellSpan[i] / 100f);courXPosion[i + 1] = courXPosion[i] + width;cellWidth[i] = width;}contexts.add(0, header);}public void createTable() throws IOException {//画第一条横线contentStream.moveTo(pageMargin, courY);contentStream.lineTo(pageWidth - pageMargin, courY);contentStream.stroke();//填充内容for (int i = 0; i < contexts.size(); i++) {courY = courY - padding - fontHeight;String[] rows = contexts.get(i);handleData(rows);}//统一画竖线 最后画就可以for (int i = 0; i < courXPosion.length; i++) {contentStream.moveTo(courXPosion[i], pageHeight - pageMargin);contentStream.lineTo(courXPosion[i], courY);contentStream.stroke();}}public void handleData(String[] data) throws IOException {int maxLineNum = 1;float courX = pageMargin + padding;for (int i = 0; i < data.length; i++) {int lineNum = writeText(data[i], cellWidth[i] - padding * 2, courX);maxLineNum = lineNum > maxLineNum ? lineNum : maxLineNum;courX = courX + cellWidth[i];}courY = courY - padding - fontHeight * (maxLineNum - 1 ) - leading * (20f / 72f);contentStream.moveTo(pageMargin, courY);contentStream.lineTo(pageWidth - pageMargin, courY);contentStream.stroke();}public int writeText(String text, float cellWidth, float x) throws IOException {int lineNum = (int) Math.floor(cellWidth / fontWidth);List<String> textList = handleText(text, lineNum);contentStream.beginText();contentStream.setFont(font, fontSize);contentStream.setLeading(leading);contentStream.newLineAtOffset(x, courY);for (int i = 0; i < textList.size(); i++) {//log.info(textList.get(i));contentStream.showText(textList.get(i));contentStream.newLine();}contentStream.endText();return textList.size();}public List<String> handleText(String text, int lineNum) {text = text.replace("\n", "");text = StringUtils.deleteWhitespace(text);List<String> list = new ArrayList<>();if (text.length() <= lineNum) {list.add(text);return list;}while (text.length() > lineNum) {list.add(text.substring(0, lineNum));text = text.substring(lineNum);}if (text.length() > 0) {list.add(text);}return list;}
}
测试调用
@Testpublic void test6() throws IOException {PDDocument document = new PDDocument();PDPage page = new PDPage();PDFont font = PDType0Font.load(document, new File("D://imgtest/font/simfang.ttf"));PDPageContentStream contentStream = new PDPageContentStream(document, page);//组装内容String[] header = new String[]{"序号", "名称", "作者", "时间", "内容"};List<String[]> listText =IntStream.range(0, 2).mapToObj(row ->new String[]{String.valueOf(row + 1),"《沁园春·雪》","毛泽东","1936","北国风光,千里冰封,万里雪飘。望长城内外,惟余莽莽;大河上下,顿失滔滔。山舞银蛇,原驰蜡象,欲与天公试比高。须晴日,看红装素裹,分外妖娆。江山如此多娇,引无数英雄竞折腰。惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。一代天骄,成吉思汗,只识弯弓射大雕。俱往矣,数风流人物,还看今朝。"}).collect(Collectors.toList());//提前设置好列比例,可以自己调整,只要保证最后是100就行int[] cellSpan = {10, 25, 15, 15, 35};Table table = new Table(page, contentStream, font, cellSpan, header, listText);table.createTable();contentStream.close();document.addPage(page);document.save(new File(filePath));}
效果展示
最后
好了以上就是完整的代码和测试用例,当然还有比较多的问题
比如
- 如果这一页满了该怎么办?
- 如果要水平和垂直居中
- 比如要插入图片
有需要的小伙伴可以私信讨论,或者回复索要代码
相关文章:

最新 生成pdf文字和表格
生成pdf文字和表格 先看效果 介绍 java项目,使用apache的pdfbox工具,可分页,自定义列 依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.22<…...

安全基础~攻防特性3
文章目录 SSTI(模板注入)1. 简介2. 成因3. 常见框架存在注入4. 判断存在SSTI SSTI(模板注入) 1. 简介 (Server-Side Template Injection) 服务端模板注入 1、使用框架(MVC的模式),如python的flask,php的tp,java的sp…...

Windows7关闭谷歌浏览器提示“若要接收后续 Google Chrome 更新,您需使用 Windows 10 或更高版本”的方法
背景 电脑比较老,系统一直没有更新,硬件和软件版本如下: 操作系统版本:Windows7 企业版 谷歌浏览器版本:109.0.5414.120(正式版本) (64 位) 该版本的谷歌浏览器是支持…...

[一]ffmpeg音视频解码
[一]ffmpeg音视频解码 一.编译ffmpeg1.安装vmware虚拟机2.vmware虚拟机安装linux操作系统3.安装ftp和fshell软件4.在Ubuntu(Linux)中编译Android平台的FFmpeg( arm和x86 )5.解压FFmpeg6.Android编译脚本(1)…...

k8s-认证授权 14
Kubernetes的认证授权分为认证(鉴定用户身份)、授权(操作权限许可鉴别)、准入控制(资源对象操作时实现更精细的许可检查)三个阶段。 Authentication(认证) 认证方式现共有8种&…...

在全志H616核桃派上实现USB摄像头的OpenCV颜色检测
在给核桃派开发板用OpenCV读取图像并显示到pyqt5的窗口上并加入颜色检测功能,尝试将图像中所有蓝色的东西都用一个框标记出来。 颜色检测核心api 按照惯例,先要介绍一下opencv中常用的hsv像素格式。颜色还是那个颜色,只是描述颜色用的参数变…...

mac安装部署gitbook教程
mac安装部署gitbook教程 前言一、安装准备二、GitBook安装三、项目初始化 前言 一些自己实际操作的记录。 一、安装准备 Node.js gitbook基于Node.js,所以需要提前安装。 下载地址:https://nodejs.org/en/,可以下载比较新的版本。(但我的建议…...

有关软件测试的,任何时间都可以,软件测试主要服务项目:测试用例 报告 计划
有关软件测试的,任何时间都可以,软件测试主要服务项目: 1. 测试用例 2. 测试报告 3. 测试计划 4. 白盒测试 5. 黑盒测试 6. 接口测试 7.自动…...

快乐过寒假,安全不放假
寒假将至,春节即来,为了使孩子们过上一个平安、快乐、文明、祥和、健康、有益的寒假和春节,在共青团永宁县委员会、永宁县望洪镇人民政府的大力支持下,在永宁新华中心村校外少工委的积极配合下,1月20日下午宁夏妇女儿童…...
qt学习:模仿qq界面+添加资源+无边框界面+修改样式
目录 一,创建登录ui界面类 LoginWidget 二,添加图片资源 三,通过样式的方法将图片设置成圆圈的背景 四,新建登录后的ui界面 MWindow 简陋的就可以,因为只为了学习,可以自己补充 五,新建三个嵌套ui界面类,ChatWidget聊天界面 FriendWiidget好友界面 CollectW…...

【Linux】基本指令收尾
文章目录 日期查找打包压缩系统信息Linux和Windows互传文件 日期 这篇是基本指令的收尾了,还有几个基本指令我们需要说一下 首先是Date,它是用来显示时间和日期 直接输入date的话显示是有点不好看的,所以我们可以根据自己的喜欢加上分隔符&…...

精准核酸检测 - 华为OD统一考试
OD统一考试(C卷) 分值: 100分 题解: Java / Python / C 题目描述 为了达到新冠疫情精准防控的需要,为了避免全员核酸检测带来的浪费,需要精准圈定可能被感染的人群。 现在根据传染病流调以及大数据分析&a…...

LINUX文件fd(file descriptor)文件描述符
目录 1.文件接口 1.1open 1.2C语言为什么要对open进行封装 2.fd demo代码 第一个问题 第二个问题 打开文件流程 引言:在学习C语言的时候,我们见过很多的文件的接口,例如fopen,fwrite,fclose等等,但…...
SpringMVC 的理解
MVC MVC(Model-View-Controller)是一种软件设计模式,用于实现用户界面。它将应用程序划分为三个互相交互的部分,以分离内部逻辑表示和表现层。这种分离有助于管理复杂的应用程序,因为它允许开发者单独修改模型、视图或…...

SpringBoot 3.1.7 集成Sentinel
一、背景 我的项目需要引入限流,降级,熔断框架,由于 Spring Cloud 2022.0.4 已经不再支持 Hystrix,Spring Cloud 提供了替代方案,如 Resilience4j,可以使用它来替换 Hystrix。但是网上搜了一下国内Resilie…...

Elastic Stack 8.12:通过对 ES|QL 等的改进增强了向量搜索
作者:来自 Elastic Tyler Perkins, Shani Sagiv, Gilad Gal, Ninoslav Miskovic Elastic Stack 8.12 构建于 Apache Lucene 9.9(有史以来最快的 Lucene 版本)之上,基于我们对标量量化和搜索并发性的贡献,为文本、向量和…...

结构体的内存对齐(计算题常考点)
许久不见我考完试回来啦,让我们接着将结构体进行到底! 目录 结构体对齐的意义: 结构体对齐的实现: 对齐规则: 训练: 好到这里误区来了: 总结: 往期回顾: 下期预告&…...
设置Json对象输出字段顺序
场景 通过情况下对前端输出json格式不需要关注字段顺序,但某些特殊场景需要设置字段输出顺序(例nginx需要对特殊字段顺序进行加密处理);框架有默认的顺序,如 jackson 默认使用字段声明的顺序, fastjson 默认是使用字典序。 jackso…...

当 OpenTelemetry 遇上阿里云 Prometheus
作者:逸陵 背景 在云原生可观测蓬勃发展的当下,想必大家对 OpenTelemetry & Prometheus 并不是太陌生。OpenTelemetry 是 CNCF(Cloud Native Computing Foundation)旗下的开源项目,它的目标是在云原生时代成为应…...

【Flink-1.17-教程】-【四】Flink DataStream API(1)源算子(Source)
【Flink-1.17-教程】-【四】Flink DataStream API(1)源算子(Source) 1)执行环境(Execution Environment)1.1.创建执行环境1.2.执行模式(Execution Mode)1.3.触发程序执行…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...