Problem
需求很單純,在我們有了自動抓圖程式後,接著就是要自動取代文件圖片了。經過研究一番,目前我只有辦法去取代Word 2007的圖片,2003並沒找到相應的操作API。
How to?
在Word2007中,本文是使用XWPFDocument物件去操作,而XWPFDocument(本文)下包含了多個XWPFParagraph(段落)。XWPFParagraph包含多個XWPFRun(文字屬性描述區塊),XWPFRun則包含CTR(Run的描述屬性)。圖片相關物件可從CTR中取出來去操作。
要達到需求,我們必須去loop本文內容,插入新圖片並刪除原本的圖片。我的範例僅僅將原本圖片大小讀出來,接著再把圖片依據這個大小插入到Word中。做法很直覺,廢話不多說,看code:
public static void main(String[] args) throws Exception { String testFile = "testdata/test.docx"; String targetFile = "testdata/test_c.docx"; String image = "./testdata/Desert.jpg"; InputStream is = null; OutputStream os = null; try { is = new FileInputStream(testFile); os = new FileOutputStream(targetFile); CustomXWPFDocument doc = new CustomXWPFDocument(is); int count = 0; for( XWPFParagraph para : doc.getParagraphs()){ List<XWPFRun> runs = para.getRuns(); for( XWPFRun run : runs ){ List<CTDrawing> drawings = run.getCTR().getDrawingList(); int size = drawings.size(); for( int i = 0 ; i < size ; i++ ){ CTPositiveSize2D ps2d = drawings.get(0).getInlineList().get(0).getExtent(); String blipId = addPictureData(image, doc); doc.createPicture(run.getCTR(), blipId, doc.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_PNG), ps2d.getCx(), ps2d.getCy()); run.getCTR().removeDrawing(0); count++; } } } doc.write(os); System.out.println("Replace " + count + " image(s)."); } finally { Cleaner.close(is); Cleaner.close(os); } } private static String addPictureData(String image, CustomXWPFDocument doc) throws FileNotFoundException, InvalidFormatException { InputStream images = null; try { images = new FileInputStream(image); return doc.addPictureData(images, XWPFDocument.PICTURE_TYPE_JPEG); } finally { Cleaner.close(images); } }
這裡是透過新增一筆在尾巴,接著刪除index 0那筆去做到類似替換的效果。但如果是文繞圖或特別調整的圖片,不僅僅只是讀取圖片大小,可能還要去取得設定的樣式做處理。如果之後有類似的需求我再研究並分享。
另外我繼承XWPFDocument類別去定義了CustomXWPFDocument,是由於XWPFDocument本身的createPicture存在bug,會造成輸出的Word無法正常開啟。
import java.io.IOException; import java.io.InputStream; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlToken; import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; public class CustomXWPFDocument extends XWPFDocument { public CustomXWPFDocument() { super(); } public CustomXWPFDocument(OPCPackage opcPackage) throws IOException { super(opcPackage); } public CustomXWPFDocument(InputStream in) throws IOException { super(in); } public void createPicture(CTR ctr, String blipId,int id, long width, long height) { //inal int EMU = 9525; //width *= EMU; //height *= EMU; //String blipId = getAllPictures().get(id).getPackageRelationship().getId(); CTInline inline = ctr.addNewDrawing().addNewInline(); String picXml = "" + "<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=\"" + blipId + "\" 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>"; //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData(); XmlToken xmlToken = null; try { xmlToken = XmlToken.Factory.parse(picXml); } catch(XmlException xe) { xe.printStackTrace(); } inline.set(xmlToken); //graphicData.set(xmlToken); inline.setDistT(0); inline.setDistB(0); inline.setDistL(0); inline.setDistR(0); CTPositiveSize2D extent = inline.addNewExtent(); extent.setCx(width); extent.setCy(height); CTNonVisualDrawingProps docPr = inline.addNewDocPr(); docPr.setId(id); docPr.setName("Picture " + id); docPr.setDescr("Generated"); } public void createPicture(String blipId,int id, int width, int height) { createPicture(createParagraph().createRun().getCTR(), blipId, id, width, height); } }
友藏內心獨白: 熬夜好幾天非常累,偷懶減少對code的說明。
留言
張貼留言