From 3849263b31a16a91ff08acaa42786ecfde76f33c Mon Sep 17 00:00:00 2001
From: zhangback <zhangback@163.com>
Date: 星期四, 27 十一月 2025 20:18:08 +0800
Subject: [PATCH] 提交
---
common/src/main/java/com/ruoyi/common/utils/PdfTemplateUtil.java | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 239 insertions(+), 0 deletions(-)
diff --git a/common/src/main/java/com/ruoyi/common/utils/PdfTemplateUtil.java b/common/src/main/java/com/ruoyi/common/utils/PdfTemplateUtil.java
new file mode 100644
index 0000000..a986295
--- /dev/null
+++ b/common/src/main/java/com/ruoyi/common/utils/PdfTemplateUtil.java
@@ -0,0 +1,239 @@
+package com.ruoyi.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
+import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton;
+import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.Base64;
+import java.util.Map;
+@Slf4j
+public class PdfTemplateUtil {
+ /**
+ * 濉厖 PDF 琛ㄥ崟瀛楁
+ *
+ * @param templatePdf 妯℃澘 PDF 璺緞
+ * @param outputPdf 杈撳嚭 PDF 璺緞
+ * @param params key=琛ㄥ崟瀛楁鍚�, value=濉厖鍊�
+ * @param fontPath 涓枃瀛椾綋 ttf 璺緞
+ * @throws Exception
+ */
+
+ public static void fillPdf(String templatePdf, String outputPdf, Map<String, String> params, String fontPath) throws Exception {
+ PDDocument document = PDDocument.load(new File(templatePdf));
+ PDAcroForm form = document.getDocumentCatalog().getAcroForm();
+
+ PDType0Font font = PDType0Font.load(document, new File(fontPath));
+
+ // 娉ㄥ唽瀛椾綋璧勬簮
+ PDResources resources = form.getDefaultResources();
+ if (resources == null) {
+ resources = new PDResources();
+ form.setDefaultResources(resources);
+ }
+ COSName fontResName = resources.add(font);
+
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ PDField field = form.getField(entry.getKey());
+
+ // 鏂囧瓧瀛楁
+ if (field instanceof PDTextField) {
+ PDTextField tf = (PDTextField) field;
+ tf.setDefaultAppearance("/" + fontResName.getName() + " 10 Tf 0 0 0 rg");
+ tf.getCOSObject().setInt(COSName.Q, 1); // 姘村钩灞呬腑
+ tf.setValue(entry.getValue());
+ }
+
+ // 鍥剧墖鎸夐挳瀛楁
+ if (field instanceof PDPushButton) {
+ PDPushButton button = (PDPushButton) field;
+ String imgBase64 = entry.getValue();
+
+ if (imgBase64.contains(",")) {
+ imgBase64 = imgBase64.split(",")[1]; // 鍘绘帀鍓嶇紑
+ }
+
+ byte[] imageBytes;
+
+ if (entry.getValue().startsWith("data:image/svg+xml;base64,")) {
+ // SVG 杞� PNG
+ byte[] svgBytes = Base64.getDecoder().decode(imgBase64);
+ ByteArrayInputStream svgStream = new ByteArrayInputStream(svgBytes);
+ PNGTranscoder transcoder = new PNGTranscoder();
+
+ // 杈撳嚭鍒� ByteArray
+ ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
+ TranscoderInput input = new TranscoderInput(svgStream);
+ TranscoderOutput output = new TranscoderOutput(pngOut);
+ transcoder.transcode(input, output);
+ pngOut.flush();
+ pngOut.close();
+ imageBytes = pngOut.toByteArray();
+
+ // BufferedImage 璇诲彇
+ BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
+
+ // 鏃嬭浆 90掳
+ int w = bufferedImage.getWidth();
+ int h = bufferedImage.getHeight();
+ BufferedImage rotated = new BufferedImage(h, w, bufferedImage.getType());
+ Graphics2D g2d = rotated.createGraphics();
+ g2d.translate(h / 2.0, w / 2.0);
+ g2d.rotate(Math.toRadians(90));
+ g2d.translate(-w / 2.0, -h / 2.0);
+ g2d.drawImage(bufferedImage, 0, 0, null);
+ g2d.dispose();
+
+ // 杞洖瀛楄妭鏁扮粍
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(rotated, "png", baos);
+ imageBytes = baos.toByteArray();
+ } else {
+ // PNG/JPG 鐩存帴瑙g爜
+ imageBytes = Base64.getDecoder().decode(imgBase64);
+ }
+
+ // 鍒涘缓 PDImageXObject 骞剁粯鍒�
+ PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, imageBytes, "img");
+ PDAppearanceStream appearance = button.getWidgets().get(0).getNormalAppearanceStream();
+ PDPageContentStream cs = new PDPageContentStream(document, appearance);
+ cs.drawImage(pdImage, 0, 0, appearance.getBBox().getWidth(), appearance.getBBox().getHeight());
+ cs.close();
+ }
+ }
+
+ form.refreshAppearances();
+ form.flatten();
+ document.save(outputPdf);
+ document.close();
+ }
+
+ public static void fillPdf(String templatePdf, OutputStream outputStream, Map<String, String> params, String fontPath) throws Exception {
+ PDDocument document = PDDocument.load(new File(templatePdf));
+ PDAcroForm form = document.getDocumentCatalog().getAcroForm();
+
+ PDType0Font font = PDType0Font.load(document, new File(fontPath));
+
+ // 娉ㄥ唽瀛椾綋璧勬簮
+ PDResources resources = form.getDefaultResources();
+ if (resources == null) {
+ resources = new PDResources();
+ form.setDefaultResources(resources);
+ }
+ COSName fontResName = resources.add(font);
+
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ PDField field = form.getField(entry.getKey());
+
+ // 鏂囧瓧瀛楁
+ if (field instanceof PDTextField) {
+ PDTextField tf = (PDTextField) field;
+ tf.setDefaultAppearance("/" + fontResName.getName() + " 10 Tf 0 0 0 rg");
+ tf.getCOSObject().setInt(COSName.Q, 1); // 姘村钩灞呬腑
+ tf.setValue(entry.getValue());
+ }
+
+ // 鍥剧墖鎸夐挳瀛楁
+ if (field instanceof PDPushButton) {
+ PDPushButton button = (PDPushButton) field;
+ String imgBase64 = entry.getValue();
+
+ if (imgBase64.contains(",")) {
+ imgBase64 = imgBase64.split(",")[1]; // 鍘绘帀鍓嶇紑
+ }
+
+ byte[] imageBytes;
+
+ if (entry.getValue().startsWith("data:image/svg+xml;base64,")) {
+ // SVG 杞� PNG
+ byte[] svgBytes = Base64.getDecoder().decode(imgBase64);
+ ByteArrayInputStream svgStream = new ByteArrayInputStream(svgBytes);
+ PNGTranscoder transcoder = new PNGTranscoder();
+
+ // 杈撳嚭鍒� ByteArray
+ ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
+ TranscoderInput input = new TranscoderInput(svgStream);
+ TranscoderOutput output = new TranscoderOutput(pngOut);
+ transcoder.transcode(input, output);
+ pngOut.flush();
+ pngOut.close();
+ imageBytes = pngOut.toByteArray();
+
+ // BufferedImage 璇诲彇
+ BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
+
+ // 鏃嬭浆 90掳
+ int w = bufferedImage.getWidth();
+ int h = bufferedImage.getHeight();
+ BufferedImage rotated = new BufferedImage(h, w, bufferedImage.getType());
+ Graphics2D g2d = rotated.createGraphics();
+ g2d.translate(h / 2.0, w / 2.0);
+ g2d.rotate(Math.toRadians(90));
+ g2d.translate(-w / 2.0, -h / 2.0);
+ g2d.drawImage(bufferedImage, 0, 0, null);
+ g2d.dispose();
+
+ // 杞洖瀛楄妭鏁扮粍
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(rotated, "png", baos);
+ imageBytes = baos.toByteArray();
+ } else {
+ // PNG/JPG 鐩存帴瑙g爜
+ imageBytes = Base64.getDecoder().decode(imgBase64);
+ }
+
+ // 鍒涘缓 PDImageXObject 骞剁粯鍒�
+ PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, imageBytes, "img");
+ PDAppearanceStream appearance = button.getWidgets().get(0).getNormalAppearanceStream();
+ PDPageContentStream cs = new PDPageContentStream(document, appearance);
+ cs.drawImage(pdImage, 0, 0, appearance.getBBox().getWidth(), appearance.getBBox().getHeight());
+ cs.close();
+ }
+ }
+
+ form.refreshAppearances();
+ form.flatten();
+ document.save(outputStream);
+ document.close();
+ }
+
+
+
+ public static void main(String[] args) throws Exception {
+
+ String template = "D:/temp/zjsf.pdf";
+ String filled = "D:/temp/tes3.pdf";
+ String finalPdf = "D:/temp/commit_final.pdf";
+
+ // Java 8 鍐欐硶锛氱敤 HashMap 鍒濆鍖栧弬鏁�
+ Map<String, String> map = new java.util.HashMap<String, String>();
+ map.put("name", "寮犱笁");
+ map.put("idCard", "440***********1234");
+ map.put("date", "2025-11-27");
+ map.put("signImage", "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iNjY0LjM5MDYyNSIgaGVpZ2h0PSIzMjgiPjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2U9InJnYigwLDAsMCkiIGZpbGw9Im5vbmUiIGQ9Ik0gMTg1LjMgMjk2IEwgMTg1LjMgMjk2IEwgMTgzLjYgMjkwIEwgMTgwLjYgMjgyIEwgMTc3LjYgMjcyIEwgMTc0LjYgMjYwIEwgMTcxLjYgMjQxIEwgMTY3LjYgMjIzIEwgMTYzLjYgMjAyIEwgMTYwLjYgMTg0IEwgMTU4LjYgMTY2IEwgMTU1LjYgMTUwIEwgMTU0LjYgMTM3IEwgMTU0LjYgMTI5IEwgMTU0LjYgMTI0IEwgMTU0LjYgMTIyIEwgMTU1LjYgMTIxIEwgMTU3LjYgMTIxIEwgMTYwLjYgMTIyIEwgMTY5LjYgMTI5IEwgMTc3LjYgMTQwIEwgMTg5LjYgMTYxIEwgMTg5LjYgMTYxIi8+CjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2U9InJnYigwLDAsMCkiIGZpbGw9Im5vbmUiIGQ9Ik0gMjk2LjMgMzIzIEwgMjk2LjMgMzIzIEwgMjk2LjYgMzIyIEwgMjk2LjYgMzIwIEwgMjk2LjYgMzE2IEwgMjk1LjYgMzA5IEwgMjkzLjYgMzAzIEwgMjg4LjYgMjkzIEwgMjg0LjYgMjgyIEwgMjc5LjYgMjcwIEwgMjc2LjYgMjU4IEwgMjcyLjYgMjQ1IEwgMjY3LjYgMjM0IEwgMjY0LjYgMjI3IEwgMjYxLjYgMjIxIEwgMjU5LjYgMjE4IEwgMjU1LjYgMjE1IEwgMjUyLjYgMjE1IEwgMjQ4LjYgMjE1IEwgMjQxLjYgMjE1IEwgMjQxLjYgMjE1Ii8+CjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2U9InJnYigwLDAsMCkiIGZpbGw9Im5vbmUiIGQ9Ik0gMTcwLjMgMjQ1IEwgMTcwLjMgMjQ1IEwgMTc3LjYgMjQ3IEwgMTg1LjYgMjUxIEwgMTk1LjYgMjU1IEwgMjA5LjYgMjYwIEwgMjIxLjYgMjY2IEwgMjM3LjYgMjcwIEwgMjUxLjYgMjc1IEwgMjY0LjYgMjc4IEwgMjc1LjYgMjc4IEwgMjg0LjYgMjc4IEwgMjkxLjYgMjc4IEwgMjk2LjYgMjc2IEwgMzAwLjYgMjcyIEwgMzAyLjYgMjY5IEwgMzA0LjYgMjYzIEwgMzA1LjYgMjU2IEwgMzA1LjYgMjQ3IEwgMzA1LjYgMjM1IEwgMzAxLjYgMjE5IEwgMjk3LjYgMjA3IEwgMjkyLjYgMTkxIEwgMjg4LjYgMTc5IEwgMjgzLjYgMTcwIEwgMjgyLjYgMTY2IEwgMjgwLjYgMTY1IEwgMjgyLjYgMTY5IEwgMjg5LjYgMTc2IEwgMjk0LjYgMTg0IEwgMzAyLjYgMTk0IEwgMzA4LjYgMjAyIEwgMzE1LjYgMjExIEwgMzIyLjYgMjE5IEwgMzI3LjYgMjIzIEwgMzMzLjYgMjI3IEwgMzM4LjYgMjI5IEwgMzQxLjYgMjMxIEwgMzQzLjYgMjMxIEwgMzQ1LjYgMjMyIEwgMzQ2LjYgMjMyIEwgMzQ3LjYgMjMyIEwgMzQ4LjYgMjMxIEwgMzQ4LjYgMjMwIEwgMzQ4LjYgMjI5IEwgMzQ3LjYgMjI3IEwgMzQ2LjYgMjI2IEwgMzQzLjYgMjI1IEwgMzQxLjYgMjI1IEwgMzM4LjYgMjI2IEwgMzM1LjYgMjI4IEwgMzMyLjYgMjMwIEwgMzMwLjYgMjM1IEwgMzMwLjYgMjM1Ii8+CjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2U9InJnYigwLDAsMCkiIGZpbGw9Im5vbmUiIGQ9Ik0gMzE2LjMgMzExIEwgMzE2LjMgMzExIEwgMzE3LjYgMzEyIEwgMzE3LjYgMzEzIEwgMzE4LjYgMzEzIEwgMzE5LjYgMzEzIEwgMzIxLjYgMzEzIEwgMzIzLjYgMzExIEwgMzI4LjYgMzAzIEwgMzM0LjYgMjkzIEwgMzQwLjYgMjc1IEwgMzQ4LjYgMjUzIEwgMzU2LjYgMjI2IEwgMzYzLjYgMTkxIEwgMzcyLjYgMTU0IEwgMzc3LjYgMTE1IEwgMzc5LjYgNzkgTCAzODAuNiA0NiBMIDM4MC42IDE4IEwgMzgwLjYgLTQgTCAzODAuNiAtMjAgTCAzODAuNiAtMzMgTCAzODAuNiAtNDQgTCAzODAuNiAtNTMgTCAzNzkuNiAtNTkgTCAzNzkuNiAtNjIgTCAzNzkuNiAtNjMgTCAzNzguNiAtNjMgTCAzNzcuNiAtNjMgTCAzNzIuNiAtNTkgTCAzNjUuNiAtNTIgTCAzNTcuNiAtNDQgTCAzNTAuNiAtMzQgTCAzNTAuNiAtMzQiLz4KPHBhdGggc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZT0icmdiKDAsMCwwKSIgZmlsbD0ibm9uZSIgZD0iTSAyNDQuMyAxNDYgTCAyNDQuMyAxNDYgTCAyNDUuNiAxNDYgTCAyNDguNiAxNDQgTCAyNTIuNiAxNDEgTCAyNTguNiAxMzcgTCAyNjQuNiAxMzIgTCAyNzAuNiAxMjcgTCAyNzkuNiAxMTkgTCAyODYuNiAxMTIgTCAyOTUuNiAxMDMgTCAzMDMuNiA5NSBMIDMwOS42IDg3IEwgMzE1LjYgNzggTCAzMTguNiA3MSBMIDMyMS42IDYyIEwgMzIyLjYgNTYgTCAzMjIuNiA1MSBMIDMyMS42IDQ4IEwgMzE4LjYgNDYgTCAzMTIuNiA0MyBMIDMwNi42IDQxIEwgMjk2LjYgNDAgTCAyOTYuNiA0MCIvPgo8cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBmaWxsPSJub25lIiBkPSJNIDI1Ni4zIDExMCBMIDI1Ni4zIDExMCBMIDI1OS42IDExNCBMIDI2NC42IDExOCBMIDI2OC42IDEyMSBMIDI3MS42IDEyMiBMIDI3My42IDEyNCBMIDI3NS42IDEyNSBMIDI3Ny42IDEyNSBMIDI3OC42IDEyNiBMIDI3OS42IDEyNiBMIDI3Ny42IDEyNiBMIDI3My42IDEyNiBMIDI3My42IDEyNiIvPjwvc3ZnPg==");
+
+ // 1. 濉厖鏂囧瓧瀛楁
+ fillPdf(template, filled, map,"D:\\temp\\msyh.ttf");
+
+ }
+}
--
Gitblit v1.8.0