栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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+xdocreport 1.1 引入maven
   
        
            org.apache.pdfbox
            pdfbox
            2.0.25
        
        
        
        
            fr.opensagres.xdocreport
            org.apache.poi.xwpf.converter.pdf
            1.0.4
        
        

        
        
            org.docx4j
            docx4j-JAXB-Internal
            8.2.4
        
        
            org.docx4j
            docx4j-export-fo
            8.2.4
        
        
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转图片工具
 *
 * 通过docx文件的书签、占位符替换变量
 *
 * 通过占位符替换注意
 *  * 通过占位符替换注意 -----------坑坑坑坑 直接再docx文件中进行修改占位符不一定会连续!!!-----------
 *  ${var}必须是连续的,否则取不到变量。有时候取不到变量的时候可以抓换为xml然后查看你的变量是否是连续的
 *  可以通过如下方式解决 现在docx文件中写入占位符然后
 *  把当前docx文件用rar或zip打开,找到其中的 word/document.xml文件,修改占位符连续
 *
 *  比如把
 *  
 *      ${na
 *  
 *  
 *      me}
 *  
 * 修改为
 *  
 *      ${name}
 *  
 *
 * @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 mappings, Map fileMapping) {
        return pdfToImg(getPdfFile(templatePath, mappings, fileMapping));
    }

    /**
     * 通过模板获取转换后docx的二进制数组
     * @param templatePath 模板文件
     * @param mappings 要匹配的占位符数据
     * @param fileMapping 书签名称对于的文件
     * @return
     */
    public static byte[] getDocxByTemplate(String templatePath, Map mappings, Map 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 mappings, Map 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 mappings, Map 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);
            // createImageInline函数的前四个参数我都没有找到具体啥意思,,,,
            // 最后一个参数是限制图片的宽度,缩放的依据
            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.3关于模板 
1.3.1 新建一个docx文档如并添加占位符 


头像出需要添加书签,书签用以替换图片

1.3.2 修改占位符使其连续

用zip或rar工具打开docx文档并找到word/document.xml文件进行编辑


偷偷的告诉你,其实docx文档也是压缩包,可以修改其后缀直接变成zip文件

打开document.xml文档如下发现刚才的占位符是不连续的,我们要修改使其连续

使用编辑器修改后如下,然后把该文件写会到word问里,或者通过zip工具放进去

现在就可以直接调用工具方法替换数据以及图片了


2、xdocreport 3、冰蓝科技的Spire 3.1、引入maven配置
      
            e-iceblue
            spire.doc.free
            3.9.0
        
        
          
            com.e-iceblue
            https://repo.e-iceblue.cn/repository/maven-public/
        
     
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 mappings  = new HashMap<>();
        mappings.put("username","小明");
        mappings.put("password","123456");
        /**
         * https://www.cnblogs.com/Yesi/p/11422349.html
         * 需要先在模板里设置书签 然后替换
         *
         */

        for(Map.Entry 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);
    }

冰蓝科技的免费版代码执行效率很低,不知道正式版怎么样
https://www.e-iceblue.cn/spiredocforjava/spire-doc-for-java-program-guide-content.html

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号