java poi設(shè)置生成的word的圖片為上下型環(huán)繞以及其位置的實(shí)現(xiàn)
問(wèn)題描述
在使用poi-tl word模版工具時(shí),發(fā)現(xiàn)生成的文檔中,圖片格式為嵌入型,有的圖片甚至被表格遮擋一半。而自己想要的圖片格式為上下型環(huán)繞,并且圖片需要居中。
問(wèn)題分析
poi-tl渲染圖片,使用的是org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,該方法中有一段代碼:CTInline inline = drawing.addNewInline();意思就是默認(rèn)將圖片轉(zhuǎn)為inline類型,即行內(nèi)元素。
然后我們把生成的嵌入型圖片的文檔轉(zhuǎn)換成xml文件,然后再新建一個(gè)文檔,插入圖片后,設(shè)置圖片為上下型環(huán)繞,保存為另一個(gè)xml,比較下兩個(gè)xml的區(qū)別。嵌入型圖片的xml是:

上下型環(huán)繞的圖片的xml是

我們看到兩種格式的圖片標(biāo)簽分別為inline和anchor。所以如果我們想把圖片設(shè)置為上下型環(huán)繞,需要重寫poi的addPicture方法,把圖片轉(zhuǎn)為anchor類型。
我們仿照org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,將CTInline inline = drawing.addNewInline();換成 CTAnchor anchor = drawing.addNewAnchor();,然后對(duì)比著xml,依次對(duì)anchor的字段進(jìn)行賦值。結(jié)果發(fā)現(xiàn)生成的word無(wú)法正常打開(kāi),查了很多資料,都說(shuō)poi的CTAnchor有問(wèn)題,使用后無(wú)法正常打開(kāi)生成的word。
此路不通,那我們就嘗試另一種思路,我們不通過(guò)CTAnchor來(lái)生成anchor標(biāo)簽,而是直接使用xml,將xml賦給poi的drawing。具體的處理方式在后面。
xml標(biāo)簽和圖片格式解析
在word中,在圖片上右鍵,選擇大小和位置,就可以看到如下界面:

圖中的上下型對(duì)應(yīng)的是xml中的<wp:wrapTopAndBottom/>標(biāo)簽,不同環(huán)繞方式該標(biāo)簽值不一樣。如果需要其他格式,可以設(shè)置好后,把文檔保存為xml,找到對(duì)應(yīng)的標(biāo)簽。
圖中的距正文上下左右距離,對(duì)應(yīng)的是<wp:anchor distT="71755" distB="71755" distL="114300" distR="114300" ...>中的disT、disB、disL、disR屬性。

圖中位置一欄,水平對(duì)齊方式居中、相對(duì)于欄對(duì)應(yīng)的是xml中的<wp:positionH relativeFrom="column"><wp:align>center</wp:align></wp:positionH>。
垂直-絕對(duì)位置0.1cm,下側(cè)段落對(duì)應(yīng)的是xml中的<wp:positionV relativeFrom="paragraph"><wp:posOffset>36195</wp:posOffset></wp:positionV>。
我們可以根據(jù)不同的需要來(lái)設(shè)置不同的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,首先定義一個(gè)poi-tl的圖片渲染器,使得其不再調(diào)用poi默認(rèn)的圖片渲染器,而是使用我們自己定義的。
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;
}
}
}
然后在渲染模板的時(shí)候,配置我們自己定義的圖片渲染器
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")));
// 將數(shù)據(jù)整合到模板中去
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
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java使用poi-tl1.9.1生成Word文檔的技巧分享
- java 使用POI合并兩個(gè)word文檔
- java實(shí)現(xiàn)在線預(yù)覽--poi實(shí)現(xiàn)word、excel、ppt轉(zhuǎn)html的方法
- 利用Java Apache POI 生成Word文檔示例代碼
- java Apache poi 對(duì)word doc文件進(jìn)行讀寫操作
- Java使用poi將word轉(zhuǎn)換為html
- Java中使用Apache POI讀取word文件簡(jiǎn)單示例
- java使用poi讀取ppt文件和poi讀取excel、word示例
- java通過(guò)poi解析word入門的操作方法
相關(guān)文章
java jackson 將對(duì)象轉(zhuǎn)json時(shí),忽略子對(duì)象的某個(gè)屬性操作
這篇文章主要介紹了java jackson 將對(duì)象轉(zhuǎn)json時(shí),忽略子對(duì)象的某個(gè)屬性操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10
解決IDEA中maven導(dǎo)入jar包一直報(bào)錯(cuò)問(wèn)題
這篇文章主要介紹了解決IDEA中maven導(dǎo)入jar包一直報(bào)錯(cuò)問(wèn)題,本文通過(guò)實(shí)例圖文的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
快速校驗(yàn)實(shí)體類時(shí),@Valid,@Validated,@NotNull注解無(wú)效的解決
這篇文章主要介紹了快速校驗(yàn)實(shí)體類時(shí),@Valid,@Validated,@NotNull注解無(wú)效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
SWT(JFace)體驗(yàn)之圖片的動(dòng)態(tài)漸變效果
SWT(JFace)體驗(yàn)之圖片的動(dòng)態(tài)漸變效果2009-06-06
Spring Cloud Gateway實(shí)現(xiàn)灰度發(fā)布方案
灰度發(fā)布是在微服務(wù)中的表現(xiàn)為同一服務(wù)同時(shí)上線不同版本,讓一部分用戶使用新版本來(lái)驗(yàn)證新特性,如果驗(yàn)證沒(méi)有問(wèn)題,則將所有用戶都遷移到新版本上,本文就來(lái)介紹一下如何實(shí)現(xiàn),感興趣的可以了解一下2023-12-12
java中Socket設(shè)置超時(shí)時(shí)間的兩種方式
這篇文章主要介紹了java中Socket設(shè)置超時(shí)時(shí)間的兩種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
SpringApplicationRunListener監(jiān)聽(tīng)器源碼詳解
這篇文章主要介紹了SpringApplicationRunListener監(jiān)聽(tīng)器源碼詳解,springboot提供了兩個(gè)類SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架還提供了一個(gè)ApplicationListener接口,需要的朋友可以參考下2023-11-11

