java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具

docx4j生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具

最近写项目时遇到一些操作数据填充word、pdf以及word转pdf、word转图片的需求。网络搜索资料经整理如下
操作office文档、pdf一般来说有好几种实现方式

1、docx4j+apache.pdfbox

1.1 引入maven

   <!-- pdf 转图片  -->
        
            org.apache.pdfbox</groupId>
            pdfbox</artifactId>
            2.0.25</version>
        </dependency>
        <!--
               
                   org.apache.poi</groupId>
                   poi-ooxml</artifactId>
                   3.10.1</version>
               </dependency>
       -->
        <!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/org.apache.poi.xwpf.converter.pdf-->
        
            fr.opensagres.xdocreport</groupId>
            org.apache.poi.xwpf.converter.pdf</artifactId>
            1.0.4</version>
        </dependency>
        <!-- pdf 转图片 -->

        <!-- docx4j 创建docx文件、pdf文档、word转pdf文档-->
        
            org.docx4j</groupId>
            docx4j-JAXB-Internal</artifactId>
            8.2.4</version>
        </dependency>
        
            org.docx4j</groupId>
            docx4j-export-fo</artifactId>
            8.2.4</version>
        </dependency>
        <!-- docx4j 创建docx文件、pdf文档、word转pdf文档-->

1.2 工具类

package com.sl.utils.office.word;

import com.sl.utils.id.IDUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.docx4j.Docx4J;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.finders.RangeFinder;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * docx4j生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具
 *
 * 有三种方式
 * 1 通过占位符
 *
 * 

* 通过docx文件的书签、占位符替换变量 *

* 通过占位符替换注意 * * 通过占位符替换注意 -----------坑坑坑坑 直接再docx文件中进行修改占位符不一定会连续!!!----------- * ${var}必须是连续的,否则取不到变量。有时候取不到变量的时候可以抓换为xml然后查看你的变量是否是连续的 * 可以通过如下方式解决 现在docx文件中写入占位符然后 * 把当前docx文件用rar或zip打开,找到其中的 word/document.xml文件,修改占位符连续 *

* 比如把 * * ${na</w:t> * </w:r> * * me}</w:t> * </w:r> * 修改为 * * ${name}</w:t> * </w:r> * 2、全部通过书签 * 3、通过域变量 * 通过域变量需要重写 docx4居中 XmlUtils 工具类中unmarshallFromTemplate方法 以适配域变量 * 具体目录在 org.docx4j * @author gaoxueyong * @create at: 2021/12/28 下午15:02 */ public class DocxAndPdfAndImgUtils { private static final Logger log = LoggerFactory.getLogger(DocxAndPdfAndImgUtils.class); private static WordprocessingMLPackage wordMLPackage; private static ObjectFactory factory; /** * 通过docx模板获取docx模板转换的图片 * @param templatePath 模板文件 * @param mappings 要匹配的占位符数据 * @param fileMapping 书签名称对于的文件 * @return */ public static List[]> getPngByDocxTemplate(String templatePath, Map, String> mappings, Map, byte[]> fileMapping) { return pdfToImg(getPdfFile(templatePath, mappings, fileMapping)); } /** * 通过模板获取转换后docx的二进制数组 * @param templatePath 模板文件 * @param mappings 要匹配的占位符数据 * @param fileMapping 书签名称对于的文件 * @return */ public static byte[] getDocxByTemplate(String templatePath, Map, String> mappings, Map, byte[]> fileMapping) { File docxFile = getDocxFile(templatePath, mappings, fileMapping); try { if (null == docxFile) { return null; } byte[] bytes = Files.readAllBytes(docxFile.toPath()); if (docxFile.exists()) { docxFile.delete(); } return bytes; } catch (IOException e) { log.error("获取文件失败"); if (docxFile.exists()) { docxFile.delete(); } return null; } } /** * 通过模板获取转换后pdf文件 * @param templatePath 模板文件 * @param mappings 要匹配的占位符数据 * @param fileMapping 书签名称对于的文件 * @return */ public static byte[] getPdfFile(String templatePath, Map, String> mappings, Map, byte[]> fileMapping){ try { File docxFile = getDocxFile(templatePath, mappings, fileMapping); if(null == docxFile){ return null; } WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(docxFile); Path pdf = Files.createTempFile(IDUtils.getPrimaryId(), "pdf"); File pdfFile = pdf.toFile(); if(null == pdfFile){ log.error("创建文件失败"); return null; } Docx4J.toPDF(wordMLPackage, new FileOutputStream(pdfFile)); if(docxFile.exists()){ docxFile.delete(); } byte[] bytes = Files.readAllBytes(pdf); if(pdfFile.exists()){ pdfFile.delete(); } return bytes; } catch (Docx4JException e) { log.error("bookReplaceVarText error:Docx4JException ", e); return null; } catch (Exception e) { log.error("bookReplaceVarText error:Docx4JException ", e); return null; } } /** * 通过文件输入流获取pdf文档的二进制数组 * @param docxInputstream * @return */ public static byte[] getPdfByte(InputStream docxInputstream){ try { if(null == docxInputstream){ return null; } WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(docxInputstream); Path pdf = Files.createTempFile(IDUtils.getPrimaryId(), "pdf"); File pdfFile = pdf.toFile(); if(null == pdfFile){ log.error("创建文件失败"); return null; } Docx4J.toPDF(wordMLPackage, new FileOutputStream(pdfFile)); byte[] bytes = Files.readAllBytes(pdf); if(pdfFile.exists()){ pdfFile.delete(); } return bytes; } catch (Docx4JException e) { log.error("bookReplaceVarText error:Docx4JException ", e); return null; } catch (Exception e) { log.error("bookReplaceVarText error:Docx4JException ", e); return null; } } /** * 通过模板获取转换后docx文件 * @param templatePath 模板文件 * @param mappings 要匹配的占位符数据 * @param fileMapping 书签名称对于的文件 * @return */ public static File getDocxFile(String templatePath, Map, String> mappings, Map, byte[]> fileMapping){ try { wordMLPackage = WordprocessingMLPackage.load(new File(templatePath)); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); if(MapUtils.isNotEmpty(mappings)){ mainDocumentPart.variableReplace(mappings); } factory = Context.getWmlObjectFactory(); Document wmlDoc = (Document) mainDocumentPart.getJaxbElement(); Body body = wmlDoc.getBody(); // 提取正文中所有段落 List paragraphs = body.getContent(); // 提取书签并创建书签的游标 RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange"); new TraversalUtil(paragraphs, rt); // 遍历书签 for (CTBookmark bm : rt.getStarts()) { log.info("标签名称:" + bm.getName()); if(MapUtils.isEmpty(fileMapping)){ break; } if (fileMapping.containsKey(bm.getName())) { addImage(wordMLPackage, bm, fileMapping.get(bm.getName())); }else { if(mappings.containsKey(bm.getName())){ replaceText (bm, mappings.get(bm.getName())); } } } wordMLPackage.setFontMapper(getFontMap()); Path docx = Files.createTempFile(IDUtils.getPrimaryId(), "docx"); File docxFile = docx.toFile(); Docx4J.save(wordMLPackage, docxFile); return docxFile; } catch (Docx4JException e) { log.error("bookReplaceVarText error:Docx4JException ", e); return null; } catch (Exception e) { log.error("bookReplaceVarText error:Docx4JException ", e); return null; } } /** * 在标签处插入内容 * @param bm * @param object * @throws Exception */ public static void replaceText(CTBookmark bm, Object object) throws Exception { if (object == null) { return; } // do we have data for this one? if (bm.getName() == null){ return; } String value = object.toString(); try { // Can't just remove the object from the parent, // since in the parent, it may be wrapped in a JAXBElement List theList = null; ParaRPr rpr = null; if (bm.getParent() instanceof P) { PPr pprTemp = ((P) (bm.getParent())).getPPr(); if (pprTemp == null) { rpr = null; } else { rpr = ((P) (bm.getParent())).getPPr().getRPr(); } theList = ((ContentAccessor) (bm.getParent())).getContent(); } else { return; } int rangeStart = -1; int rangeEnd = -1; int i = 0; for (Object ox : theList) { Object listEntry = XmlUtils.unwrap(ox); if (listEntry.equals(bm)) { if (((CTBookmark) listEntry).getName() != null) { rangeStart = i + 1; } } else if (listEntry instanceof CTMarkupRange) { if (((CTMarkupRange) listEntry).getId().equals(bm.getId())) { rangeEnd = i - 1; break; } } i++; } int x = i - 1; // if (rangeStart > 0 && x >= rangeStart) { // Delete the bookmark range for (int j = x; j >= rangeStart; j--) { theList.remove(j); } // now add a run R run = factory.createR(); Text t = factory.createText(); // if (rpr != null) // run.setRPr(paraRPr2RPr(rpr)); t.setValue(value); run.getContent().add(t); // t.setValue(value); theList.add(rangeStart, run); // } } catch (ClassCastException cce) { log.error("error", cce); } } /** * 插入图片 * @param wPackage * @param bm * @param bytes */ public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm,byte[] bytes) { // log.info("addImage :->{},{},{}", wPackage, bm); if(null == bytes){ return; } try { // 这儿可以对单个书签进行操作,也可以用一个map对所有的书签进行处理 // 获取该书签的父级段落 P p = (P) (bm.getParent()); // R对象是匿名的复杂类型,然而我并不知道具体啥意思,估计这个要好好去看看ooxml才知道 R run = factory.createR(); // 读入图片并转化为字节数组,因为docx4j只能字节数组的方式插入图片 // byte[] bytes = IOUtils.toByteArray(new FileInputStream(file)); // InputStream is = new FileInputStream; // byte[] bytes = IOUtils.toByteArray(inputStream); // byte[] bytes = FileUtil.getByteFormBase64DataByImage(""); // 开始创建一个行内图片 BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage, bytes); // 最后一个参数是限制图片的宽度,缩放的依据 Inline inline = imagePart.createImageInline(null, null, 0, 1, false, 2350); // 获取该书签的父级段落 // drawing理解为画布? Drawing drawing = factory.createDrawing(); drawing.getAnchorOrInline().add(inline); run.getContent().add(drawing); p.getContent().add(run); } catch (Exception e) { log.error("", e); } } /** * 解决转换后数据显示异常的问题 * @return */ private static Mapper getFontMap(){ Mapper fontMapper = new IdentityPlusMapper(); fontMapper.put("隶书", PhysicalFonts.get("LiSu")); fontMapper.put("宋体", PhysicalFonts.get("SimSun")); fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei")); fontMapper.put("黑体", PhysicalFonts.get("SimHei")); fontMapper.put("楷体", PhysicalFonts.get("KaiTi")); fontMapper.put("新宋体", PhysicalFonts.get("NSimSun")); fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai")); fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong")); fontMapper.put("仿宋", PhysicalFonts.get("FangSong")); fontMapper.put("幼圆", PhysicalFonts.get("YouYuan")); fontMapper.put("华文宋体", PhysicalFonts.get("STSong")); fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong")); fontMapper.put("等线", PhysicalFonts.get("SimSun")); fontMapper.put("等线 Light", PhysicalFonts.get("SimSun")); fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo")); fontMapper.put("华文隶书", PhysicalFonts.get("STLiti")); fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei")); fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun")); fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti")); fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi")); fontMapper.put("华文细黑", PhysicalFonts.get("STXihei")); fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB")); fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312")); fontMapper.put("新細明體", PhysicalFonts.get("SimSun")); return fontMapper; } /** * pdf 转图片 * @param pdfFile * @return */ public static List[]> pdfToImg(byte[] pdfFile) { PDDocument doc = null; List[]> outFile = new ArrayList<>(); try { doc = PDDocument.load(pdfFile); PDFRenderer render = new PDFRenderer(doc); int count = doc.getNumberOfPages(); for (int i = 0; i < count; i++) { // 设置图片的分辨率 BufferedImage image = render.renderImageWithDPI(i, 296); // 如果是PNG图片想要背景透明的话使用下面这个 // BufferedImage image = render.renderImageWithDPI(i, 296, // ImageType.ARGB); Path png = Files.createTempFile(IDUtils.getPrimaryId() + "_" + i, "png"); File pngFile = png.toFile(); ImageIO.write(image, "PNG", pngFile); outFile.add(Files.readAllBytes(png)); pngFile.delete(); } } catch (IOException e) { log.error("pdf转换图片失败!"); } finally { if (doc != null) { try { doc.close(); } catch (IOException e) { log.error("关闭PDDocument失败"); } } return outFile; } } }

1.2.1 重写 XmlUtils以适配域变量

重写 XmlUtils 工具类中unmarshallFromTemplate方法 以适配域变量
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第1张图片

1.3 关于模板

1.3.1 新建一个docx文档如并添加占位符 (不推荐 可以全部都是用标签或域变量)

java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第2张图片
头像出需要添加书签,书签用以替换图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第3张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第4张图片

1.3.2 修改占位符使其连续

用zip或rar工具打开docx文档并找到word/document.xml文件进行编辑
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第5张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第6张图片
偷偷的告诉你,其实docx文档也是压缩包,可以修改其后缀直接变成zip文件
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第7张图片
打开document.xml文档如下发现刚才的占位符是不连续的,我们要修改使其连续
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第8张图片
使用编辑器修改后如下,然后把该文件写会到word问里,或者通过zip工具放进去
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第9张图片
现在就可以直接调用工具方法替换数据以及图片了
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第10张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第11张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第12张图片

1.3.2 使用域变量+书签(图片需要使用书签)

注意 使用域变量需要重写 docx4居中 XmlUtils 工具类中unmarshallFromTemplate方法 以适配域变量
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第13张图片

2、xdocreport

2.1 引入maven

        <!-- xdocreport 生成word、pdf -->
        <!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/fr.opensagres.xdocreport.document.docx -->
        
            fr.opensagres.xdocreport</groupId>
            fr.opensagres.xdocreport.document.docx</artifactId>
            2.0.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/fr.opensagres.xdocreport.template.freemarker -->
        
            fr.opensagres.xdocreport</groupId>
            fr.opensagres.xdocreport.template.freemarker</artifactId>
            2.0.2</version>
        </dependency>

        
            fr.opensagres.xdocreport</groupId>
            fr.opensagres.xdocreport.converter.docx.xwpf</artifactId>
            2.0.2</version>
        </dependency>
        <!-- xdocreport 生成word、pdf -->

        <!-- pdf转图片 -->
        
            org.apache.pdfbox</groupId>
            pdfbox</artifactId>
            2.0.25</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/fr.opensagres.poi.xwpf.converter.pdf -->
        
            fr.opensagres.xdocreport</groupId>
            fr.opensagres.poi.xwpf.converter.pdf</artifactId>
            2.0.2</version>
        </dependency>

        <!-- pdf转图片 -->
        
            org.projectlombok</groupId>
            lombok</artifactId>
        </dependency>

2.2 模板

注意 如果要动态替换图片需要先在模板里插入一张图片,否则无法替换图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第14张图片
选中头像后的图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第15张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第16张图片

java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第17张图片

2.3 逻辑代码

      public static void main(String[] args) {
        Map<String, Object> param = new HashMap<>();
        param.put("user.username", "小明不怕不怕啦");
        param.put("user.hobby", "爱玩dota");
        param.put("name", "sssssssssssssssssssssss");
        String rootPath = XdocreportUtils.class.getClassLoader().getResource("").getPath();
        String filePath = String.format("%stemplates/xdocreport/xdocxtemplate.docx", rootPath);

        Map<String, IImageProvider> imgMap = new HashMap<>();
        IImageProvider logo = new FileImageProvider(new File("C:\\Users\\Administrator\\Desktop\\2021122211591833953227008.png"), true);
        logo.setSize(500f, 500f);
        imgMap.put("logo", logo);
        IImageProvider pic = new FileImageProvider(new File("C:\\Users\\Administrator\\Desktop\\suoluePic.PNG"), true);
        pic.setSize(200f, 200f);
        imgMap.put("pic", pic);
        exportDocx(param, imgMap, new File(filePath), "C:\\Users\\Administrator\\Desktop\\DocxProjectWithFreemarker_Out.docx");


        exportPdf(param, imgMap, new File(filePath), "C:\\Users\\Administrator\\Desktop\\DocxProjectWithFreemarker_Out.pdf");
    }


    public static void exportDocx(Map<String, Object> param, Map<String, IImageProvider> imgMap, File templateFIle, String outPath) {
        try {
            InputStream in = new FileInputStream(templateFIle);
            //载入模板
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
            IContext context = report.createContext();
            //设置要替换的值
            if (MapUtils.isNotEmpty(param)) {
                for (Map.Entry<String, Object> entry : param.entrySet()) {
                    context.put(entry.getKey(), entry.getValue());
                }
            }
            FieldsMetadata metadata = report.createFieldsMetadata();
            report.setFieldsMetadata(metadata);
            //替换图片
            if (MapUtils.isNotEmpty(imgMap)) {
                for (Map.Entry<String, IImageProvider> entry : imgMap.entrySet()) {
                    context.put(entry.getKey(), entry.getValue());
                    metadata.addFieldAsImage(entry.getKey());
                }
            }
            report.setFieldsMetadata(metadata);

            OutputStream out = new FileOutputStream(new File(outPath));
            report.process(context, out);
            out.close();
        } catch (IOException e) {
            log.error("导出docx文件出现异常!", e);
        } catch (XDocReportException e) {
            log.error("导出docx文件出现异常!", e);
        }
    }

    public static void exportPdf(Map<String, Object> param, Map<String, IImageProvider> imgMap, File templateFIle, String outPath) {
        try {
            InputStream in = new FileInputStream(templateFIle);
            //载入模板
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
            IContext context = report.createContext();
            //设置要替换的值
            if (MapUtils.isNotEmpty(param)) {
                for (Map.Entry<String, Object> entry : param.entrySet()) {
                    context.put(entry.getKey(), entry.getValue());
                }
            }
            FieldsMetadata metadata = report.createFieldsMetadata();
            report.setFieldsMetadata(metadata);
            //替换图片
            if (MapUtils.isNotEmpty(imgMap)) {
                for (Map.Entry<String, IImageProvider> entry : imgMap.entrySet()) {
                    context.put(entry.getKey(), entry.getValue());
                    metadata.addFieldAsImage(entry.getKey());
                }
            }
            report.setFieldsMetadata(metadata);
            OutputStream out = new FileOutputStream(new File(outPath));
            Options options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.XWPF);
            report.convert(context, options, out);
            out.close();
        } catch (IOException e) {
            log.error("导出pdf文件出现异常!", e);
        } catch (XDocReportException e) {
            log.error("导出pdf文件出现异常!", e);
        }
    }

2.4 效果

java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第18张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第19张图片
java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第20张图片

3、冰蓝科技的Spire

3.1 引入maven配置

      
            e-iceblue</groupId>
            spire.doc.free</artifactId>
            3.9.0</version>
        </dependency>
        
          
            com.e-iceblue</id>
            https://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
     </repositories>

3.2 逻辑代码

import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.documents.BookmarksNavigator;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.documents.TextBodyPart;
import com.spire.doc.fields.DocPicture;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class SpireWordPicTest {
    public static void main(String[] args) throws IOException {

        //加载Word文档
        Document doc = new Document("C:\\Users\\Administrator\\Desktop\\testDocTemplates.docx");


        Map,String> mappings  = new HashMap<>();
        mappings.put("username","小明");
        mappings.put("password","123456");
        /**
         * https://www.cnblogs.com/Yesi/p/11422349.html
         * 需要先在模板里设置书签 然后替换
         *
         */

        for(Map.Entry,String > entry:mappings.entrySet()){
            doc.replace(String.format("${%s}",entry.getKey()),entry.getValue(), false, true);
        }


        //定位到指定书签位置 设置二维码
        BookmarksNavigator bookmarksNavigator = new BookmarksNavigator(doc);

        bookmarksNavigator.moveToBookmark("headerPng", true, true);
        Paragraph para=  new Paragraph(doc);
        DocPicture docPicture = para.appendPicture("C:\\Users\\Administrator\\Desktop\\企业微信截图_20211228152622.png");//设置图片宽度
        docPicture.setWidth(110);
        //设置图片高度
        docPicture.setHeight(110);
        TextBodyPart bodyPart = new TextBodyPart(doc);
        bodyPart.getBodyItems().add(para);
        bookmarksNavigator.replaceBookmarkContent(bodyPart);


        //保存文档
        doc.saveToFile("C:\\Users\\Administrator\\Desktop\\ReplaceAllMatchedText.docx", FileFormat.Docx_2013);
    }

java生成docx文件、pdf文件、docx转pdf、docx转图片 pdf转图片工具_第21张图片

冰蓝科技的免费版代码执行效率很低,不知道正式版怎么样
https://www.e-iceblue.cn/spiredocforjava/spire-doc-for-java-program-guide-content.html
样例代码可参考 https://gitee.com/wahnn/SpringBoot2.x/tree/master/XdocreportAndDocx4j

你可能感兴趣的:(java,docx4j,pdf,docx,图片)