差異處
這裏顯示兩個版本的差異處。
下次修改 | 前次修改 | ||
java:apache_poi:word_imagesreplacement [2014/02/06 18:05] tony 建立 |
java:apache_poi:word_imagesreplacement [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 1: | 行 1: | ||
{{tag>java poi}} | {{tag>java poi}} | ||
====== Word - Images Replacement ====== | ====== Word - Images Replacement ====== | ||
- | 需求很單純,在我們有了自動抓圖程式後,接著就是要自動取代文件圖片了。經過研究一番,目前我只有辦法去取代Word 2007的圖片,2003還沒辦法。 | + | ===== Problem ===== |
+ | 需求很單純,在我們有了自動抓圖程式後,接著就是要自動取代文件圖片了。經過研究一番,目前我只有辦法去取代Word 2007的圖片,2003並沒找到相應的操作API。 | ||
===== How to? ===== | ===== How to? ===== | ||
+ | 在Word2007中,本文是使用XWPFDocument物件去操作,而XWPFDocument(本文)下包含了多個XWPFParagraph(段落)。XWPFParagraph包含多個XWPFRun(文字屬性描述區塊),XWPFRun則包含CTR(Run的描述屬性)。圖片相關物件可從CTR中取出來去操作。\\ | ||
+ | \\ | ||
+ | 要達到需求,我們必須去loop本文內容,插入新圖片並刪除原本的圖片。我的範例僅僅將原本圖片大小讀出來,接著再把圖片依據這個大小插入到Word中。做法很直覺,廢話不多說,看code: | ||
+ | <file java TestWord2007.java> | ||
+ | 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); | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
+ | 這裡是透過新增一筆在尾巴,接著刪除index 0那筆去做到類似替換的效果。但如果是文繞圖或特別調整的圖片,不僅僅只是讀取圖片大小,可能還要去取得設定的樣式做處理。如果之後有類似的需求我再研究並分享。\\ | ||
+ | \\ | ||
+ | 另外我繼承XWPFDocument類別去定義了CustomXWPFDocument,是由於XWPFDocument本身的createPicture存在bug,會造成輸出的Word無法正常開啟。 | ||
+ | <file java CustomXWPFDocument.java> | ||
+ | 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); | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | 友藏內心獨白: 熬夜好幾天非常累,偷懶減少對code的說明。 | ||
+ | ===== Reference ===== | ||
+ | * [[http://blog.csdn.net/zhyh1986/article/details/8717585|在Word2007插入圖片後無法開啟檔案的Bug]] | ||
===== ===== | ===== ===== |