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中的<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> {
@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 = "<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

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

(0)

相关推荐

  • Java使用poi将word转换为html

    使用poi将word转换为html,支持doc,docx,转换后可以保持图片.样式. 1.导入Maven包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.14</version> </dependency> <dependency> <groupId>org.a

  • 利用Java Apache POI 生成Word文档示例代码

    最近公司做的项目需要实现导出Word文档的功能,网上关于POI生成Word文档的例子很少,找了半天才在官网里找到个Demo,有了Demo一切就好办了. /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See

  • java使用poi读取ppt文件和poi读取excel、word示例

    Apache的POI项目可以用来处理MS Office文档,codeplex上还有一个它的.net版本.POI项目可创建和维护操作各种基于OOXML和OLE2文件格式的Java API.大多数MS Office都是OLE2格式的.POI通HSMF子项目来支持Outlook,通过HDGF子项目来支持Visio,通过HPBF子项目来支持Publisher. 使用POI抽取Word简单示例: 要引入poi-3.7.jat和poi-scratchpad-3.7.ajr这两个包. 复制代码 代码如下: p

  • Java中使用Apache POI读取word文件简单示例

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 1.读取word 2003及word 2007需要的jar包 读取 2003 版本(.doc)的word文件相对来说比较简单,只需要 poi-3.5-beta6-20090622.jar 和 poi-scratchpad-3.5-beta6-20090622.jar 两个 jar 包即可, 而 2007 版本(.docx)就麻烦多,我说的这个麻烦不

  • java使用POI实现html和word相互转换

    项目后端使用了springboot,maven,前端使用了ckeditor富文本编辑器.目前从html转换的word为doc格式,而图片处理支持的是docx格式,所以需要手动把doc另存为docx,然后才可以进行图片替换. 一.添加maven依赖 主要使用了以下和poi相关的依赖,为了便于获取html的图片元素,还使用了jsoup: <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi&

  • java Apache poi 对word doc文件进行读写操作

    使用POI读写Word doc文件 Apache poi的hwpf模块是专门用来对word doc文件进行读写操作的.在hwpf里面我们使用HWPFDocument来表示一个word doc文档.在HWPFDocument里面有这么几个概念: Range:它表示一个范围,这个范围可以是整个文档,也可以是里面的某一小节(Section),也可以是某一个段落(Paragraph),还可以是拥有共同属性的一段文本(CharacterRun).   Section:word文档的一个小节,一个word文

  • java poi解析word的方法

    之前做过用java读取word文档,获取word文本内容. 但发现docx的支持,doc就异常了. 后来找了很多资料发现是解析方法不一样. 首先要导入poi相关的jar包 我用的是maven,pom.xml引入如下: <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.8</version>

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

    问题描述 在使用poi-tl word模版工具时,发现生成的文档中,图片格式为嵌入型,有的图片甚至被表格遮挡一半.而自己想要的图片格式为上下型环绕,并且图片需要居中. 问题分析 poi-tl渲染图片,使用的是org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,该方法中有一段代码:CTInline inline = drawing.addNewInline();意思就是默认将图片转为inline类型,即行内元素. 然后我们把生成的嵌入型图片的文档转

  • java 使用POI合并两个word文档

    java POI合并两个word文档 有需要的可以将主函数中写死的地方改为一个List import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.xwpf.usermodel

  • java 验证码的生成实现

    java 验证码的生成实现 所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片, 图片里加上一些干扰,例如随机画数条直线或者画一些点,由用户肉眼识别其中的验证码信息,输入表单提交网站验证,验证成功后才能使用某项功能.验证码中之所以加上凌乱的直线是为了防止某些人使用OCR软件识别随机产生的数字或符号,从而达到恶意破解密码.刷票.论坛灌水.刷页等恶意行为.下面就开始直接上代码吧: 下面是Demo的文件组织结构 下面就是index.jsp的代码.主要功能是单击浏览器上的验证码图片,实现验证码的更

  • Java模板动态生成word文件的方法步骤

    最近项目中需要根据模板生成word文档,模板文件也是word文档.当时思考一下想用POI API来做,但是觉得用起来相对复杂.后来又找了一种方式,使用freemarker模板生成word文件,经过尝试觉得还是相对简单易行的. 使用freemarker模板生成word文档主要有这么几个步骤 1.创建word模板:因为我项目中用到的模板本身是word,所以我就直接编辑word文档转成freemarker(.ftl)格式的. 2.将改word文件另存为xml格式,注意使用另存为,不是直接修改扩展名.

  • js生成word中图片处理方法

    首先功能是要求前台导出word,但是前后台是分离的,图片存在后台,所以就存在跨域问题. 导出文字都是没有问题的(jquery.wordexport.js),但是导出图片就存在问题了: 图片是以链接形式存到word中,这样如果是需要vpn的网站就会存在生成的word在没有vpn的情况下打不开,有vpn的情况下必须启用编辑才能加载出来图片. 解决办法:将图片转换成Data URL格式,再导出. 详细代码如下所示: function changeImgToDataurl(){ var charImg

  • java poi导出图片到excel示例代码

    本文实例为大家分享了java使用poi导出图片到Excel的具体代码,供大家参考,具体内容如下 代码实现 Controller /** * 导出志愿者/人才数据 * @param talent_type * @return */ @RequestMapping("/exportData") public void exportData(Integer talent_type, HttpServletResponse response) { String fileId = UUID.ra

  • Java使用Servlet生成验证码图片

    本文实例为大家分享了Java使用Servlet生成验证码图片的具体代码,供大家参考,具体内容如下 一.实现思路 1.使用BufferedImage用于在内存中存储生成的验证码图片 2.使用Graphics来进行验证码图片的绘制,并将绘制在图片上的验证码存放到session中用于后续验证 3.最后通过ImageIO将生成的图片进行输出 4.页面通过访问servlet来获取并展示验证码 5.在后台获取页面提交的验证码,然后和存放在session中的验证码进行比对,进行校验 二.生成验证码 生成验证码

  • Java实现自动生成缩略图片

    本文实例为大家分享了Java实现自动生成缩略图片的具体代码,供大家参考,具体内容如下 一.自动生成缩略图方法: package writeimg;   import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import ja

  • java中ZXing 生成、解析二维码图片的小示例

    概述 ZXing 是一个开源 Java 类库用于解析多种格式的 1D/2D 条形码.目标是能够对QR编码.Data Matrix.UPC的1D条形码进行解码. 其提供了多种平台下的客户端包括:J2ME.J2SE和Android. 官网:ZXing github仓库 实战 本例演示如何在一个非 android 的 Java 项目中使用 ZXing 来生成.解析二维码图片. 安装 maven项目只需引入依赖: <dependency> <groupId>com.google.zxing

随机推荐