一、因为原本的XWPFDocument类插入图片方法有bug,要么打不开word,要么打开了不显示图片,所以新建一个CustomXWPFDocument类继承XWPFDocument,重写插入图片方法。
二、插入到指定位置(书签)是获取所有段落、所有表格,遍历获取到的每一个段落(表格可以获取到cell后再获取cell里的段落),段落通过paragraph.getCTP().getBookmarkStartList()获得所有的书签,匹配需要的书签创建run,然后把图片添加到创建的run中。
三、插入图片默认为嵌入型,这里提供浮于文字上方方法(把anchor标签下的behindDoc属性设为0,同时添加一个
四、其中main方法里为启动方式
五、完整代码如下:
package com.enter.net.fhbusiness.construction.service.impl;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
/**
* poi在指定书签位置添加图片
*/
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 addPictureToRun(XWPFRun run, String blipId, int id, int width, int height) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
String picXml = "" +
"" +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" ";
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch(XmlException xe) {
xe.printStackTrace();
}
CTPositiveSize2D extent = null;
CTNonVisualDrawingProps docPr = null;
CTInline inline = run.getCTR().addNewDrawing().addNewInline();
inline.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
extent = inline.addNewExtent();
docPr = inline.addNewDocPr();
extent.setCx(width);
extent.setCy(height);
docPr.setId(id);
docPr.setName("Picture " + id);
docPr.setDescr("Generated");
}
public static void main(String[] args) throws IOException, InvalidFormatException {
// String doc_path = "E:\\apache-tomcat-8.0.30\\webapps\\jeefh\\fh\\doc\\pageoffice\\c3f13d99bb1e455fb585691271a9d729.doc";
String doc_path = "D:\\11.docx";
String img_path = "E:\\apache-tomcat-8.0.30\\webapps\\jeefh\\fh\\doc\\pageoffice\\img\\jsk.png";
new CustomXWPFDocument().runText("PO_user_name1",doc_path, "d");//书签替换内容
new CustomXWPFDocument().runImg("PO_user_name1",doc_path, img_path, true, 100, 100, 0, 0);//书签替换图片
// new CustomXWPFDocument().runText("PO_user_name2",doc_path, " bb");//书签替换内容
// new CustomXWPFDocument().runImg("PO_user_name2",doc_path, img_path, true, 100, 100, 80, 0);//书签替换图片
// new CustomXWPFDocument().runText("PO_user_name3",doc_path, " cc");//书签替换内容
// new CustomXWPFDocument().runImg("PO_user_name3",doc_path, img_path, true, 100, 100, 160, 0);//书签替换图片
}
/**
* @param name 书签名
* @param doc_path word路径
* @param text 替换的内容
*/
public void runText(String name,String doc_path,String text) {
CustomXWPFDocument document = null;
try {
document = new CustomXWPFDocument(new FileInputStream(doc_path));
Iterator it = document.getTablesIterator();//获取所有表格
boolean flag = false;
while(it.hasNext()){
XWPFTable table = it.next();
List rows = table.getRows();//每一行数据
for (XWPFTableRow row : rows) {
List cells = row.getTableCells();//每一列数据
for (XWPFTableCell cell : cells) {
List paragraphs = cell.getParagraphs();
flag = document.setText(document, paragraphs,name,text);
if (flag) {
break;
}
}
if (flag) {
break;
}
}
if (flag) {
break;
}
}
List list = document.getParagraphs();//获取所有段落
if (!flag) {//表格里没找到需要的书签,段落里接着找
document.setText(document, list,name,text);
}
FileOutputStream fos = new FileOutputStream(doc_path);
document.write(fos);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}catch (InvalidFormatException e) {
e.printStackTrace();
}
}
/**
*
* @param document
* @param paragraphs 所有段落
* @param name 书签名
* @param text 替换的内容
* @return boolean
* @throws InvalidFormatException
* @throws FileNotFoundException
*/
private boolean setText(CustomXWPFDocument document, List paragraphs,String name,String text) throws InvalidFormatException, FileNotFoundException {
boolean flag = false;
for (XWPFParagraph paragraph : paragraphs) {//遍历段落
List bookmarkStartList = paragraph.getCTP().getBookmarkStartList();//当前段落里的所有书签
for (CTBookmark bookmark : bookmarkStartList) {//遍历当前段落里的所有书签
String bookmarkName = bookmark.getName();
if (name.equals(bookmarkName)) {//找到需要的书签
XWPFRun run = paragraph.createRun();//创建run
run.setText(text);
return true;
}
}
}
return flag;
}
/**
* @param name 书签名
* @param doc_path word路径
* @param img_path 图片路径
* @param behindDoc 是否浮于文字上方 true是浮于,false是不浮
* @param width 图片宽度
* @param height 图片高度
* @param leftOffset 图片水平偏移:负数向左,正数向右
* @param topOffset 图片垂直偏移:负数向上,正数向下
*/
public void runImg(String name,String doc_path,String img_path,boolean behindDoc,int width, int height,int leftOffset, int topOffset) {
CustomXWPFDocument document = null;
try {
document = new CustomXWPFDocument(new FileInputStream(doc_path));
Iterator it = document.getTablesIterator();//获取所有表格
boolean flag = false;
while(it.hasNext()){
XWPFTable table = it.next();
List rows = table.getRows();//每一行数据
for (XWPFTableRow row : rows) {
List cells = row.getTableCells();//每一列数据
for (XWPFTableCell cell : cells) {
List paragraphs = cell.getParagraphs();
flag = document.setPicture(document, paragraphs,name,img_path,behindDoc,width,height,leftOffset,topOffset);
if (flag) {
break;
}
}
if (flag) {
break;
}
}
if (flag) {
break;
}
}
List list = document.getParagraphs();//获取所有段落
if (!flag) {//表格里没找到需要的书签,段落里接着找
document.setPicture(document, list,name,img_path,behindDoc,width,height,leftOffset,topOffset);
}
FileOutputStream fos = new FileOutputStream(doc_path);
document.write(fos);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}catch (InvalidFormatException e) {
e.printStackTrace();
}
}
/**
*
* @param document
* @param paragraphs 所有段落
* @param name 书签名
* @param img_path 图片路径
* @param behindDoc 是否浮于文字上方 true是浮于,false是不浮
* @param width 图片宽度
* @param height 图片高度
* @param leftOffset 图片水平偏移:负数向左,正数向右
* @param topOffset 图片垂直偏移:负数向上,正数向下
* @return boolean
* @throws InvalidFormatException
* @throws FileNotFoundException
*/
private boolean setPicture(CustomXWPFDocument document, List paragraphs,String name,String img_path,boolean behindDoc,int width, int height,
int leftOffset, int topOffset) throws InvalidFormatException, FileNotFoundException {
boolean flag = false;
for (XWPFParagraph paragraph : paragraphs) {//遍历段落
List bookmarkStartList = paragraph.getCTP().getBookmarkStartList();//当前段落里的所有书签
for (CTBookmark bookmark : bookmarkStartList) {//遍历当前段落里的所有书签
String bookmarkName = bookmark.getName();
if (name.equals(bookmarkName)) {//找到需要的书签
XWPFRun run = paragraph.createRun();//创建run
String picId = document.addPictureData(new FileInputStream(img_path), XWPFDocument.PICTURE_TYPE_PNG);
document.addPictureToRun(run, picId, document.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_PNG), width, height);//把图片添加到创建的run中
//设置图片浮于文字上方
if (behindDoc) {
CTDrawing drawing = run.getCTR().getDrawingArray(0);
CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
//拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "11",
Units.toEMU(width), Units.toEMU(height),//图片大小
Units.toEMU(leftOffset), Units.toEMU(topOffset));//相对当前段落位置的偏移位置,左右偏移:负数向左,正数向右,上下偏移:负数向上,正数向下
drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
drawing.removeInline(0);//删除行内属性
}
return true;
}
}
}
return flag;
}
/**
* @param ctGraphicalObject 图片数据
* @param deskFileName 图片描述
* @param width 宽
* @param height 高
* @param leftOffset 水平偏移:负数向左,正数向右
* @param topOffset 垂直偏移:负数向上,正数向下
* @return CTAnchor
* @throws Exception
*/
public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
String deskFileName, int width, int height,
int leftOffset, int topOffset) {
//浮在文字上的设置主要是anchor标签下的behindDoc属性设为0,同时添加一个 的空标签。
if (StringUtils.isBlank(deskFileName)) {
deskFileName = new Random().nextInt(999) + "";//描述不能为空,赋值一个随机数
}
String anchorXML =
""
+ ""
+ ""
+ "" + leftOffset + " "
+ " "
+ ""
+ "" + topOffset + " " +
" "
+ " "
+ ""
+ " "
+ " "
+ " ";
CTDrawing drawing = null;
try {
drawing = CTDrawing.Factory.parse(anchorXML);
} catch (XmlException e) {
e.printStackTrace();
}
CTAnchor anchor = drawing.getAnchorArray(0);
anchor.setGraphic(ctGraphicalObject);
return anchor;
}
}
六、用到的相关jar包maven
org.apache.poi
poi
3.9
org.apache.poi
poi-examples
3.9
org.apache.poi
poi-ooxml
3.9
org.apache.poi
poi-ooxml-schemas
3.9
org.apache.poi
ooxml-schemas
1.1
org.apache.xmlbeans
xmlbeans
2.6.0
org.apache.poi
poi-scratchpad
3.9