利用word的xml格式,使用POI在图片位置插入文字

使用POI在图片之后插入文字

首先要知道docx文件是zip形式保存的,文档内容会保存为xml格式。我们将一个docx文件后缀改为zip并打开,会发现里面又很多文件夹以及xml文件。
在这里插入图片描述
内容存在word文件夹下的document.xml文件中,charts文件夹保存图表,embeddings中的xlsx文件是图表的信息,图片则保存在media中。
在这里插入图片描述
使用浏览器打开document.xml文件,里面就是我们在文档中输入的内容。

<w:p>:段落,Paragraph
<w:pPr>:段落样式
<w:r>:文本,Run
<w:rPr>:文本样式
<w:t>:文本内容
<w:hdr>:页眉
<w:ftr>:页脚
<w:pict>:图片
<w:drawing>:

在这里插入图片描述

 进入正题,采用的主要想法是根据图片和文字的标签进行定位,然后
File file = new File(filePath);
in = new FileInputStream(file);
XWPFDocument doc = new XWPFDocument(in);

//获取段落
List<XWPFParagraph> paraList = doc.getParagraphs();
//run.getEmbeddedPictures()方法只能获取嵌入式的图片
//doc.getAllPictures()获取全部图片
List<XWPFPictureData> pictures = doc.getAllPictures();
//将图片的byte放到map中,方便后面获取
Map<String, byte[]> picDataMap = new HashMap<>();
for (XWPFPictureData pic : pictures) {
	//relationId就是图片引用的rid
    String rid = pic.getParent().getRelationId(pic);
    picDataMap.put(rid, pic.getData());
}
for (XWPFParagraph para : paraList){
	//run是一段文本对象,一个段落(XWPFPaaragraph)的run会根据图片进行分割
    List<XWPFRun> runList = para.getRuns();
    for (int i = 0; i < runList.size(); i++) {
		//保存当前run需要插入的值和插入位置,在判断结束后统一插入
        Map<Integer, String> insertMap = new HashMap<>();
        //当前run没有文字时,需要插入的值:
        String insertValue = "";
        XWPFRun run = runList.get(i);
        //POI对word的处理:将word以xml格式读取后进行封装
        //getCTR方法获取xml信息
        String runXmlText = run.getCTR().xmlText();
        //判断当前文本对象<w:pict>为引用图片,<w:drawing>为嵌入图片:嵌入图片也可以通过run.getEmbeddedPictures()获取
        if (runXmlText.indexOf("<w:pict>") != -1) {
			//该方法利用indexOf获取当前文本包含图片的位置,如果为嵌入图片应使用r:embed获取位置。
            List<Integer> indexList = getRIdIndex(0, runXmlText, "r:id");
            List<Integer> wtIndexList = getWtIndex(0, runXmlText, "<w:t");
            for (int j = 0; j < indexList.size(); j++){
            	//通过切割获取当前位置图片的rid
                int rIdIndex = indexList.get(j);
                int rIdEndIndex = runXmlText.indexOf("/>", rIdIndex);
                String rIdText = runXmlText.substring(rIdIndex, rIdEndIndex);
                String id = rIdText.split("\"")[1];
                //通过获取到的rid读取图片信息
                byte[] bytes = picDataMap.get(id);
                //当前图片流,可以对图片进行处理
                InputStream picIn = new ByteArrayInputStream(bytes);
                
                //value为要插入的文字
                String value = "要插入的值";
                if (!CommonUtil.checkNull(value)){
                	//用于判断图片后面是否还有文本
                    boolean hasEndWt = false;
                    for (int k = 0; k < wtIndexList.size(); k++) {
                    	int wtIndex = wtIndexList.get(k);
                        //当wt在pic之后进行插入
                        if (wtIndex > rIdIndex) {
                        	//run.setText(value, pos);pos数量就是当前run中<w:t></w:t>的数量
                            //防止多图问题,先把值和位置放到map中。在当前run中所有图片值确定之后在进行插入。
                            if (!CommonUtil.checkNull(insertMap.get(k))){
                            	insertMap.put(k, insertMap.get(k) + value);
                            } else{
                                insertMap.put(k, value);
                            }
                            hasEndWt = true;
                            break;
                        }
                    }
                    //如果图片后没有文本
                    if (!hasEndWt) {
                    	//防止多图问题,先把值和位置放到map中。在当前run中所有图片值确定之后在进行插入。
                        insertValue += value;
                        //通过测试来看可以不做下列判断,直接在当前run插入文本,但不确定文本是否都在图片后面。
                    }
                }
            }
        }
		//在当前run进行插入
        if (!CommonUtil.checkNullOrEmpty(insertMap)){
       		for (Map.Entry<Integer, String> entry : insertMap.entrySet()){
            	int key = entry.getKey();
                String value = entry.getValue();
                run.setText(value + run.getText(key), key);
            }
        }
        if (!"".equals(insertValue)) {
            XWPFRun newRun = para.createRun();
        	newRun.setText(insertValue);
        }
    }
}
out = new FileOutputStream(filePath);
doc.write(out);

————————————————
版权声明:本文为CSDN博主「学习要趁早z」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42677452/article/details/116267235

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习要趁早z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值