解决 poi3.8版本在word中插入图片不展示的问题

解决 poi3.8版本在word中插入图片不展示的问题

  • [1. 前言](#1. 前言)
  • [2. 问题描述](#2. 问题描述)
  • [3. 解决问题](#3. 解决问题)
    • [3.1 方案1------自定义XWPFDocument](#3.1 方案1——自定义XWPFDocument)
      • [3.1.1 解决代码](#3.1.1 解决代码)
      • [3.1.2 参考](#3.1.2 参考)
    • [3.2 方案2------使用开源框架xdocreport](#3.2 方案2——使用开源框架xdocreport)
  • [4. 其他](#4. 其他)

1. 前言

  • 本次使用的是poi3.8版本,引入的依赖如下:

    xml 复制代码
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>3.8</version>
    </dependency>
    
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.8</version>
    </dependency>
    
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-scratchpad</artifactId>
      <version>3.8</version>
    </dependency>
  • word里插入图片的代码如下:

    java 复制代码
    package org.example.example1.poi38;
    
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.util.Units;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFRun;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /**
     * @Description
     * @Author susu
     * @Date 2024/3/8
     */
    public class TestWordImage2NotDealBug {
        public static void main(String[] args) throws IOException {
            // 读取本地的一个现有的Word文档,并创建对应的文档对象
            String fileInPath = "/Users/susu/file_test/poi3.8-test/test_word_in_1.docx";
            String imagePath = "/Users/susu/file_test/poi3.8-test/susu.jpg"; // 图片文件路径
            String fileOutPath = "/Users/susu/file_test/poi3.8-test/test_word_out_1.docx";
    
            FileInputStream fileInputStream = new FileInputStream(fileInPath);
            XWPFDocument document = new XWPFDocument(fileInputStream);
    
            try {
                XWPFParagraph imageParagraph = document.createParagraph();
                XWPFRun imageRun = imageParagraph.createRun();
    
                FileInputStream imageStream = new FileInputStream(imagePath);
    //            imageRun.addPicture(imageStream,XWPFDocument.PICTURE_TYPE_PNG,"susu.png,", Units.toEMU(100), Units.toEMU(100));
                imageRun.addPicture(imageStream,XWPFDocument.PICTURE_TYPE_JPEG,"susu.jpg,", Units.toEMU(100), Units.toEMU(100));
    
                FileOutputStream fos = new FileOutputStream(fileOutPath);
                document.write(fos);
                fos.close();
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }

2. 问题描述

  • Java使用poi3.8版本在word中插入图片不展示,使用XWPFDocument类的方法addPictureData()插入图片时虽然不报异常,word也能打开生成的文件,但图片却无法显示出来,如果将word文件用解压缩文件打开,也能看到里面包含的图片文件,但在word中无法正常显示。(图片插入成功,有占位就是不展示),效果如下:

3. 解决问题

3.1 方案1------自定义XWPFDocument

3.1.1 解决代码

  • 自定义的 XWPFDocument.java代码如下:

    java 复制代码
    package org.example.example1.poi38;
    
    
    import org.apache.poi.openxml4j.opc.OPCPackage;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.xmlbeans.XmlException;
    import org.apache.xmlbeans.XmlToken;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
    import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * @Description 解决 poi3.8 图片bug问题
     * @Author susu
     * @Date 2024/3/8
     */
    public class MyXWPFDocument extends XWPFDocument {
        public MyXWPFDocument() {
            super();
        }
    
        public MyXWPFDocument(OPCPackage opcPackage) throws IOException {
            super(opcPackage);
        }
    
        public MyXWPFDocument(InputStream in) throws IOException {
            super(in);
        }
    
        public void createPicture(String blipId,int id, int width, int height) {
            final int EMU = 9525;
            width *= EMU;
            height *= EMU;
    
            CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline();
    
            String picXml = "" +
                    "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
                    "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                    "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                    "         <pic:nvPicPr>" +
                    "            <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
                    "            <pic:cNvPicPr/>" +
                    "         </pic:nvPicPr>" +
                    "         <pic:blipFill>" +
                    "            <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
                    "            <a:stretch>" +
                    "               <a:fillRect/>" +
                    "            </a:stretch>" +
                    "         </pic:blipFill>" +
                    "         <pic:spPr>" +
                    "            <a:xfrm>" +
                    "               <a:off x=\"0\" y=\"0\"/>" +
                    "               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
                    "            </a:xfrm>" +
                    "            <a:prstGeom prst=\"rect\">" +
                    "               <a:avLst/>" +
                    "            </a:prstGeom>" +
                    "         </pic:spPr>" +
                    "      </pic:pic>" +
                    "   </a:graphicData>" +
                    "</a:graphic>";
    
            //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
            XmlToken xmlToken = null;
            try {
                xmlToken = XmlToken.Factory.parse(picXml);
            } catch(XmlException xe) {
                xe.printStackTrace();
            }
            inline.set(xmlToken);
            //graphicData.set(xmlToken);
    
            inline.setDistT(0);
            inline.setDistB(0);
            inline.setDistL(0);
            inline.setDistR(0);
    
            CTPositiveSize2D extent = inline.addNewExtent();
            extent.setCx(width);
            extent.setCy(height);
    
            CTNonVisualDrawingProps docPr = inline.addNewDocPr();
            docPr.setId(id);
            docPr.setName("Picture " + id);
            docPr.setDescr("Generated");
        }
    
    }
  • 测试代码如下:

    java 复制代码
    package org.example.example1.poi38;
    
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /**
     * @Description
     * @Author susu
     * @Date 2024/3/8
     */
    public class TestWordImage2DealBug {
        public static void main(String[] args) throws IOException {
            // 读取本地的一个现有的Word文档,并创建对应的文档对象
            String fileInPath = "/Users/susu/file_test/poi3.8-test/test_word_in_1.docx";
            FileInputStream fileInputStream = new FileInputStream(fileInPath);
    
            // 使用自定义的 MyXWPFDocument
            MyXWPFDocument document = new MyXWPFDocument(fileInputStream);
    
            try {
                String imagePath = "/Users/susu/file_test/poi3.8-test/susu.jpg"; // 图片文件路径
                FileInputStream imageStream = new FileInputStream(imagePath);
                String picId = document.addPictureData(imageStream, XWPFDocument.PICTURE_TYPE_JPEG);
                document.createPicture(picId, document.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_JPEG), 200, 150);
    
                String fileOutPath = "/Users/susu/file_test/poi3.8-test/test_word_out_1.docx";
                FileOutputStream fos = new FileOutputStream(fileOutPath);
                document.write(fos);
                fos.close();
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
  • 测试效果如下(可以看到图片已成功插入):

3.1.2 参考

3.2 方案2------使用开源框架xdocreport

  • 只需导入 xdocreport 依赖,代码不用改变,原先图片不展示的代码再测试就没问题了。如下:

  • xdocreport 内部依赖了 poi ,如果xdocreport之后,可以不用导入poi,但是如果还想继续poi3.8版本,则需要指定poi版本,继续导入poi3.8,依赖如下:

    xml 复制代码
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>3.8</version>
    </dependency>
    
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.8</version>
    </dependency>
    
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-scratchpad</artifactId>
      <version>3.8</version>
    </dependency>
    
    <!--引入这个之后,poi3.8就没有图片的bug了-->
    <dependency>
      <groupId>fr.opensagres.xdocreport</groupId>
      <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
      <version>1.0.6</version>
    </dependency>
  • 对比一下导入 xdocreport 之后依赖的变化,如下:

4. 其他

  • 如果你的项目很老,升级很闹心,那就暂且用上面方法解决吧!
  • 当然如果你用的不是不好升级的老系统,可以考虑更高级的poi版本,也可以了解一下 Poi-tl ,poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,主要是官网文档真的很友好,很详细,相当不错,官网如下:
    https://deepoove.com/poi-tl/#_why_poi_tl.
相关推荐
YuTaoShao几秒前
【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
java·算法·leetcode
考虑考虑1 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·2 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠3 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
Zz_waiting.3 小时前
Javaweb - 10.4 ServletConfig 和 ServletContext
java·开发语言·前端·servlet·servletconfig·servletcontext·域对象
全栈凯哥3 小时前
02.SpringBoot常用Utils工具类详解
java·spring boot·后端
兮动人3 小时前
获取终端外网IP地址
java·网络·网络协议·tcp/ip·获取终端外网ip地址