Java 魔法:精准掌控 PDF 合同模板,指定页码与关键字替换签章日期

朋友们!在实际业务场景中,经常会碰到处理 PDF 合同模板的需求,要在几十页的合同里对指定页面替换公章、签名和日期,还涉及多人签名以及多个公司盖公章。下面就给大家分享两种用 Java 处理这类问题的方法,一种是通过指定页码和坐标,另一种是通过指定页面关键字来进行替换。

准备工作

咱们使用 iText 库来完成这些操作,如果你用 Maven 管理项目,在 pom.xml 里添加以下依赖:

 
<dependencies><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13.3</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency>
</dependencies>

方法一:指定页码坐标进行替换

实现思路

先读取 PDF 模板文件,利用 PdfStamper 在原模板基础上进行修改。通过指定页码和坐标,把公章、签名图片插入到对应位置,同时在指定坐标处添加日期文本。

示例代码

 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;public class PdfContractProcessorByCoordinate {public static void main(String[] args) {String templatePath = "contract_template.pdf";String outputPath = "contract_output_by_coordinate.pdf";String sealImagePath1 = "seal1.png";String sealImagePath2 = "seal2.png";String signatureImagePath1 = "signature1.png";String signatureImagePath2 = "signature2.png";try {// 读取 PDF 模板PdfReader reader = new PdfReader(templatePath);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPath));// 获取首页、中间页和最后一页int totalPages = reader.getNumberOfPages();int middlePage = totalPages / 2;// 插入公章和签名insertImage(stamper, sealImagePath1, 1, 200, 200); // 首页插入公章 1insertImage(stamper, sealImagePath2, middlePage, 300, 300); // 中间页插入公章 2insertImage(stamper, signatureImagePath1, totalPages, 400, 400); // 最后一页插入签名 1insertImage(stamper, signatureImagePath2, totalPages, 500, 400); // 最后一页插入签名 2// 插入日期insertDate(stamper, 1, 200, 100); // 首页插入日期// 关闭 stamper 和 readerstamper.close();reader.close();System.out.println("PDF 合同处理完成(指定页码坐标)!");} catch (IOException | DocumentException e) {e.printStackTrace();}}/*** 在指定页面插入图片* @param stamper PdfStamper 对象* @param imagePath 图片路径* @param pageNumber 页面编号* @param x 图片插入的 x 坐标* @param y 图片插入的 y 坐标* @throws IOException* @throws DocumentException*/private static void insertImage(PdfStamper stamper, String imagePath, int pageNumber, float x, float y) throws IOException, DocumentException {Image image = Image.getInstance(imagePath);image.scaleToFit(100, 100); // 调整图片大小image.setAbsolutePosition(x, y);PdfContentByte contentByte = stamper.getOverContent(pageNumber);contentByte.addImage(image);}/*** 在指定页面插入日期* @param stamper PdfStamper 对象* @param pageNumber 页面编号* @param x 日期插入的 x 坐标* @param y 日期插入的 y 坐标* @throws DocumentException* @throws IOException*/private static void insertDate(PdfStamper stamper, int pageNumber, float x, float y) throws DocumentException, IOException {PdfContentByte contentByte = stamper.getOverContent(pageNumber);PdfTemplate template = contentByte.createTemplate(100, 30);ColumnText columnText = new ColumnText(template);// 设置字体BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);com.itextpdf.text.Font font = new com.itextpdf.text.Font(baseFont, 12);// 获取当前日期SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");String currentDate = dateFormat.format(new Date());columnText.addElement(new com.itextpdf.text.Paragraph(currentDate, font));columnText.setSimpleColumn(0, 0, 100, 30);columnText.go();contentByte.addTemplate(template, x, y);}
}

代码解释

  • main 方法:读取 PDF 模板文件,创建 PdfStamper 对象,调用 insertImage 方法插入公章和签名图片,调用 insertDate 方法插入日期,最后关闭 PdfStamperPdfReader

  • insertImage 方法:将指定路径的图片插入到指定页面的指定位置。

  • insertDate 方法:在指定页面的指定位置插入当前日期。

方法二:指定页面关键字进行替换

实现思路

先读取 PDF 模板文件,逐页查找包含关键字的页面。找到页面后,在该页面根据关键字的位置来插入公章、签名图片和日期文本。

示例代码

 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;public class PdfContractProcessorByKeyword {public static void main(String[] args) {String templatePath = "contract_template.pdf";String outputPath = "contract_output_by_keyword.pdf";String sealImagePath1 = "seal1.png";String sealImagePath2 = "seal2.png";String signatureImagePath1 = "signature1.png";String signatureImagePath2 = "signature2.png";String keyword1 = "甲方签字";String keyword2 = "乙方盖章";try {// 读取 PDF 模板PdfReader reader = new PdfReader(templatePath);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPath));// 查找关键字并插入内容findAndReplace(stamper, reader, keyword1, sealImagePath1, signatureImagePath1);findAndReplace(stamper, reader, keyword2, sealImagePath2, signatureImagePath2);// 插入日期insertDateByKeyword(stamper, reader, "合同日期", 50, 20);// 关闭 stamper 和 readerstamper.close();reader.close();System.out.println("PDF 合同处理完成(指定页面关键字)!");} catch (IOException | DocumentException e) {e.printStackTrace();}}/*** 查找关键字并插入公章和签名* @param stamper PdfStamper 对象* @param reader PdfReader 对象* @param keyword 关键字* @param sealImagePath 公章图片路径* @param signatureImagePath 签名图片路径* @throws IOException* @throws DocumentException*/private static void findAndReplace(PdfStamper stamper, PdfReader reader, String keyword, String sealImagePath, String signatureImagePath) throws IOException, DocumentException {int totalPages = reader.getNumberOfPages();for (int page = 1; page <= totalPages; page++) {String pageText = PdfTextExtractor.getTextFromPage(reader, page);if (pageText.contains(keyword)) {// 假设在关键字下方一定位置插入公章和签名float x = 200;float y = getYPosition(pageText, keyword) - 150;insertImage(stamper, sealImagePath, page, x, y);insertImage(stamper, signatureImagePath, page, x + 150, y);}}}/*** 根据关键字插入日期* @param stamper PdfStamper 对象* @param reader PdfReader 对象* @param keyword 关键字* @param offsetX x 偏移量* @param offsetY y 偏移量* @throws DocumentException* @throws IOException*/private static void insertDateByKeyword(PdfStamper stamper, PdfReader reader, String keyword, float offsetX, float offsetY) throws DocumentException, IOException {int totalPages = reader.getNumberOfPages();for (int page = 1; page <= totalPages; page++) {String pageText = PdfTextExtractor.getTextFromPage(reader, page);if (pageText.contains(keyword)) {float x = 200;float y = getYPosition(pageText, keyword) + offsetY;insertDate(stamper, page, x + offsetX, y);}}}/*** 获取关键字的 y 坐标(简单示例,实际可能需要更复杂的计算)* @param pageText 页面文本* @param keyword 关键字* @return y 坐标*/private static float getYPosition(String pageText, String keyword) {// 这里简单返回一个固定值,实际应用中需要根据文本布局计算return 500;}/*** 在指定页面插入图片* @param stamper PdfStamper 对象* @param imagePath 图片路径* @param pageNumber 页面编号* @param x 图片插入的 x 坐标* @param y 图片插入的 y 坐标* @throws IOException* @throws DocumentException*/private static void insertImage(PdfStamper stamper, String imagePath, int pageNumber, float x, float y) throws IOException, DocumentException {Image image = Image.getInstance(imagePath);image.scaleToFit(100, 100); // 调整图片大小image.setAbsolutePosition(x, y);PdfContentByte contentByte = stamper.getOverContent(pageNumber);contentByte.addImage(image);}/*** 在指定页面插入日期* @param stamper PdfStamper 对象* @param pageNumber 页面编号* @param x 日期插入的 x 坐标* @param y 日期插入的 y 坐标* @throws DocumentException* @throws IOException*/private static void insertDate(PdfStamper stamper, int pageNumber, float x, float y) throws DocumentException, IOException {PdfContentByte contentByte = stamper.getOverContent(pageNumber);PdfTemplate template = contentByte.createTemplate(100, 30);ColumnText columnText = new ColumnText(template);// 设置字体BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);com.itextpdf.text.Font font = new com.itextpdf.text.Font(baseFont, 12);// 获取当前日期SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");String currentDate = dateFormat.format(new Date());columnText.addElement(new com.itextpdf.text.Paragraph(currentDate, font));columnText.setSimpleColumn(0, 0, 100, 30);columnText.go();contentByte.addTemplate(template, x, y);}
}

代码解释

  • main 方法:读取 PDF 模板文件,创建 PdfStamper 对象,调用 findAndReplace 方法根据关键字插入公章和签名,调用 insertDateByKeyword 方法根据关键字插入日期,最后关闭 PdfStamperPdfReader

  • findAndReplace 方法:逐页查找包含关键字的页面,在该页面根据关键字的位置插入公章和签名图片。

  • insertDateByKeyword 方法:逐页查找包含关键字的页面,在该页面根据关键字的位置插入日期。

  • getYPosition 方法:获取关键字的 y 坐标,这里只是简单返回一个固定值,实际应用中需要根据文本布局进行更复杂的计算。

朋友们!通过这两种方法,你就可以使用 Java 灵活地处理 PDF 合同模板,替换指定页面的公章、签名和日期啦。赶紧动手试试吧!

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

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

相关文章

e2studio开发RA4M2(10)----定时器AGT输出PWM

e2studio开发RA4M2.10--定时器AGT输出PWM 概述视频教学样品申请硬件准备参考程序源码下载选择计时器新建工程工程模板保存工程路径芯片配置工程模板选择时钟设置SWD调试口设置GPIO口配置AGT定时器AGT定时器属性配置初始化AGT启动AGT PWM模块AGTIO 和 AGTO演示 概述 AGT模块是R…

使用PyCharm进行Django项目开发环境搭建

如果在PyCharm中创建Django项目 1. 打开PyCharm&#xff0c;选择新建项目 2.左侧选择Django&#xff0c;并设置项目名称 3.查看项目解释器初始配置 4.新建应用程序 执行以下操作之一&#xff1a; 转到工具| 运行manage.py任务或按CtrlAltR 在打开的manage.pystartapp控制台…

【Java基础】为什么不支持多重继承?方法重载和方法重写之间区别、Exception 和 Error 区别?

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;Java基础面经 &#x1f4da;本系列文章为个…

【Jetson Nano安装gpu版pytroch1.7torchvision0.8.1 in python3.8 跑 Ultralytics YOLO】

文章目录 1. 系统环境2. 安装torch1.7.03. 安装torchvision0.8.14. 参考文献 1. 系统环境 笔者的jetson nano b01的系统版本如下&#xff1a; 环境版本JetPack4.4Ubuntu18.04python(Miniforge3环境)3.8python3(系统自带环境)3.6.9python2(系统自带环境)2.7 由于Ultralytics …

bladeX微服务框架如何修改nacos分组

nacos中注册的服务他的分组&#xff08;分组名称&#xff09;怎么修改 在org.springblade.common.launch // 指定注册IP PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.ip", "127.0.0.1"); // 指定注册端口 PropsUtil.setProperty(props, &…

大数据项目2a:基于spark的电影推荐和分析系统设计与实现

1、项目目的 本项目的目的是设计并实现一个基于Spark的电影推荐系统&#xff0c;以应对大数据环境下电影推荐服务的挑战。通过整合电影、评分和用户数据集&#xff0c;并利用SparkSql框架进行高效处理&#xff0c;系统能够为用户提供个性化的电影推荐。项目采用多种先进技术&…

机器学习常用包matplotlib篇(四)绘图规范

前言 为了让 Matplotlib 绘图代码更规范、易读&#xff0c;且为后期图形完善预留空间&#xff0c;建议遵循一些规范绘图方法。&#x1f609; 1.管理图形对象 建议使用 plt.figure() 或者 plt.subplots() 管理完整的图形对象&#xff0c;而非直接用 plt.plot(...) 绘图。这样能…

LVGL4种输入设备详解(触摸、键盘、实体按键、编码器)

lvgl有触摸、键盘、实体按键、编码器四种输入设备 先来分析一下这四种输入设备有什么区别 &#xff08;1&#xff09;LV_INDEV_TYPE_POINTER 主要用于触摸屏 用到哪个输入设备保留哪个其他的也是&#xff0c;保留触摸屏输入的任务注册&#xff0c;其它几种种输入任务的注册&…

5G技术解析:从核心概念到关键技术

1. 引言 5G技术的迅猛发展正在重塑我们的生活方式和社会结构。它不仅仅是新一代的移动通信技术&#xff0c;更是一场深刻的技术革命。5G网络正在以其惊人的高速、低延迟和大带宽能力&#xff0c;为智能家居、自动驾驶、工业自动化、远程医疗等另一带来前所未有的可能性。 本文…

背包问题1

核心&#xff1a; // f[i][j] 表示只看前i个物品&#xff0c;总体积是j的情况下&#xff0c;总价值是多少 //res maxx(f[n][]0-v] //f[i][j]: //1 不选第i个物品 f[i][j] f[i-1][j] //2 选第i个物品 f[i][j] f[i-1][j-v[i]] w[i]

Redis | 十大数据类型

文章目录 十大数据类型概述key操作命令数据类型命令及落地运用redis字符串&#xff08;String&#xff09;redis列表&#xff08;List&#xff09;redis哈希表&#xff08;Hash&#xff09;redis集合&#xff08;Set&#xff09;redis有序集合&#xff08;ZSet / SortedSet&…

AI-学习路线图-PyTorch-我是土堆

1 需求 PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆】_哔哩哔哩_bilibili PyTorch 深度学习快速入门教程 配套资源 链接 视频教程 https://www.bilibili.com/video/BV1hE411t7RN/ 文字教程 https://blog.csdn.net/xiaotudui…

DeepSeek图解10页PDF

以前一直在关注国内外的一些AI工具&#xff0c;包括文本型、图像类的一些AI实践&#xff0c;最近DeepSeek突然爆火&#xff0c;从互联网收集一些资料与大家一起分享学习。 本章节分享的文件为网上流传的DeepSeek图解10页PDF&#xff0c;免费附件链接给出。 1 本地 1 本地部…

C# OpenCvSharp 部署MOWA:多合一图像扭曲模型

目录 说明 效果 项目 代码 下载 参考 C# OpenCvSharp 部署MOWA&#xff1a;多合一图像扭曲模型 说明 算法模型的paper名称是《MOWA: Multiple-in-One Image Warping Model》 ariv链接 https://arxiv.org/pdf/2404.10716 效果 Stitched Image 翻译成中文意思是&…

vite+vue3搭建前端项目并使用 Bulma 框架

vitevue3搭建前端项目并使用 Bulma 框架 bluma css框架参照。 https://bulma.org.cn/documentation/start/overview/ 1. 创建项目 npm init vitelatest ai-imageneration --template vue选择 vue 和 typescript 作为模板&#xff1a; 2. 安装依赖 npm install npm install…

Spring 6.2.2 @scope(“prototype“)原理

Spring Prototype 原理&#xff1f; 前置准备 创建一个MyService类 Scope("prototype") Service("myService") public class MyService {public String getMessage() {return "Hello, World!";} }创建一个main类&#xff0c;用于debug。 pr…

Android车机DIY开发之软件篇(十) NXP MfgTool和UUU的使用

标题Android车机DIY开发之软件篇(十) NXP MfgTool和UUU的使用 一、MfgTool工具 1.基本原理 1、先向DDR下载一个linux系统2. 通过linux完成烧写files里面保存的是最终保存到开发板中的uboot.imx zimage dtb rootfsvbs是在打开mfgtool2和很多参数ucl2.xml表示文件选择 定义自…

RabbitMQ 可靠性投递

文章目录 前言一、RabbitMQ自带机制1、生产者发送消息注意1.1、事务&#xff08;Transactions&#xff09;1.2、发布确认&#xff08;Publisher Confirms&#xff09;1.2.1、同步1.2.2、异步 2、消息路由机制2.1、使用备份交换机&#xff08;Alternate Exchanges&#xff09;2.…

番外02:前端八股文面试题-CSS篇

一&#xff1a;CSS基础 1&#xff1a;CSS选择器及其优先级 2&#xff1a;display的属性值及其作用 属性值作用none元素不显示&#xff0c;并且会从文档流中移除block块类型&#xff0c;默认元素为父元素宽度&#xff0c;可设置宽高&#xff0c;换行显示inline行内元素类型&a…

如何在C++ QT 程序中集成cef3开源浏览器组件去显示网页?

文章目录 1. **准备工作**1.1 下载CEF31.2 配置Qt项目 2. **集成CEF3到Qt窗口**2.1 创建Qt窗口容器2.2 初始化CEF3 3. **处理CEF3消息循环**4. **处理多进程架构**5. **完整代码示例**main.cpp 6. **常见问题**6.1 黑屏问题6.2 窗口嵌入失败6.3 多进程调试 7.**Github源码参考*…