|
@@ -0,0 +1,218 @@
|
|
|
+package com.ruoyi.common.utils;
|
|
|
+
|
|
|
+import com.ruoyi.common.core.domain.AjaxResult;
|
|
|
+import org.docx4j.TraversalUtil;
|
|
|
+import org.docx4j.XmlUtils;
|
|
|
+import org.docx4j.dml.CTPositiveSize2D;
|
|
|
+import org.docx4j.dml.Graphic;
|
|
|
+import org.docx4j.dml.GraphicData;
|
|
|
+import org.docx4j.dml.picture.Pic;
|
|
|
+import org.docx4j.dml.wordprocessingDrawing.Inline;
|
|
|
+import org.docx4j.finders.RangeFinder;
|
|
|
+import org.docx4j.jaxb.Context;
|
|
|
+import org.docx4j.openpackaging.exceptions.Docx4JException;
|
|
|
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
|
|
+import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
|
|
|
+import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
|
|
|
+import org.docx4j.wml.*;
|
|
|
+
|
|
|
+import javax.xml.bind.JAXBElement;
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 给word模板,在需要插入图片(签字)的地方,word中设则书签
|
|
|
+ * wordFilePath word 文档路径
|
|
|
+ * image 签名BASE64
|
|
|
+ * @Author: tjf
|
|
|
+ * @Date: 2024/5/15 10:25
|
|
|
+ * @Describe:
|
|
|
+ */
|
|
|
+public class WordUtil {
|
|
|
+ public static AjaxResult wordFilePath(String wordFilePath,String image) {
|
|
|
+ try {
|
|
|
+ WordprocessingMLPackage wordMLPackage = load(wordFilePath);
|
|
|
+
|
|
|
+ // 提取正文
|
|
|
+ MainDocumentPart main = wordMLPackage.getMainDocumentPart();
|
|
|
+ Document doc = null;
|
|
|
+ doc = main.getContents();
|
|
|
+ Body body = doc.getBody();
|
|
|
+
|
|
|
+ // 获取段落
|
|
|
+ List<Object> paragraphs = body.getContent();
|
|
|
+
|
|
|
+ // 提取书签并获取书签的游标
|
|
|
+ RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
|
|
|
+ new TraversalUtil(paragraphs, rt);
|
|
|
+
|
|
|
+ // 遍历书签
|
|
|
+ for (CTBookmark bm : rt.getStarts()) {
|
|
|
+ System.out.println("name:" + bm.getName());
|
|
|
+ // 替换image sign是书签名字
|
|
|
+ if ("sign".equals(bm.getName())) {
|
|
|
+ addImage(wordMLPackage, bm, image);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ save(wordMLPackage, wordFilePath);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return AjaxResult.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param wPackage 文档
|
|
|
+ * @param bm 书签
|
|
|
+ * @param base64String 签名图片base64
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String base64String) throws Exception {
|
|
|
+ P p = (P) (bm.getParent());
|
|
|
+ ObjectFactory factory = Context.getWmlObjectFactory();
|
|
|
+ R run = factory.createR();
|
|
|
+
|
|
|
+ // 读入图片并转化为字节数组,因为docx4j只能字节数组的方式插入图片
|
|
|
+ // byte[] bytes = IOUtils.toByteArray(new FileInputStream("图片文件路径"));
|
|
|
+ //byte[] bytes = getFileBytes(image);
|
|
|
+ if (base64String.contains("data:")) {
|
|
|
+ int start = base64String.indexOf(",");
|
|
|
+ base64String = base64String.substring(start + 1);
|
|
|
+ }
|
|
|
+ base64String = base64String.replaceAll("\r|\n", "");
|
|
|
+ base64String = base64String.trim();
|
|
|
+ byte[] bytes = Base64.getDecoder().decode(base64String);
|
|
|
+ // 开始创建一个行内图片
|
|
|
+ BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage, bytes);
|
|
|
+ // 最后一个是限制图片的宽度,缩放的依据
|
|
|
+ Inline newInline = imagePart.createImageInline(null, null, 0, 1, false, 0);
|
|
|
+ // 构建绘图
|
|
|
+ Drawing drawing = factory.createDrawing();
|
|
|
+ // 加入图片段落
|
|
|
+ drawing.getAnchorOrInline().add(newInline);
|
|
|
+ run.getContent().add(drawing);
|
|
|
+ // 清理书签所在数据
|
|
|
+ // p.getContent().clear();
|
|
|
+ // 加入图片信息
|
|
|
+ p.getContent().add(run);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理图片适应大小
|
|
|
+ * @param cx
|
|
|
+ * @param cy
|
|
|
+ * @param newCx
|
|
|
+ * @param newCy
|
|
|
+ */
|
|
|
+ public static Map<String, Long> dealCxy(Long cx, Long cy, Long newCx, Long newCy){
|
|
|
+ Map<String, Long> map = new HashMap<>();
|
|
|
+ Long setCx;
|
|
|
+ Long setCy;
|
|
|
+
|
|
|
+ if (newCx > cx){
|
|
|
+ if (newCy <= cy){
|
|
|
+ setCx = cx;
|
|
|
+ setCy = newCy/(newCx/cx);
|
|
|
+ } else {
|
|
|
+ if ((newCx/cx) > (newCy/cy)){
|
|
|
+ setCx = cx;
|
|
|
+ setCy = newCy/(newCx/cx);
|
|
|
+ } else {
|
|
|
+ setCy = cy;
|
|
|
+ setCx = newCx/(newCy/cy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else { // newCx < cx
|
|
|
+ if (newCy > cy) {
|
|
|
+ setCx = cx;
|
|
|
+ setCy = newCy * (cx/newCx);
|
|
|
+ } else {
|
|
|
+ if ((cx/newCx) > (cy/newCy)) {
|
|
|
+ setCx = cx;
|
|
|
+ setCy = newCy *(cx/newCx);
|
|
|
+ } else {
|
|
|
+ setCy = cy;
|
|
|
+ setCx = newCy * (cy/newCy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ map.put("setCx",setCx);
|
|
|
+ map.put("setCy",setCy);
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 得到指定类型的元素
|
|
|
+ * @param obj
|
|
|
+ * @param toSearch
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
|
|
|
+ List<Object> result = new ArrayList<>();
|
|
|
+ if (obj instanceof JAXBElement)
|
|
|
+ obj = ((JAXBElement<?>) obj).getValue();
|
|
|
+ if (obj.getClass().equals(toSearch))
|
|
|
+ result.add(obj);
|
|
|
+ else if (obj instanceof ContentAccessor) {
|
|
|
+ List<?> children = ((ContentAccessor) obj).getContent();
|
|
|
+ for (Object child : children) {
|
|
|
+ result.addAll(getAllElementFromObject(child, toSearch));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 构建文件
|
|
|
+ */
|
|
|
+ public static WordprocessingMLPackage build() throws Exception {
|
|
|
+ return WordprocessingMLPackage.createPackage();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取存在的word文件
|
|
|
+ *
|
|
|
+ * @param wordFilePath word文件路径
|
|
|
+ */
|
|
|
+ public static WordprocessingMLPackage load(String wordFilePath) throws Exception {
|
|
|
+ return WordprocessingMLPackage.load(new File(wordFilePath));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存
|
|
|
+ *
|
|
|
+ * @param wordMLPackage word
|
|
|
+ */
|
|
|
+ public static void save(WordprocessingMLPackage wordMLPackage, String wordFilePath) throws Exception {
|
|
|
+ wordMLPackage.save(new File(wordFilePath));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将图片转为Base64数组
|
|
|
+ *
|
|
|
+ * @param filePath
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static byte[] getFileBytes(String filePath) throws Exception {
|
|
|
+ File file = new File(filePath);
|
|
|
+ if (!file.exists()) {
|
|
|
+ throw new Exception("文件不存在!");
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] data = null;
|
|
|
+ try (FileInputStream fis = new FileInputStream(file); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
|
|
+ int len;
|
|
|
+ byte[] buffer = new byte[1024];
|
|
|
+ while ((len = fis.read(buffer)) != -1) {
|
|
|
+ baos.write(buffer, 0, len);
|
|
|
+ }
|
|
|
+ data = baos.toByteArray();
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+}
|