您好,登錄后才能下訂單哦!
小編給大家分享一下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(); }
以上是“java中poi如何設置生成的word圖片為上下型環繞”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。