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

网友投稿 968 2022-12-28


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

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

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

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

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

我使用的xml是

String xml = "

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\" >" +

"" +

"" +

"center" +

"" +

"" +

"0" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"0" +

"" +

"" +

"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\" >" +

"" +

"" +

"center" +

"" +

"" +

"0" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"0" +

"" +

"" +

"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 = "

" 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\" >" +

"" +

"" +

"center" +

"" +

"" +

"0" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"" +

"0" +

"" +

"" +

"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\" >" +

"" +

"" +

"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")) {

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:项目管理系统接口设计(工程接口管理)
下一篇:微信模板消息接口测试工具(微信消息接口api)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~