当前位置: 首页 > news >正文

Java使用IText7动态生成带审批文本框的PDF文档

Java使用IText7动态生成带审批文本框的PDF文档

文章目录

  • Java使用IText7动态生成带审批文本框的PDF文档
    • 1.构建第一个框的起始坐标
    • 2.渲染第一个框
    • 3.渲染其他的审批框

测试结果示例
在这里插入图片描述

实现思路

使用Canvas进行相对定位和绝对定位来确定文本框内文字位置,用Rectangle通过坐标转换来确定文本框的位置

   <itext.version>7.1.2</itext.version>
 <!--itext--><dependency><groupId>com.itextpdf</groupId><artifactId>kernel</artifactId><version>${itext.version}</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>io</artifactId><version>${itext.version}</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>layout</artifactId><version>${itext.version}</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>forms</artifactId><version>${itext.version}</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>pdfa</artifactId><version>${itext.version}</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>pdftest</artifactId><version>${itext.version}</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>font-asian</artifactId><version>${itext.version}</version></dependency>

1.构建第一个框的起始坐标

注意:由于Rectangle构造的坐标为以文档的左下角为xy轴,为了支持计算分页顺序添加需要转换到左上角

        //第一个文本框(非审批框,高度比较大有特殊自动换行需求)// 定义文本框坐标和矩形尺寸(左上点坐标)float xLeftTop = 80;    // 左上角x坐标float yLeftTop = 100;   // 左上角y坐标float width = 450;      // 矩形宽度float height = 300;      // 矩形高度//坐标转换:默认是左下角坐标轴PdfPage firstPage = pdfDoc.getPage(1);float yBottom = firstPage.getPageSize().getHeight() - yLeftTop - height;Rectangle rect = new Rectangle(xLeftTop, yBottom, width, height);

2.渲染第一个框

使用Canvas进行相对定位和绝对定位,来确保文本框内的文字内容位置

为了防止自动换行超出框内,建议Canvas布局的宽度小于文本框的布局

    private void createIndexFieldText(Document doc, PdfFont font, String text, Rectangle rect) {// 创建Canvas进行绝对定位PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());//防止字体出框Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);// 绘制文本框边框pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();//相对定位Paragraph approve = new Paragraph().setFont(font).setFontSize(12).setRelativePosition(10, 10,0,0).add("致______________:");canvas.add(approve);Paragraph approve1 = new Paragraph().setFont(font).setFontSize(12).setFirstLineIndent(25).setRelativePosition(10,  10,0,0).add("________________机构:");canvas.add(approve1);Paragraph approve2 = new Paragraph("我方承担的工程," +"已完成相关准备工作,申请开工,请予以审核,批准。").setTextAlignment(TextAlignment.JUSTIFIED).setFont(font).setFirstLineIndent(25).setRelativePosition(10, 10, 0,0).setFontSize(12);canvas.add(approve2);// 审批相关绝对定位Paragraph fieldText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300).add(text);canvas.add(fieldText);// 在文本框内添加Paragraph dateText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300).add("日期:                        ");canvas.add(dateText);canvas.close();}

3.渲染其他的审批框

原理同大框,需计算是否需要分页,如分页需要重置新页面的起始坐标,且由于大框高度大于其他框,需要重置高度,多个框添加时需计算y轴坐标。

   /*** 添加审批文本框*/private static void addTextField(Document doc, PdfFont font, String text, Rectangle rect,boolean page) {// 创建Canvas进行绝对定位PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());//防止字体出框Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());if(page){pdfCanvas = new PdfCanvas(doc.getPdfDocument().addNewPage());}Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);// 绘制文本框边框pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();//审核意见定位Paragraph approve = new Paragraph().setFont(font).setFontSize(12).setFixedPosition(rect.getX() + 10,  rect.getY()+rect.getHeight()-25,200).add("审核意见:");canvas.add(approve);// 在文本框内添加Paragraph fieldText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300).add(text);canvas.add(fieldText);// 在文本框内添加Paragraph dateText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300).add("日期:                        ");canvas.add(dateText);canvas.close();}

4.完整代码

package com.moshangshang.pdf.controller;import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;@RestController
@RequestMapping("")
public class PDFController {/*** 带文本框的审批表生成*/@GetMapping(value = "/pdf")public void test( HttpServletResponse response) throws Exception {response.setContentType("application/pdf");OutputStream os = response.getOutputStream();// 创建 PDF 文档PdfDocument pdfDoc = new PdfDocument(new PdfWriter(os));Document document = new Document(pdfDoc,PageSize.A4);PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", true);// 设置页面尺寸和边距document.setMargins(50, 50, 50, 50);Paragraph title = new Paragraph("审批测试表").setTextAlignment(TextAlignment.CENTER).setFont(font).setBold().setFontSize(22);document.add(title);List<String> unitList = Arrays.asList("测试1","测试2","测试3","测试4","测试5","测试6","测试7","测试8","测试9");//文本框绘制索引int fieldTextIndex = 1;//第一个文本框(非审批框,高度比较大有特殊自动换行需求)// 定义文本框坐标和矩形尺寸(左上点坐标)float xLeftTop = 80;    // 左上角x坐标float yLeftTop = 100;   // 左上角y坐标float width = 450;      // 矩形宽度float height = 300;      // 矩形高度//坐标转换:默认是左下角坐标轴PdfPage firstPage = pdfDoc.getPage(1);float yBottom = firstPage.getPageSize().getHeight() - yLeftTop - height;Rectangle rect = new Rectangle(xLeftTop, yBottom, width, height);for (String name : unitList) {//定位if(fieldTextIndex == 1){//开工报告第一个大框添加createIndexFieldText(document, font, name+"(签字、印章):", rect,false);}else {//其他全为同等审批框,修改高度height = 150;//默认第一页三个框,其他页默认四个if(fieldTextIndex%4==0){//如果大于单页数量,创建新页,并重置坐标float yBottom1 = firstPage.getPageSize().getHeight() - yLeftTop - height;rect = new Rectangle(xLeftTop, yBottom1, width, height);addTextField(document, font, name+" (签字、印章):", rect,true);fieldTextIndex++;continue;}rect = new Rectangle(xLeftTop, rect.getY()-height, width, height);// 绘制文本框边框addTextField(document, font, name+"(签字、印章):", rect,false);}fieldTextIndex++;}document.close();}/****/private void createIndexFieldText(Document doc, PdfFont font, String text, Rectangle rect,boolean page) {// 创建Canvas进行绝对定位PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());//防止字体出框Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());if(page){pdfCanvas = new PdfCanvas(doc.getPdfDocument().addNewPage());}Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);// 绘制文本框边框pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();//相对定位Paragraph approve = new Paragraph().setFont(font).setFontSize(12).setRelativePosition(10,  10,0,0).add("致______________(单位):");canvas.add(approve);Paragraph approve1 = new Paragraph().setFont(font).setFontSize(12).setFirstLineIndent(25).setRelativePosition(10,  10,0,0).add("________________机构:");canvas.add(approve1);Paragraph approve2 = new Paragraph("我方," +"已完成相关准备工作,具备开工条件,申请于2025年开工,请予以审核,批准。").setTextAlignment(TextAlignment.JUSTIFIED).setFont(font).setFirstLineIndent(25).setRelativePosition(10, 10, 0,0).setFontSize(12);canvas.add(approve2);// 审批相关绝对定位Paragraph fieldText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300).add(text);canvas.add(fieldText);// 在文本框内添加Paragraph dateText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300).add("日期:                        ");canvas.add(dateText);canvas.close();}/*** 添加审批文本框*/private static void addTextField(Document doc, PdfFont font, String text, Rectangle rect,boolean page) {// 创建Canvas进行绝对定位PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());//防止字体出框Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());if(page){pdfCanvas = new PdfCanvas(doc.getPdfDocument().addNewPage());}Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);// 绘制文本框边框pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();//审核意见定位Paragraph approve = new Paragraph().setFont(font).setFontSize(12).setFixedPosition(rect.getX() + 10,  rect.getY()+rect.getHeight()-25,200).add("审核意见:");canvas.add(approve);// 在文本框内添加Paragraph fieldText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300).add(text);canvas.add(fieldText);// 在文本框内添加Paragraph dateText = new Paragraph().setFont(font).setFontSize(12).setTextAlignment(TextAlignment.RIGHT).setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300).add("日期:                        ");canvas.add(dateText);canvas.close();}}

相关文章:

  • 【Nova UI】十、打造组件库第一个组件-图标组件(下):从.svg 到 SVG Vue 组件的高效蜕变✨
  • LeetCode 1780 判断一个数字是否可以表示成三的幂的和
  • AI超级智能体项目教程(二)---后端项目初始化(设计knif4j接口文档的使用)
  • PHP框架在微服务迁移中能发挥什么作用?
  • 测试流程?
  • 猫咪如厕检测与分类识别系统系列【十三】猫咪进出事件逻辑及日志优化【下】
  • 计算机组成原理:指令系统
  • 10前端项目----商品详情页/滚轮行为
  • Java多线程同步有哪些方法?
  • top 命令里面可以看到进程哪些状态?
  • java排序算法-计数排序
  • 非序列实现MEMS聚焦功能
  • 【Redis】hash类型
  • day37图像处理OpenCV
  • Huffman(哈夫曼)解/压缩算法实现
  • 高职人工智能技术应用专业(计算机视觉方向)实训室解决方案
  • 蜜罐管理和数据收集服务器:Modern Honey Network (MHN)
  • Linux 内核网络协议栈中 inet_stream_ops 与 tcp_prot 的深度解析
  • Python----深度学习(基于深度学习Pytroch簇分类,圆环分类,月牙分类)
  • uniapp 仿企微左边公司切换页
  • 网警侦破特大“刷量引流”网络水军案:涉案金额达2亿余元
  • 外交部回应涉长江和记出售巴拿马运河港口交易:望有关各方审慎行事,充分沟通
  • 马上评|“AI神医宇宙”欺诈,连演员都不请了
  • 四川在浙江公开招募200名退休教师,赴川支教帮扶
  • 李勇已任内蒙古乌兰察布市委副书记,曾在中央编办任职
  • 大家聊中国式现代化|陶希东:打造高水平安全韧性城市,给群众看得见的安全感