差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

Both sides previous revision 前次修改
下次修改
前次修改
java:apache_poi:word_imagesreplacement [2014/02/06 18:09]
tony [Word - Images Replacement]
java:apache_poi:word_imagesreplacement [2023/06/25 09:48] (目前版本)
行 2: 行 2:
 ====== Word - Images Replacement ====== ====== Word - Images Replacement ======
 ===== Problem ===== ===== Problem =====
-需求很單純,在我們有了自動抓圖程式後,接著就是要自動取代文件圖片了。經過研究一番,目前我只有辦法去取代Word 2007的圖片,2003辦法+需求很單純,在我們有了自動抓圖程式後,接著就是要自動取代文件圖片了。經過研究一番,目前我只有辦法去取代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]]
  
 =====    ===== =====    =====