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 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 dealCxy(Long cx, Long cy, Long newCx, Long newCy){ Map 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 getAllElementFromObject(Object obj, Class toSearch) { List 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; } }