导出word文档的过程中因为文档信息展示需要,要在指定位置插入图片,遇到的一系列问题整理:
POI框架在处理Excel文档方面功能的确很强大,但是在处理word文档方面就略显劣势,使用poi在文档中插入图片时打开文档提示有错误或者图片不显示甚至文档直接打不开,这个问题一方面和office版本有关系,另一方面POI自出生那天起在处理word文档方面就带有缺陷,直至今天在最新版本的代码中仍然没有把这个bug优化。
下面是我遇到的问题:

其实这个问题如果你不在意的话也不算是什么大问题,点击“是”然后另存为新文档这个问题就会消失,但是真正拿出去用或是自己较真的话还真是一个挺头疼的问题。
先说一下造成这个问题的原因吧(个人理解不一定准确),poi向word插入图片首先是以xml形式写进去的,如果你把.doc文件转换成xml格式文件你会发现所有的文字、图片、表格等信息都是以xml数据格式存储,生成的文档之所以会报错就是因为poi自带的生成图片的方法中图片的xml头文件是错的。
知道问题的原因了那就试着去重写他的方法就好了,网上也有很多大神已经重写好的,不过大多重写的是create方法,createpicture只能在文章末尾添加图片,不能满足我的需求。
下面是addpicture方法:
//添加图片重写addPicture方法
public static void addPictureRewrite(XWPFRun xwpfRun, String embed, int id, int width, int height) throws XmlException {
final int EMU = 9000;
width *= EMU;
height *= EMU;
CTInline ctInline = xwpfRun.getCTR().addNewDrawing().addNewInline();
String pictureXml ="<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=\"" + embed + "\" 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>";
XmlToken xmlToken = XmlToken.Factory.parse(pictureXml);
ctInline.set(xmlToken);
ctInline.setDistT(0);
ctInline.setDistB(0);
ctInline.setDistL(0);
ctInline.setDistR(0);
CTPositiveSize2D ct = ctInline.addNewExtent();
ct.setCx(width);
ct.setCy(height);
CTNonVisualDrawingProps docPic = ctInline.addNewDocPr();
docPic.setId(id);
docPic.setName("Picture " + id);
docPic.setDescr("Generated");
}
方法调用:
//这里都是零星的代码段,完整代码没有贴出来,只是简单示意怎么调用重写后的方法
InputStream is = new FileInputStream(path);
XWPFDocument doc = new XWPFDocument(is);
//获取表格对象
List<XWPFTable> tables = doc.getTables();
//获取表格模板
XWPFTable tabel = tables.get(index);
//获取表格
rows = tabel.getRows();
cells = rows.get(i).getTableCells();
//遍历这一行单元格
for (int j = 0; j < cells.size(); j++) {
//判断该单元格内容是否是需要替换的图片
if (imgMatcher(cells.get(i).getText()).find()) {
params1.put("picture", list.get(i));
replaceInImg(cells.get(i), params1, doc);
continue;
}
}
XWPFParagraph parag = cell.addParagraph();
XWPFRun run = para.createRun();
String picId = doc.addPictureData(is, XWPFDocument.PICTURE_TYPE_JPEG);
//addPict方法调用
addPictureRewrite(run, picId, XWPFDocument.PICTURE_TYPE_JPEG, 450, 300);
最后还遇到一个挺离谱的事,在重写addPicture方法之后添加第二张图片,那个问题又出现了,各种方式都没排查出来是什么问题,在快要放弃的时候试着把模板重新写了一个,问题竟然消失了,最后竟然是模板的问题,因为文件模板是客户给的,文件后缀是.doc,后面拿过来之后直接把文件后缀改成了.docx看似没问题的操作,其实文档的数据格式差别还是很大的,又兴趣可以把这两个后缀的文档分别转换成xml格式研究一下。
|