简体   繁体   English

如何使用apache poi在word文档中用占位符或某些图像替换图形?

[英]How to replace figure with placeholder or certain image in word document using apache poi,?

Let's assume i have a word document, with this body.假设我有一个带有这个正文的 word 文档。 Word document before replacing images替换图像前的 Word 文档

    private void findImages(XWPFParagraph p) {
    for (XWPFRun r : p.getRuns()) {
        for (XWPFPicture pic : r.getEmbeddedPictures()) {
            XWPFPicture picture = pic;
                XWPFPictureData source = picture.getPictureData();
                BufferedImage qrCodeImage = printVersionService.generateQRCodeImage("JASAW EMA WWS");
                File imageFile = new File("image.jpg");
                try {
                    ImageIO.write(qrCodeImage, "jpg", imageFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try ( FileInputStream in = new FileInputStream(imageFile);
                      OutputStream out = source.getPackagePart().getOutputStream();
                ) {
                    byte[] buffer = new byte[2048];
                    int length;
                    while ((length = in.read(buffer)) > 0) {
                        out.write(buffer, 0, length);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
        }
     }
}

So this code replaces any image with QR code.所以这个代码用二维码替换任何图像。

But I have one trouble.但我有一个麻烦。

Word Document after replacing替换后的Word文档

So my question is?所以我的问题是? How can I replace only the image i chose or how can i replace inserted figure with text with image generated by my own function?如何仅替换我选择的图像,或者如何用我自己的函数生成的图像将插入的图形替换为文本?

Detecting the picture and replacing the picture data will be the simplest.检测图片并替换图片数据将是最简单的。 In following answer I have shown how to detect and replace pictures by name: Java Apache POI: insert an image "infront the text" .在以下答案中,我展示了如何按名称检测和替换图片: Java Apache POI: insert an image "infront the text" If you do not know the name of the embedded picture, a picture also can be detected by alt text.如果您不知道嵌入图片的名称,也可以通过替换文字检测图片。 To edit the alt text of a picture, open the context menu by right mouse click on the picture and choose Edit A̲lt Text from that context menu.要编辑图片的替代文本,请在图片上单击鼠标右键打开上下文菜单,然后从该上下文菜单中选择编辑 A̲lt 文本

In How to read alt text of image in word document apache.poi I have shown already how to read alt text of image.如何读取 word 文档 apache.poi 中图像的替代文本中,我已经展示了如何读取图像的替代文本。

So code could look like:所以代码可能如下所示:

import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;

public class WordReplacePictureData {
    
 static org.apache.xmlbeans.XmlObject getInlineOrAnchor(org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture ctPictureToFind, org.apache.xmlbeans.XmlObject inlineOrAnchor) {
  String declareNameSpaces = "declare namespace pic='http://schemas.openxmlformats.org/drawingml/2006/picture'; ";
  org.apache.xmlbeans.XmlObject[] selectedObjects = inlineOrAnchor.selectPath(
   declareNameSpaces 
   + "$this//pic:pic");
  for (org.apache.xmlbeans.XmlObject selectedObject : selectedObjects) {
   if (selectedObject instanceof org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) {
    org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture ctPicture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture)selectedObject;
    if (ctPictureToFind.equals(ctPicture)) {
     // this is the inlineOrAnchor for that picture   
     return inlineOrAnchor;
    }        
   }          
  }
  return null;
 }
                
 static org.apache.xmlbeans.XmlObject getInlineOrAnchor(XWPFRun run, XWPFPicture picture) {
  org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture ctPictureToFind = picture.getCTPicture();
  for (org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing drawing : run.getCTR().getDrawingList()) {
   for (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline inline : drawing.getInlineList()) {
    org.apache.xmlbeans.XmlObject inlineOrAnchor = getInlineOrAnchor(ctPictureToFind, inline);
    // if inlineOrAnchor is not null, then this is the inline for that picture
    if (inlineOrAnchor != null) return inlineOrAnchor;
   }
   for (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor anchor : drawing.getAnchorList()) {
    org.apache.xmlbeans.XmlObject inlineOrAnchor = getInlineOrAnchor(ctPictureToFind, anchor);
    // if inlineOrAnchor is not null, then this is the anchor for that picture
    if (inlineOrAnchor != null) return inlineOrAnchor;
   }
  }
  return null;
 }

 static org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps getNonVisualDrawingProps(org.apache.xmlbeans.XmlObject inlineOrAnchor) {
  if (inlineOrAnchor == null) return null;
  if (inlineOrAnchor instanceof org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline) {
   org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline inline = (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline)inlineOrAnchor;
   return inline.getDocPr();    
  } else if (inlineOrAnchor instanceof org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor) {
   org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor anchor = (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor)inlineOrAnchor;
   return anchor.getDocPr();
  }
  return null;
 }

 static String getSummary(org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps nonVisualDrawingProps) {
  if (nonVisualDrawingProps == null) return "";
  String summary = "Id:=" + nonVisualDrawingProps.getId();
  summary += " Name:=" + nonVisualDrawingProps.getName();
  summary += " Title:=" + nonVisualDrawingProps.getTitle();
  summary += " Descr:=" + nonVisualDrawingProps.getDescr();
  return summary;
 }
    
 static XWPFPicture getPictureByAltText(XWPFRun run, String altText) {
  if (altText == null) return null;
  for (XWPFPicture picture : run.getEmbeddedPictures()) {
   String altTextSummary = getSummary(getNonVisualDrawingProps(getInlineOrAnchor(run, picture)));
   System.out.println(altTextSummary);
   if (altTextSummary.contains(altText)) {
    return picture;   
   }
  }
  return null;
 }
 
 static void replacePictureData(XWPFPictureData source, String pictureResultPath) {
  try ( FileInputStream in = new FileInputStream(pictureResultPath); 
        OutputStream out = source.getPackagePart().getOutputStream();
       ) {
   byte[] buffer = new byte[2048];
   int length;
   while ((length = in.read(buffer)) > 0) {
    out.write(buffer, 0, length);
   }
  } catch (Exception ex) {
   ex.printStackTrace();  
  }
 }
 
 static void replacePicture(XWPFRun run, String altText, String pictureResultPath) {
  XWPFPicture picture = getPictureByAltText(run, altText);
  if (picture != null) {
   XWPFPictureData source = picture.getPictureData();
   replacePictureData(source, pictureResultPath);
  }   
 }

 public static void main(String[] args) throws Exception {
  String templatePath = "./source.docx";
  String resultPath = "./result.docx";
  String altText = "Placeholder QR-Code";
  String pictureResultPath = "./QR.jpg";
  
  try ( XWPFDocument document = new XWPFDocument(new FileInputStream(templatePath));
        FileOutputStream out = new FileOutputStream(resultPath);
       ) {
   
   for (IBodyElement bodyElement : document.getBodyElements()) {
    if (bodyElement instanceof XWPFParagraph) {
     XWPFParagraph paragraph = (XWPFParagraph)bodyElement;
     for (XWPFRun run : paragraph.getRuns()) {
      replacePicture(run, altText, pictureResultPath);
     }
    }
   }       
   document.write(out);
  }    
 }
}

This replaces the picture or pictures having alt text "Placeholder QR-Code".这将替换具有替代文字“Placeholder QR-Code”的图片或图片。 All other pictures remain as they are.所有其他图片保持原样。

Replacing shapes with pictures is very laborious as shapes are stored in alternate content elements (to choice shape and fallback) and so the shape needs to be changed as well as the fallback.用图片替换形状非常费力,因为形状存储在备用内容元素中(用于选择形状和后备),因此需要更改形状以及后备。 If one would let the fallback untouched, then applications which rely on that fallback will further show the old shape.如果人们不改变后备,那么依赖于该后备的应用程序将进一步显示旧的形状。 Furthermore detecting shapes by text box content is not really much simpler than detecting pictures by alt text content.此外,通过文本框内容检测形状并不比通过替代文本内容检测图片简单得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM