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

server/2025/2/13 7:07:44/

朋友们!在实际业务场景中,经常会碰到处理 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 在原模板基础上进行修改。通过指定页码和坐标,把公章、签名图片插入到对应位置,同时在指定坐标处添加日期文本。

示例代码

 
java">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 模板文件,逐页查找包含关键字的页面。找到页面后,在该页面根据关键字的位置来插入公章、签名图片和日期文本。

示例代码

 
java">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.ppmy.cn/server/167268.html

相关文章

Python——批量图片转PDF(GUI版本)

目录 专栏导读1、背景介绍2、库的安装3、核心代码4、完整代码总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——>Python办公自动化专…

MybatisPlus常用增删改查

记录下MybatisPlus的简单的增删改查 接口概述 Service和Mapper区别 Mapper简化了单表的sql操作步骤&#xff08;CRUD&#xff09;&#xff0c;而Serivce则是对Mapper的功能增强。 Service虽然加入了数据库的操作&#xff0c;但还是以业务功能为主&#xff0c;而更加复杂的SQL…

《Coresight/Trace/Debug大合集》64节课16小时,6大主题, 685页PPT

CSDN学院课程连接&#xff1a;https://edu.csdn.net/course/detail/39573 虽然说当前已经完结了&#xff0c;但后续可能会持续更新。

【Day38 LeetCode】动态规划DP 子序列问题Ⅱ

一、动态规划DP 子序列问题Ⅱ 1、最长公共子序列 1143 确定dp数组含义&#xff0c;dp[i][j]表示长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列的长度。 dp转移关系&#xff0c;对于当前值dp[i][j], 分为text1[i - 1] 与 text2[j - 1]相同与…

PhotoShop中创建窗口使用对应按钮创建对应图层简单示例

以前在使用Photoshop的PSD文件转换成Unity的UI Prefab工具的时候&#xff0c;想过是否能在PhotoShop中创建“组件”方式创建层&#xff0c;然后通过代码给层做重命名&#xff0c;不需要手动改写层的名字&#xff0c;可以直接创建所需数量的图层并按照层级排列&#xff0c;具体思…

大模型deepseek-r1 本地快速搭建

1、安装部署ollama 详细步骤见&#xff1a;Ollama 下载和安装 官网下载地址&#xff1a;Ollama官网 2、大模型Deepseekk-r1下载 详细步骤见&#xff1a;大模型deepseek-r1 本地ollama部署详解 ollama run deepseek-r13、Open WebUI部署详解 详细见步骤&#xff1a;大模型d…

DeepSeek+图生生:电商制作商品图的高效方案,适合大众生图的AI工具

在电商红海竞争中&#xff0c;商品视觉呈现已成为流量争夺的核心战场。然而&#xff0c;传统拍摄模式面临多重瓶颈&#xff0c;成本高昂、效率低下等。 而DeepSeek与图生生的结合使用&#xff0c;正以“AI提示词智能生图”的协作模式&#xff0c;为商家提供零成本、分钟级、高…

蓝桥杯---N字形变换(leetcode第6题)题解

文章目录 1.问题重述2.例子分析3.思路讲解4.代码分析 1.问题重述 这个题目可以是Z字形变换&#xff0c;也可以叫做N字形变换&#xff1a; 给定我们一串字符&#xff0c;我们需要把这串字符按照先往下写&#xff0c;再往右上方去写&#xff0c;再往下去写&#xff0c;再往右上…