POI给word中插入图片后打不开的bug

在使用POI给word插入图片的时候发现,插入图片后,生成的文件打不开,提示格式损坏,查了一下,这是POI自带的bug,真是不想说这是有多操蛋了。
直接查看word中的document.xml文件,和正常的word中的document.xml对比,发现了POI生成的word格式有问题,因此就得从这方面找解决之道,这是一个正常的document.xml的图片部分,如果大家有相同的问题,可以用这个做对比:

<w:p>
			<w:pPr>
				<w:jc w:val="center"/>
			</w:pPr>
			<w:r>
				<w:drawing>
					<wp:inline distT="0" distB="0" distL="0" distR="0">
						<wp:extent cx="7620000" cy="1905000"/>
						<wp:docPr id="2" name="Picture 2" descr="Generated"/>
						<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="2" name="Generated"/>
										<pic:cNvPicPr/>
									</pic:nvPicPr>
									<pic:blipFill>
										<a:blip r:embed="rId2" 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="7620000" cy="1905000"/>
										</a:xfrm>
										<a:prstGeom prst="rect">
											<a:avLst/>
										</a:prstGeom>
									</pic:spPr>
								</pic:pic>
							</a:graphicData>
						</a:graphic>
					</wp:inline>
				</w:drawing>
			</w:r>
		</w:p>

现在看解决办法:

package com.railway.schedule.service;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
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.*;
import java.util.List;

public class CustomXWPFDocument extends XWPFDocument {
    public CustomXWPFDocument() {
        super();
    }

    public CustomXWPFDocument(OPCPackage opcPackage) throws IOException {
        super(opcPackage);
    }

    public CustomXWPFDocument(InputStream in) throws IOException {
        super(in);
    }


    public void createPicture(String blipId,int id, int width, int height) {

        width = width * 1000;
        height = height * 1000;
        //String blipId = getAllPictures().get(id).getPackageRelationship().getId();
        XWPFParagraph paragraph = createParagraph();
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        CTInline inline = paragraph.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");
    }
    
}

我们把插入图片使用的类继承一下,扩展一下,然后把原生使用的方法绕过就好了,请看具体实现:

private CustomXWPFDocument fillSignalImgToWord(Map<String, String> pathMap, CustomXWPFDocument doc) {
        String chartSignalAnalysis1 = pathMap.get("chartSignalAnalysis1");
        XWPFRun run;
        if (!"".equals(chartSignalAnalysis1) && !"".equals(chartSignalAnalysis2)) {
            try {
                XWPFParagraph paragraph5 = doc.createParagraph();
                run = paragraph5.createRun();
                run = Utils.chgFont(run, "宋体", 14);
                run.setText("    MT1呼叫信令:");

                FileInputStream is = new FileInputStream(chartSignalAnalysis1);
                //run.addPicture(is, XWPFDocument.PICTURE_TYPE_PNG, chartSignalAnalysis1, 600, 1200);
                doc.createPicture(doc.addPictureData(is, XWPFDocument.PICTURE_TYPE_PNG), doc.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_PNG), 7000, 8000);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            }
        }
        return doc;
    }

注释掉的代码就是原来插入图片的方法,插入图片后,返回CustomXWPFDocument这个对象,再做其他使用,就OK了
亲测可用!!!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POI(Poor Obfuscation Implementation)是一个Apache基金会下的开源项目,用于操作Microsoft Office文件格式(包括.doc、.docx、.xls、.xlsx等)。在使用POI操作Word文件时,可以通过XWPFDocument类和XWPFParagraph类来获取Word文档的文本内容。但是,如果要获取Word文档插入的图片的文本内容,需要利用POI提供的XWPFDocument类的getAllPictures()方法来获取Word文档所有图片,然后再通过图片的位置信息(比如paragraph和run的位置)来获取图片插入的文本内容。具体的代码实现可以参考下面的示例代码: ```java import org.apache.poi.xwpf.usermodel.*; import java.io.FileInputStream; import java.io.IOException; import java.util.List; public class ReadWord { public static void main(String[] args) throws IOException { // 读取Word文档 XWPFDocument doc = new XWPFDocument(new FileInputStream("test.docx")); // 获取Word文档所有的图片 List<XWPFPicture> pictures = doc.getAllPictures(); // 遍历所有图片 for (XWPFPicture picture : pictures) { // 获取图片所在的段落 XWPFParagraph paragraph = picture.getParagraph(); // 获取图片所在的文本段 XWPFRun run = picture.getCTPicture().getPictArray(0).newCursor().getObject().getSpArray(0).getTxBody().getPArray(0).getRArray(0); // 获取图片插入的文本内容 String text = run.getText(0); System.out.println(text); } } } ``` 需要注意的是,上述代码只适用于获取Word文档插入的图片的文本内容,如果图片是作为文本的背景或者其他特殊情况,则无法获取到图片的文本内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值