java poi设置生成的word的图片为上下型环绕以及其位置的实现

这篇文章主要介绍了java poi设置生成的word的图片为上下型环绕以及其位置的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

问题描述

在使用poi-tl word模版工具时,发现生成的文档中,图片格式为嵌入型,有的图片甚至被表格遮挡一半。而自己想要的图片格式为上下型环绕,并且图片需要居中。

问题分析

poi-tl渲染图片,使用的是org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,该方法中有一段代码:CTInline inline = drawing.addNewInline();意思就是默认将图片转为inline类型,即行内元素。

然后我们把生成的嵌入型图片的文档转换成xml文件,然后再新建一个文档,插入图片后,设置图片为上下型环绕,保存为另一个xml,比较下两个xml的区别。嵌入型图片的xml是:


上下型环绕的图片的xml是

我们看到两种格式的图片标签分别为inline和anchor。所以如果我们想把图片设置为上下型环绕,需要重写poi的addPicture方法,把图片转为anchor类型。

我们仿照org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,将CTInline inline = drawing.addNewInline();换成 CTAnchor anchor = drawing.addNewAnchor();,然后对比着xml,依次对anchor的字段进行赋值。结果发现生成的word无法正常打开,查了很多资料,都说poi的CTAnchor有问题,使用后无法正常打开生成的word。

此路不通,那我们就尝试另一种思路,我们不通过CTAnchor来生成anchor标签,而是直接使用xml,将xml赋给poi的drawing。具体的处理方式在后面。

xml标签和图片格式解析

在word中,在图片上右键,选择大小和位置,就可以看到如下界面:


图中的上下型对应的是xml中的标签,不同环绕方式该标签值不一样。如果需要其他格式,可以设置好后,把文档保存为xml,找到对应的标签。

图中的距正文上下左右距离,对应的是中的disT、disB、disL、disR属性。


图中位置一栏,水平对齐方式居中、相对于栏对应的是xml中的center

垂直-绝对位置0.1cm,下侧段落对应的是xml中的36195

我们可以根据不同的需要来设置不同的xml。

我使用的xml是

 String xml = "" + "" + "" + "center" + "" + "" + "0" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "0" + "" + "" + "0" + "" + ""; 

其中width和height是图片的宽度和高度,relationId是图片的id。

解决方案

1,首先定义一个poi-tl的图片渲染器,使得其不再调用poi默认的图片渲染器,而是使用我们自己定义的。

 public class MyPictureRenderPolicy extends AbstractRenderPolicy { @Override protected boolean validate(PictureRenderData data) { return (null != data.getData() || null != data.getPath()); } @Override public void doRender(RunTemplate runTemplate, PictureRenderData picture, XWPFTemplate template) throws Exception { XWPFRun run = runTemplate.getRun(); MyPictureRenderPolicy.Helper.renderPicture(run, picture); } @Override protected void afterRender(RenderContext context) { clearPlaceholder(context, false); } @Override protected void doRenderException(RunTemplate runTemplate, PictureRenderData data, Exception e) { logger.info("Render picture " + runTemplate + " error: {}", e.getMessage()); runTemplate.getRun().setText(data.getAltMeta(), 0); } public static class Helper { public static void renderPicture(XWPFRun run, PictureRenderData picture) throws Exception { int suggestFileType = suggestFileType(picture.getPath()); InputStream ins = null == picture.getData() ? new FileInputStream(picture.getPath()) : new ByteArrayInputStream(picture.getData()); String relationId = run.getDocument().addPictureData(ins, suggestFileType); long width = Units.toEMU(picture.getWidth()); long height = Units.toEMU(picture.getHeight()); CTDrawing drawing = run.getCTR().addNewDrawing(); String xml = "" + "" + "" + "center" + "" + "" + "0" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "0" + "" + "" + "0" + "" + ""; drawing.set(XmlToken.Factory.parse(xml, DEFAULT_XML_OPTIONS)); CTPicture pic = getCTPictures(drawing).get(0); XWPFPicture xwpfPicture = new XWPFPicture(pic, run); run.getEmbeddedPictures().add(xwpfPicture); } public static List getCTPictures(XmlObject o) { List pictures = new ArrayList<>(); XmlObject[] picts = o.selectPath("declare namespace pic='" + CTPicture.type.getName().getNamespaceURI() + "' .//pic:pic"); for (XmlObject pict : picts) { if (pict instanceof XmlAnyTypeImpl) { // Pesky XmlBeans bug - see Bugzilla #49934 try { pict = CTPicture.Factory.parse(pict.toString(), DEFAULT_XML_OPTIONS); } catch (XmlException e) { throw new POIXMLException(e); } } if (pict instanceof CTPicture) { pictures.add((CTPicture) pict); } } return pictures; } public static int suggestFileType(String imgFile) { int format = 0; if (imgFile.endsWith(".emf")) { format = XWPFDocument.PICTURE_TYPE_EMF; } else if (imgFile.endsWith(".wmf")) { format = XWPFDocument.PICTURE_TYPE_WMF; } else if (imgFile.endsWith(".pict")) { format = XWPFDocument.PICTURE_TYPE_PICT; } else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg-600")) { format = XWPFDocument.PICTURE_TYPE_JPEG; } else if (imgFile.endsWith(".png-600")) { format = XWPFDocument.PICTURE_TYPE_PNG; } else if (imgFile.endsWith(".dib")) { format = XWPFDocument.PICTURE_TYPE_DIB; } else if (imgFile.endsWith(".gif")) { format = XWPFDocument.PICTURE_TYPE_GIF; } else if (imgFile.endsWith(".tiff")) { format = XWPFDocument.PICTURE_TYPE_TIFF; } else if (imgFile.endsWith(".eps")) { format = XWPFDocument.PICTURE_TYPE_EPS; } else if (imgFile.endsWith(".bmp")) { format = XWPFDocument.PICTURE_TYPE_BMP; } else if (imgFile.endsWith(".wpg")) { format = XWPFDocument.PICTURE_TYPE_WPG; } else { throw new RenderException( "Unsupported picture: " + imgFile + ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg"); } return format; } } } 

然后在渲染模板的时候,配置我们自己定义的图片渲染器

 public static void main(String[] args) throws Exception{ String path = "1.docx"; InputStream templateFile = Demo.class.getClassLoader().getResourceAsStream(path); Map map = new HashMap(); map.put("pic", new PictureRenderData(120, 80, ".png-600", Demo.class.getClassLoader().getResourceAsStream("1.png-600"))); // 将数据整合到模板中去 Configure.ConfigureBuilder builder = Configure.newBuilder(); builder.supportGrammerRegexForAll(); builder.addPlugin('@', new MyPictureRenderPolicy()); XWPFTemplate template = XWPFTemplate.compile(templateFile, builder.build()).render(map); String docPath = "C:\\Users\\csdc01\\Desktop\\out.docx"; FileOutputStream outputStream1 = new FileOutputStream(docPath); template.write(outputStream1); outputStream1.flush(); outputStream1.close(); } 

源码:https://github.com/ksyzz/poi-tl-demo.git

以上就是java poi设置生成的word的图片为上下型环绕以及其位置的实现的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » Java