您的位置:首页 > 其它

POI4.0(或3.17) 替换word(docx)文字为图片时,如何设置图片格式浮于文字上方

2018-11-06 13:30 1616 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/eei238234324/article/details/83758828

      最近项目中遇到一个问题:POI 根据模板文件生成 word时,需要进行文字替换和图片替换,其中文字替换不必多说,只是图片替换时需要格式为浮于文字上方,网上找不到合适的资料,没办法 ,只好穷折腾了一天。

      以WORD文件为模板,我用的是DOCX格式 的,至于DOC格式的话我想下面可能帮助不大,建议终止阅读。

      一、文字替换

      根据word模板进行文字替换比较简单,主要是将word中的目标位置预先填写好要插入的标记,定义的特殊一点,最好有前缀和后缀,防止poi解析时解析成多个段落,方便拼接,比如写成#{abc};在循环读取时设置好变量,检索到以 “#{” 开头的字符,再继续找到以 “}”结束的字符,拼好再替换。这里代码就不详细贴了,网上也能找到很多。

      另外 特殊字符如果是两个相临的话最好中间加个空格一类的 #{u1}  #{u2}。

      二、图片替换

      图片替换时,是以图片替换模板中的文本,还是上文说的类似 #{abc}类的特殊标记,其中POI官方给出的文档比较简单,并且默认是以嵌入式插入的,并不能满足需要,所以需要做一些改动,以poi4.0.0,3.17为例(我用的是4.0.0版本)。

      说说解决思路过程:操作docx也可以看作是处理xml文件。docx用压缩文件打开就能看到word/document.xml,此文件是关键,我开始的时候怎么试也不行,最后想到直接用xml方式来处理。我先用CTInline插入图片到一个名叫a.docx的文件,此效果是图片嵌入。将此word另存一份新的b.docx,用office程序打开b.docx,然后只做一个操作,将图片调节为浮于文字上方,关闭保存。现在得到的a.docx和b.docx一个是嵌入一个是浮于文字上方,用压缩文件打开a.docx,b.docx两个文档 ,然后找到刚才说的word/document.xml,用文本编辑器打开,比较在关键文档 处的不同,就是标签<wp:inline>和<wp:anchor>的不同,具体代码不贴了,然后找到这个不同后基本问题就解决了,剩下的就是代码实现了。

      代码实现上遇到了一个小问题,就是此关键要是重写org.apache.poi.xwpf.usermodel.XWPFRun.java类,开始用到的版本是3.17,在把源码拷出来重写时,找不到名称为CTSignedTwipsMeasure的类,很奇怪,应该是在poi-ooxml-schemas.jar的包里,最后我是升级到了4.0.0,又把poi-ooxml-schemas.jar包替换为ooxml-schemas-1.4.jar,其实直接替换为ooxml-schemas-1.4.jar就行,不过已经升级了就不再回退版本了,只用到一小部分,没什么大事。

      言归正传,下一步就是重写XWPFRun.java(重写操作是先在项目源文件中增加一个org.apache.poi.xwpf.usermodel的包,然后再新建个XWPFRun.java的类,源代码拷上去)。主要是重写XWPFRun.java中的addPicture方法,上代码:

[code]public XWPFPicture addPicture(InputStream pictureData, int pictureType, String filename, int width, int height)
throws InvalidFormatException, IOException {
String relationId;
XWPFPictureData picData;

// Work out what to add the picture to, then add both the
//  picture and the relationship for it
// TODO Should we have an interface for this sort of thing?
if (parent.getPart() instanceof XWPFHeaderFooter) {
XWPFHeaderFooter headerFooter = (XWPFHeaderFooter) parent.getPart();
relationId = headerFooter.addPictureData(pictureData, pictureType);
picData = (XWPFPictureData) headerFooter.getRelationById(relationId);
} else {
@SuppressWarnings("resource")
XWPFDocument doc = parent.getDocument();
relationId = doc.addPictureData(pictureData, pictureType);
picData = (XWPFPictureData) doc.getRelationById(relationId);
}

// Create the drawing entry for it
try {
CTDrawing drawing = run.addNewDrawing();
CTAnchor inline = drawing.addNewAnchor();

// Do the fiddly namespace bits on the inline
// (We need full control of what goes where and as what)
String xml =
"<a:graphic xmlns:a=\"" + CTGraphicalObject.type.getName().getNamespaceURI() + "\">" +
"<a:graphicData uri=\"" + CTPicture.type.getName().getNamespaceURI() + "\">" +
"<pic:pic xmlns:pic=\"" + CTPicture.type.getName().getNamespaceURI() + "\" />" +
"</a:graphicData>" +
"</a:graphic>";
InputSource is = new InputSource(new StringReader(xml));
org.w3c.dom.Document doc = DocumentHelper.readDocument(is);
inline.set(XmlToken.Factory.parse(doc.getDocumentElement(), DEFAULT_XML_OPTIONS));

System.out.println("*********************"+inline.xmlText());
// Setup the inline
inline.setDistT(0);
inline.setDistR(0);
inline.setDistB(0);
inline.setDistL(0);

inline.setSimplePos2(false);
inline.setRelativeHeight(251658240);//查了文档 ,也试过,没找到作用位置,先放着
inline.setBehindDoc(false);//重点,浮于文字上方
inline.setLocked(false);
inline.setLayoutInCell(true);
inline.setAllowOverlap(true);

CTPoint2D simplePost = inline.addNewSimplePos();
simplePost.setX(0);
simplePost.setY(0);
CTPosH ph = inline.addNewPositionH();
ph.setRelativeFrom(STRelFromH.PAGE);//以整个页面为准的定位
ph.setPosOffset(396049);//水平位置,针对RelativeFrom的一个偏移 1厘米=360045 ,1.1*360045
CTPosV pv = inline.addNewPositionV();
pv.setRelativeFrom(STRelFromV.PAGE);
pv.setPosOffset(468058);//竖直位置,针对RelativeFrom的一个偏移 1.3*360045

/**
* 这个是此元素指定的其他程度应添加到每个边缘 (顶部、 底部、 左、 右)
* 以补偿应用于 DrawingML 对象的任何图形效果的图像
* 但目前好像用不到
*/
CTEffectExtent efextent = inline.addNewEffectExtent();
efextent.setL(19050);
efextent.setT(0);
efextent.setR(0);
efextent.setB(0);

CTWrapNone wn = inline.addNewWrapNone();

CTNonVisualGraphicFrameProperties fp = inline.addNewCNvGraphicFramePr();

CTNonVisualDrawingProps docPr = inline.addNewDocPr();
long id = getParent().getDocument().getDrawingIdManager().reserveNew();
docPr.setId(id);
/* This name is not visible in Word 2010 anywhere. */
docPr.setName("Drawing " + id);
docPr.setDescr(filename);

CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);

// Grab the picture object
CTGraphicalObject graphic = inline.getGraphic();
CTGraphicalObjectData graphicData = graphic.getGraphicData();
CTPicture pic = getCTPictures(graphicData).get(0);

// Set it up
CTPictureNonVisual nvPicPr = pic.addNewNvPicPr();

CTNonVisualDrawingProps cNvPr = nvPicPr.addNewCNvPr();
/* use "0" for the id. See ECM-576, 20.2.2.3 */
cNvPr.setId(0L);
/* This name is not visible in Word 2010 anywhere */
cNvPr.setName("Picture " + id);
cNvPr.setDescr(filename);

CTNonVisualPictureProperties cNvPicPr = nvPicPr.addNewCNvPicPr();
cNvPicPr.addNewPicLocks().setNoChangeAspect(true);

CTBlipFillProperties blipFill = pic.addNewBlipFill();
CTBlip blip = blipFill.addNewBlip();
blip.setEmbed(parent.getPart().getRelationId(picData));
/********   增加  ***********/
blip.setCstate(STBlipCompression.PRINT);//压缩状态

blipFill.addNewStretch().addNewFillRect();

CTShapeProperties spPr = pic.addNewSpPr();
CTTransform2D xfrm = spPr.addNewXfrm();

CTPoint2D off = xfrm.addNewOff();
off.setX(0);
off.setY(0);

CTPositiveSize2D ext = xfrm.addNewExt();
ext.setCx(width);
ext.setCy(height);

CTPresetGeometry2D prstGeom = spPr.addNewPrstGeom();
prstGeom.setPrst(STShapeType.RECT);
prstGeom.addNewAvLst();

// Finish up
XWPFPicture xwpfPicture = new XWPFPicture(pic, this);
pictures.add(xwpfPicture);
return xwpfPicture;
} catch (XmlException | SAXException e) {
throw new IllegalStateException(e);
}
}

      其他代码就不贴了,网上很多,浮于文字上方的关键就是要用CTAnchor。

      如果大家有时间的话仔细对比office的xml文件及官方文档的话,office的问题基本都能迎刃而解,附其中一个属性的官方文档说明https://docs.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.drawing.wordprocessing.horizontalposition?view=openxml-2.8.1

      希望对大家有所帮助。

      心态放平,多试多思考。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: