首页 > 编程 > Java > 正文

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

2019-11-26 08:37:14
字体:
来源:转载
供稿:网友

问题描述

在使用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中的<wp:wrapTopAndBottom/>标签,不同环绕方式该标签值不一样。如果需要其他格式,可以设置好后,把文档保存为xml,找到对应的标签。

图中的距正文上下左右距离,对应的是<wp:anchor distT="71755" distB="71755" distL="114300" distR="114300" ...>中的disT、disB、disL、disR属性。


图中位置一栏,水平对齐方式居中、相对于栏对应的是xml中的<wp:positionH relativeFrom="column"><wp:align>center</wp:align></wp:positionH>。

垂直-绝对位置0.1cm,下侧段落对应的是xml中的<wp:positionV relativeFrom="paragraph"><wp:posOffset>36195</wp:posOffset></wp:positionV>。

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

我使用的xml是

 String xml = "<wp:anchor allowOverlap=/"0/" layoutInCell=/"1/" locked=/"0/" behindDoc=/"0/" relativeHeight=/"0/"         simplePos=/"0/" distR=/"0/" distL=/"0/" distB=/"0/" distT=/"0/" " +        " xmlns:wp=/"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing/"" +        " xmlns:wp14=/"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing/"" +        " xmlns:r=/"http://schemas.openxmlformats.org/officeDocument/2006/relationships/" >" +        "<wp:simplePos y=/"0/" x=/"0/"/>" +        "<wp:positionH relativeFrom=/"column/">" +        "<wp:align>center</wp:align>" +        "</wp:positionH>" +        "<wp:positionV relativeFrom=/"paragraph/">" +        "<wp:posOffset>0</wp:posOffset>" +        "</wp:positionV>" +        "<wp:extent cy=/""+height+"/" cx=/""+width+"/"/>" +        "<wp:effectExtent b=/"0/" r=/"0/" t=/"0/" l=/"0/"/>" +        "<wp:wrapTopAndBottom/>" +        "<wp:docPr descr=/"Picture Alt/" name=/"Picture Hit/" id=/"0/"/>" +        "<wp:cNvGraphicFramePr>" +        "<a:graphicFrameLocks noChangeAspect=/"true/" xmlns:a=/"http://schemas.openxmlformats.org/drawingml/2006/main/" />" +        "</wp:cNvGraphicFramePr>" +        "<a:graphic xmlns:a=/"http://schemas.openxmlformats.org/drawingml/2006/main/">" +        "<a:graphicData uri=/"http://schemas.openxmlformats.org/drawingml/2006/picture/" xmlns:a=/"http://schemas.openxmlformats.org/drawingml/2006/main/">" +        "<pic:pic xmlns:pic=/"http://schemas.openxmlformats.org/drawingml/2006/picture/">" +        "<pic:nvPicPr>" +        "<pic:cNvPr name=/"Picture Hit/" id=/"1/"/>" +        "<pic:cNvPicPr/>" +        "</pic:nvPicPr>" +        "<pic:blipFill>" +        "<a:blip r:embed=/""+relationId+"/"/>" +        "<a:stretch>" +        "<a:fillRect/>" +        "</a:stretch>" +        "</pic:blipFill>" +        "<pic:spPr>" +        "<a:xfrm>" +        "<a:off y=/"0/" x=/"0/"/>" +        "<a:ext cy=/""+height+"/" cx=/""+width+"/"/>" +        "</a:xfrm>" +        "<a:prstGeom prst=/"rect/">" +        "<a:avLst/>" +        "</a:prstGeom>" +        "</pic:spPr>" +        "</pic:pic>" +        "</a:graphicData>" +        "</a:graphic>" +        "<wp14:sizeRelH relativeFrom=/"margin/">" +        "<wp14:pctWidth>0</wp14:pctWidth>" +        "</wp14:sizeRelH>" +        "<wp14:sizeRelV relativeFrom=/"margin/">" +        "<wp14:pctHeight>0</wp14:pctHeight>" +        "</wp14:sizeRelV>" +        "</wp:anchor>";        

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

解决方案

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

public class MyPictureRenderPolicy extends AbstractRenderPolicy<PictureRenderData> {@Overrideprotected boolean validate(PictureRenderData data) {  return (null != data.getData() || null != data.getPath());}@Overridepublic void doRender(RunTemplate runTemplate, PictureRenderData picture, XWPFTemplate template)    throws Exception {  XWPFRun run = runTemplate.getRun();  MyPictureRenderPolicy.Helper.renderPicture(run, picture);}@Overrideprotected void afterRender(RenderContext context) {  clearPlaceholder(context, false);}@Overrideprotected 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 = "<wp:anchor allowOverlap=/"0/" layoutInCell=/"1/" locked=/"0/" behindDoc=/"0/" relativeHeight=/"0/" simplePos=/"0/" distR=/"0/" distL=/"0/" distB=/"0/" distT=/"0/" " +        " xmlns:wp=/"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing/"" +        " xmlns:wp14=/"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing/"" +        " xmlns:r=/"http://schemas.openxmlformats.org/officeDocument/2006/relationships/" >" +        "<wp:simplePos y=/"0/" x=/"0/"/>" +        "<wp:positionH relativeFrom=/"column/">" +        "<wp:align>center</wp:align>" +        "</wp:positionH>" +        "<wp:positionV relativeFrom=/"paragraph/">" +        "<wp:posOffset>0</wp:posOffset>" +        "</wp:positionV>" +        "<wp:extent cy=/""+height+"/" cx=/""+width+"/"/>" +        "<wp:effectExtent b=/"0/" r=/"0/" t=/"0/" l=/"0/"/>" +        "<wp:wrapTopAndBottom/>" +        "<wp:docPr descr=/"Picture Alt/" name=/"Picture Hit/" id=/"0/"/>" +        "<wp:cNvGraphicFramePr>" +        "<a:graphicFrameLocks noChangeAspect=/"true/" xmlns:a=/"http://schemas.openxmlformats.org/drawingml/2006/main/" />" +        "</wp:cNvGraphicFramePr>" +        "<a:graphic xmlns:a=/"http://schemas.openxmlformats.org/drawingml/2006/main/">" +        "<a:graphicData uri=/"http://schemas.openxmlformats.org/drawingml/2006/picture/" xmlns:a=/"http://schemas.openxmlformats.org/drawingml/2006/main/">" +        "<pic:pic xmlns:pic=/"http://schemas.openxmlformats.org/drawingml/2006/picture/">" +        "<pic:nvPicPr>" +        "<pic:cNvPr name=/"Picture Hit/" id=/"1/"/>" +        "<pic:cNvPicPr/>" +        "</pic:nvPicPr>" +        "<pic:blipFill>" +        "<a:blip r:embed=/""+relationId+"/"/>" +        "<a:stretch>" +        "<a:fillRect/>" +        "</a:stretch>" +        "</pic:blipFill>" +        "<pic:spPr>" +        "<a:xfrm>" +        "<a:off y=/"0/" x=/"0/"/>" +        "<a:ext cy=/""+height+"/" cx=/""+width+"/"/>" +        "</a:xfrm>" +        "<a:prstGeom prst=/"rect/">" +        "<a:avLst/>" +        "</a:prstGeom>" +        "</pic:spPr>" +        "</pic:pic>" +        "</a:graphicData>" +        "</a:graphic>" +        "<wp14:sizeRelH relativeFrom=/"margin/">" +        "<wp14:pctWidth>0</wp14:pctWidth>" +        "</wp14:sizeRelH>" +        "<wp14:sizeRelV relativeFrom=/"margin/">" +        "<wp14:pctHeight>0</wp14:pctHeight>" +        "</wp14:sizeRelV>" +        "</wp:anchor>";    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<CTPicture> getCTPictures(XmlObject o) {    List<CTPicture> 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")) {      format = XWPFDocument.PICTURE_TYPE_JPEG;    } else if (imgFile.endsWith(".png")) {      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", Demo.class.getClassLoader().getResourceAsStream("1.png")));  // 将数据整合到模板中去  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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表