1
votes

enter image description here I want to add an image into docx , but I just found simple apache poi code:

 XWPFDocument document = new XWPFDocument()
        XWPFParagraph paragraph = document.createParagraph()
        XWPFRun run = paragraph.createRun()
        run.addPicture(new FileInputStream(img), format, img, Units.toEMU(width), Units.toEMU(height))
        FileOutputStream outputStream = new FileOutputStream(doc)
        document.write(outputStream)

Now I want to set the picture in front of text , but I can not found any reference.

1
That's a good question and it is interesting how difficult is to find any resources on internet related to this. I tried to search but have not found anything. XWPFRun seems to have only simple text formatting. The closest I found is this: stackoverflow.com/q/47673133/2886891 - but it is soooo an ugly solution :)Honza Zidek
@Honza Zidek: I am curious how a more less ugly solution would look like. Can we hope you will providing a such sooner or later?Axel Richter
@AxelRichter: Nope unless I need it for my project :) I am not blaming you for providing an ugly solution, I am blaming POI for not providing an API for achieving the same goal without need to hack the XML.Honza Zidek
@Honza Zidek: "without need to hack the XML": Well Office Open **XML** is the new file format for Microsoft Office. And answers here, at least my answers, are never thought to be ready-to-use productive code but to be minimal working examples showing the principles. Of course in productive code this should be done more flexible and less based on fixed XML strings. But, as said in my answer, when using class by class of org.openxmlformats.schemas.drawingml.x2006 you are probably coding page wise code. Not applicable for an answer here.Axel Richter

1 Answers

2
votes

The Office Open XML formats and also *.docx as such are ZIP archives containing XML files and other files in a directory structure. So if we are curious we can simple unzip them and taking a look into.

Using the default code for adding a picture to a text run in /word/document.xml we find something like:

<w:r>
 <w:t>Picture inline with text:</w:t>
 <w:drawing>
  <wp:inline distT="0" distR="0" distB="0" distL="0">
   <wp:extent cx="1905000" cy="254000"/>
   <wp:docPr id="0" name="Drawing 0" descr="samplePict.jpeg"/>
   <a:graphic>
    <a:graphicData ...

If we are opening this usig Word and changing the text wrap of the picture to behind text, then in /word/document.xml we find something like:

<w:r>
 <w:drawing>
  <wp:anchor allowOverlap="1" behindDoc="1" layoutInCell="1" locked="0" relativeHeight="0" simplePos="0">
   <wp:simplePos x="0" y="0"/>
   <wp:positionH relativeFrom="column"><wp:posOffset>0</wp:posOffset></wp:positionH>
   <wp:positionV relativeFrom="paragraph"><wp:posOffset>0</wp:posOffset></wp:positionV>
   <wp:extent cx="1905000" cy="508000"/>
   <wp:effectExtent b="0" l="0" r="0" t="0"/><wp:wrapNone/>
   <wp:docPr descr="samplePict.jpeg" id="1" name="Drawing 0"/><wp:cNvGraphicFramePr/>
   <a:graphic>
    <a:graphicData ...

As you see, the first is within an wp:inline element while the second is within an wp:anchor element.

Unfortunately the wp:anchor element cannot be applied using apache poi until now. So we need to know where to find the low level objects, apache poi bases on. I found http://grepcode.com a good reference.

Now we can coding the needed things based on those low level objects:

import java.io.*;

import org.apache.poi.xwpf.usermodel.*;

import org.apache.poi.util.Units;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;

public class CreateWordImagesBehindAndInFrontText {

 private static CTAnchor getAnchorWithGraphic(CTDrawing drawing /*inline drawing*/ , 
  String drawingDescr, boolean behind) throws Exception {

  CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
  long width = drawing.getInlineArray(0).getExtent().getCx();
  long height = drawing.getInlineArray(0).getExtent().getCy();

  String anchorXML = 
   "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
  +"simplePos=\"0\" relativeHeight=\"0\" behindDoc=\""+((behind)?1:0)+"\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
  +"<wp:simplePos x=\"0\" y=\"0\"/>"
  +"<wp:positionH relativeFrom=\"column\"><wp:posOffset>0</wp:posOffset></wp:positionH>"
  +"<wp:positionV relativeFrom=\"paragraph\"><wp:posOffset>0</wp:posOffset></wp:positionV>"
  +"<wp:extent cx=\""+width+"\" cy=\""+height+"\"/>"
  +"<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/><wp:wrapNone/>"
  +"<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\""+drawingDescr+"\"/><wp:cNvGraphicFramePr/>"
  +"</wp:anchor>";

  drawing = CTDrawing.Factory.parse(anchorXML);
  CTAnchor anchor = drawing.getAnchorArray(0);
  anchor.setGraphic(graphicalobject);
  return anchor;  
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument doc= new XWPFDocument();
  XWPFParagraph paragraph;
  XWPFRun run; 
  InputStream in;
  CTDrawing drawing;
  CTAnchor anchor;

  //default
  paragraph = doc.createParagraph();
  run = paragraph.createRun();
  run.setText("Picture inline with text:");
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(150), Units.toEMU(40));
  in.close();  

  paragraph = doc.createParagraph();

  //behind text
  paragraph = doc.createParagraph();
  run = paragraph.createRun();
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(150), Units.toEMU(40));
  in.close();  
  drawing = run.getCTR().getDrawingArray(0);

  anchor = getAnchorWithGraphic(drawing, "samplePict.jpeg", true /*behind text*/);

  drawing.setAnchorArray(new CTAnchor[]{anchor});
  drawing.removeInline(0);
  run = paragraph.createRun();
  run.setText("The above picture is behind the text. ");

  paragraph = doc.createParagraph();

  //in front of text
  paragraph = doc.createParagraph();
  run = paragraph.createRun();
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(150), Units.toEMU(40));
  in.close();  
  drawing = run.getCTR().getDrawingArray(0);

  anchor = getAnchorWithGraphic(drawing, "samplePict.jpeg", false /*not behind text*/);

  drawing.setAnchorArray(new CTAnchor[]{anchor});
  drawing.removeInline(0);
  run = paragraph.createRun();
  run.setText("The above picture is in front of the text. ");

  paragraph = doc.createParagraph();

  doc.write(new FileOutputStream("CreateWordImagesBehindAndInFrontText.docx"));
  doc.close();

 }
}