POI匯出word檔案 插入圖片報錯問題整理
阿新 • • 發佈:2021-02-13
匯出word文件的過程中因為文件資訊展示需要,要在指定位置插入圖片,遇到的一系列問題整理:
POI框架在處理Excel文件方面功能的確很強大,但是在處理word文件方面就略顯劣勢,使用poi在文件中插入圖片時開啟文件提示有錯誤或者圖片不顯示甚至文件直接打不開,這個問題一方面和office版本有關係,另一方面POI自出生那天起在處理word文件方面就帶有缺陷,直至今天在最新版本的程式碼中仍然沒有把這個bug優化。
下面是我遇到的問題:
其實這個問題如果你不在意的話也不算是什麼大問題,點選“是”然後另存為新文件這個問題就會消失,但是真正拿出去用或是自己較真的話還真是一個挺頭疼的問題。
先說一下造成這個問題的原因吧(個人理解不一定準確),poi向word插入圖片首先是以xml形式寫進去的,如果你把.doc檔案轉換成xml格式檔案你會發現所有的文字、圖片、表格等資訊都是以xml資料格式儲存,生成的文件之所以會報錯就是因為poi自帶的生成圖片的方法中圖片的xml標頭檔案是錯的。
知道問題的原因了那就試著去重寫他的方法就好了,網上也有很多大神已經重寫好的,不過大多重寫的是create方法,createpicture只能在文章末尾新增圖片,不能滿足我的需求。
下面是addpicture方法:
//新增圖片重寫addPicture方法 public static void addPictureRewrite(XWPFRun xwpfRun, String embed, int id, int width, int height) throws XmlException { final int EMU = 9000; width *= EMU; height *= EMU; CTInline ctInline = xwpfRun.getCTR().addNewDrawing().addNewInline(); String pictureXml ="<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" + " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" + " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" + " <pic:nvPicPr>" + " <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" + " <pic:cNvPicPr/>" + " </pic:nvPicPr>" + " <pic:blipFill>" + " <a:blip r:embed=\"" + embed + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" + " <a:stretch>" + " <a:fillRect/>" + " </a:stretch>" + " </pic:blipFill>" + " <pic:spPr>" + " <a:xfrm>" + " <a:off x=\"0\" y=\"0\"/>" + " <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" + " </a:xfrm>" + " <a:prstGeom prst=\"rect\">" + " <a:avLst/>" + " </a:prstGeom>" + " </pic:spPr>" + " </pic:pic>" + " </a:graphicData>" + "</a:graphic>"; XmlToken xmlToken = XmlToken.Factory.parse(pictureXml); ctInline.set(xmlToken); ctInline.setDistT(0); ctInline.setDistB(0); ctInline.setDistL(0); ctInline.setDistR(0); CTPositiveSize2D ct = ctInline.addNewExtent(); ct.setCx(width); ct.setCy(height); CTNonVisualDrawingProps docPic = ctInline.addNewDocPr(); docPic.setId(id); docPic.setName("Picture " + id); docPic.setDescr("Generated"); }
方法呼叫:
//這裡都是零星的程式碼段,完整程式碼沒有貼出來,只是簡單示意怎麼呼叫重寫後的方法 InputStream is = new FileInputStream(path); XWPFDocument doc = new XWPFDocument(is); //獲取表格物件 List<XWPFTable> tables = doc.getTables(); //獲取表格模板 XWPFTable tabel = tables.get(index); //獲取表格 rows = tabel.getRows(); cells = rows.get(i).getTableCells(); //遍歷這一行單元格 for (int j = 0; j < cells.size(); j++) { //判斷該單元格內容是否是需要替換的圖片 if (imgMatcher(cells.get(i).getText()).find()) { params1.put("picture", list.get(i)); replaceInImg(cells.get(i), params1, doc); continue; } } XWPFParagraph parag = cell.addParagraph(); XWPFRun run = para.createRun(); String picId = doc.addPictureData(is, XWPFDocument.PICTURE_TYPE_JPEG); //addPict方法呼叫 addPictureRewrite(run, picId, XWPFDocument.PICTURE_TYPE_JPEG, 450, 300);
最後還遇到一個挺離譜的事,在重寫addPicture方法之後新增第二張圖片,那個問題又出現了,各種方式都沒排查出來是什麼問題,在快要放棄的時候試著把模板重新寫了一個,問題竟然消失了,最後竟然是模板的問題,因為檔案模板是客戶給的,檔案字尾是.doc,後面拿過來之後直接把檔案字尾改成了.docx看似沒問題的操作,其實文件的資料格式差別還是很大的,又興趣可以把這兩個字尾的文件分別轉換成xml格式研究一下。