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.rhkb.cn/news/15131.html

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

相关文章

我们来学人工智能 -- 将Ollama已下载的模型从C盘迁出

题记 未配置OLLAMA_MODELS系统变量导致模型下载到了C盘 迁移步骤 退出ollama 配置OLLAMA_MODELS系统变量 OLLAMA_MODELS&#xff1a;D:\ollama\models 直接将C盘下的models目录剪切到指定目录 检查 cmd命令窗口退出重新打开

Redis 集群原理、主从复制和哨兵模式的详细讲解

引言&#xff1a;本文记录了博主在学习Redis的过程中的原理&#xff0c;了解为什么使用与怎么样使用 Redis 集群&#xff0c;在使用 Redis 集群时出现的主从复制和哨兵模式的相关知识。本文并不涉及Redis安装。 文章目录 一、简单介绍什么是 Redis二、为什么要使用 Redis 集群三…

Java数据结构 | TreeMap 和 TreeSet

TreeMap 和 TreeSet 1. 搜索树1.1 概念1.2 搜索树的查找、插入、删除思路及代码1.2.1 查找1.2.2 插入1.2.3 删除&#xff08;难点&#xff09; 1.3 二叉搜索树的性能分析 2. Map 和 Set2.1 Map 接口2.1.1 Map.Entry<K,V>2.1.2 Map的常用方法 2.2 Set 接口2.2.1 Set 的常用…

智能理解 PPT 内容,快速生成讲解视频

当我们想根据一版 PPT 制作出相对应的解锁视频时&#xff0c;从撰写解锁词&#xff0c;录制音频到剪辑视频&#xff0c;每一个环节都需要投入大量的时间和精力&#xff0c;本方案将依托于阿里云函数计算 FC 和百炼模型服务&#xff0c;实现从 PPT 到视频的全自动转换&#xff0…

小鹅通首页网页开发

一、小鹅通首页开发 二、代码&#xff1a; index.html: <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…

离散型变量的 PSI-群体稳定性指标计算

文章目录 PSI-群体稳定性指标(离散型)单个指标计算所有指标计算 PSI-群体稳定性指标(离散型) 单个指标计算 代码 import pandas as pddf pd.read_csv(/Users/mengzhichao/Desktop/文件/图表/小微企业用电量数据.csv)X_train df.sample(n7000) X_test df.sample(n3000)计算单…

STM32G474--Whetstone程序移植(单精度)笔记

1 准备基本工程代码 参考这篇笔记从我的仓库中选择合适的基本工程&#xff0c;进行程序移植。这里我用的是stm32g474的基本工程。 使用git clone一个指定文件或者目录 2 移植程序 2.1 修改Whetstone.c 主要修改原本变量定义的类型&#xff0c;以及函数接口全部更换为单精度…

【电机控制器】STC8H1K芯片——低功耗

【电机控制器】STC8H1K芯片——低功耗 文章目录 [TOC](文章目录) 前言一、芯片手册说明二、IDLE模式三、PD模式四、PD模式唤醒五、实验验证1.接线2.视频&#xff08;待填&#xff09; 六、参考资料总结 前言 使用工具&#xff1a; 1.STC仿真器烧录器 提示&#xff1a;以下是本…

Neo4j图数据库学习(二)——SpringBoot整合Neo4j

一. 前言 本文介绍如何通过SpringBoot整合Neo4j的方式&#xff0c;对图数据库进行简单的操作。 Neo4j和SpringBoot的知识不再赘述。关于Neo4j的基础知识&#xff0c;有兴趣可以看看作者上一篇的文章&#xff1a;Neo4j图数据库学习(一)——初识CQL 二. 前置准备 新建SpringBo…

【后端开发】系统设计101——Devops,Git与CICD,云服务与云原生,Linux,安全性,案例研究(30张图详解)

【后端开发】系统设计101——Devops&#xff0c;Git与CICD&#xff0c;云服务与云原生&#xff0c;Linux&#xff0c;安全性&#xff0c;案例研究&#xff08;30张图详解&#xff09; 文章目录 1、DevopsDevOps与SRE与平台工程的区别是什么&#xff1f;什么是k8s&#xff08;Ku…

01_Machine Vision_LSI及傅立叶变换

outline 图像分解和线性时不变系统二维傅立叶变换图像采样 图像分解和线性时不变系统 图像数学表达 图像由基本的像素点组成&#xff0c;如果将每一个像素点看作一个脉冲&#xff0c;则每个像素点的值可以看作是脉冲的幅值&#xff0c;这样图像就可以看作是由一系列脉冲组成…

elasticsearch实战三 elasticsearch与mysql数据实时同步

一 介绍 elasticsearch数据不是一直不变的&#xff0c;需要与mysql、oracle等数据库的数据做同步。 本博客里涉及到的项目地址&#xff1a;https://www.aliyundrive.com/s/7bRWpTYsxWV 方案一&#xff1a; 同步调用&#xff0c;即操作mysql数据后&#xff0c;接着操作elastic…

智能化食品安全管理:AI视频监控在大型商场的技术方案

前言 在卖场中&#xff0c;尤其是熟食区&#xff0c;AI视频监控的应用对于食品安全至关重要。通过AI视频监控系统&#xff0c;卖场可以实时监测食品处理环节中的每一个细节&#xff0c;从员工的个人防护到清洁操作&#xff0c;再到区域管理&#xff0c;全面提升食品安全管理的…

分析模式应用――帐务模式02

Party 模式中的层次结构模型支持多种灵活的层次结构&#xff0c;但这里我们只要关心上下级的包含关系就可以了&#xff0c;参加结算的称为结算实体BalanceEntity&#xff0c; 不可再拆分的称为LeafEntity&#xff0c; 可以包含下级结算实体的称为CompositeEntity&#xff0c;因…

什么是网络安全

1) 什么是网络安全 作为程序员&#xff0c;主要是面向产品的安全的问题。比如sql注入&#xff0c;xss&#xff0c;csrf&#xff0c;cookie窃取等等&#xff0c;都值得我们去思考。保证网站运行正常&#xff0c;客户数据安全。 2) sql注入 简单的说&#xff0c;就是利用表单提…

2025年软件测试五大趋势:AI、API安全、云测试等前沿实践

随着软件开发的不断进步&#xff0c;测试方法也在演变。企业需要紧跟新兴趋势&#xff0c;以提升软件质量、提高测试效率&#xff0c;并确保安全性&#xff0c;在竞争激烈的技术环境中保持领先地位。本文将深入探讨2025年最值得关注的五大软件测试趋势。 Parasoft下载https://…

等级保护2.0|网络安全服务

等级保护2.0|网络安全服务 定义 对于国家秘密信息、法人和其他组织及公民专有信息以及公开信息的存储、传输、处理这些信息系统分等级实行安全保护&#xff0c;对信息系统中发生的信息安全时间分等级响应、处置。 思想 对信息安全实行等级化保护和等级化管理 目标 突出重…

Spatial Branching for Conic Non-Convexities in Optimal Electricity-Gas Flow

摘要—本文提出了一种基于几何的空间分支策略&#xff08; spatial branching strategy&#xff09;&#xff0c;用于解决集成电力-燃气系统中的圆锥非凸方程&#xff08; conic non-convex equations&#xff09;。所提出的策略嵌入在空间分支定界算法中&#xff0c;以求解最优…

ChunkKV:优化 KV 缓存压缩,让 LLM 长文本推理更高效

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

IDEA编写SpringBoot项目时使用Lombok报错“找不到符号”的原因和解决

目录 概述|背景 报错解析 解决方法 IDEA配置解决 Pom配置插件解决 概述|背景 报错发生背景&#xff1a;在SpringBoot项目中引入Lombok依赖并使用后出现"找不到符号"的问题。 本文讨论在上述背景下发生的报错原因和解决办法&#xff0c;如果仅为了解决BUG不论原…