解决 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.
相关推荐
神仙别闹8 分钟前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭32 分钟前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫1 小时前
泛型(2)
java
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
南宫生1 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石1 小时前
12/21java基础
java
李小白661 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp1 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶2 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
n北斗2 小时前
常用类晨考day15
java