解决 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.
相关推荐
程序员阿龙31 分钟前
基于SpringBoot的医疗陪护系统设计与实现(源码+定制+开发)
java·spring boot·后端·医疗陪护管理平台·患者护理服务平台·医疗信息管理系统·患者陪护服务平台
前 方1 小时前
若依入门案例
java·spring boot·maven
funnyZpC1 小时前
quartz集群增强版🎉
java·分布式·开源·集群·定时任务
阿华的代码王国1 小时前
【Spring】——SpringBoot项目创建
java·spring boot·后端·启动类·target文件
stormjun1 小时前
Java基于微信小程序的私家车位共享系统(附源码,文档)
java·微信小程序·共享停车位·私家车共享停车位小程序·停车位共享
转世成为计算机大神1 小时前
网关 Spring Cloud Gateway
java·网络·spring boot·1024程序员节
paopaokaka_luck1 小时前
基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
java·spring boot·小程序·毕业设计·mybatis·1024程序员节
m0_594526301 小时前
Python批量合并多个PDF
java·python·pdf
咕哧普拉啦1 小时前
乐尚代驾十订单支付seata、rabbitmq异步消息、redisson延迟队列
java·spring boot·mysql·spring·maven·乐尚代驾·java最新项目
✿゚卡笨卡1 小时前
pdf 添加页眉页脚,获取前五页
java·pdf