Apache POI XWPF adding shapes to header

2019-01-29 10:58发布

问题:

I'm trying to add some shapes and a logo-file into the header of my word docx document. Adding a picture works for me, but i didn't find any solution how to add a shape. can anyone help me?

String imgFile="logo.png";

XWPFDocument document = new XWPFDocument(new FileInputStream("myfile.docx"));

CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();

XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document, sectPr);               
XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);

XWPFParagraph paragraph = header.getParagraphArray(0);
paragraph.setAlignment(ParagraphAlignment.CENTER);

XWPFRun run = paragraph.createRun();
XWPFPicture picture = run.addPicture(new FileInputStream(imgFile), XWPFDocument.PICTURE_TYPE_PNG, imgFile, Units.toEMU(195), Units.toEMU(22));

String blipID = "";
for(XWPFPictureData picturedata : header.getAllPackagePictures()) {
  blipID = header.getRelationId(picturedata);
}
picture.getCTPicture().getBlipFill().getBlip().setEmbed(blipID); //now they have a blipID too

At the end the header should look like this

thanks

回答1:

Since the apache poi XWPF is really in beta state until now, such things are only possible if one knows exactly how Word will store it's contents into the XML. Then one can work around the inadequacies of apache poi XWPF. You have already used such a workaround which corrects the missed blipID when pictures are added to runs in header or footer.

To discover how Word will store it's contents into the XML is not rocket science. A *.docx file is simply a ZIP file. If one unzip this file using a Zip software, one can simply have a look into the XML files.

As far as I know adding shapes (in this case text boxes) in Word documents is not supported by apache poi directly. For this using the low level underlying objects (in this case CTGroupand CTShape) is needed.

Example: (code should be self explanatory)

import java.io.*;

import org.apache.poi.util.Units;

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

import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTxbxContent;

import com.microsoft.schemas.vml.CTGroup;
import com.microsoft.schemas.vml.CTShape;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTabStop;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTabJc;

import org.w3c.dom.Node;

import java.math.BigInteger;

public class CreateWordHeaderFooterTextBoxPicture {

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

  XWPFDocument doc= new XWPFDocument();

  // the body content
  XWPFParagraph paragraph = doc.createParagraph();
  XWPFRun run=paragraph.createRun();  
  run.setText("The Body:");

  paragraph = doc.createParagraph();
  run=paragraph.createRun();  
  run.setText("Lorem ipsum....");

  // create header start
  XWPFHeaderFooterPolicy headerFooterPolicy = doc.createHeaderFooterPolicy();
  XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);

  // header's first paragraph
  paragraph = header.getParagraphArray(0);
  if (paragraph == null) paragraph = header.createParagraph();
  paragraph.setAlignment(ParagraphAlignment.LEFT);

  // create tab stops
  CTTabStop tabStop = paragraph.getCTP().getPPr().addNewTabs().addNewTab();
  tabStop.setVal(STTabJc.CENTER);
  int twipsPerInch =  1440;
  tabStop.setPos(BigInteger.valueOf(3 * twipsPerInch));

  tabStop = paragraph.getCTP().getPPr().getTabs().addNewTab();
  tabStop.setVal(STTabJc.RIGHT);
  twipsPerInch =  1440;
  tabStop.setPos(BigInteger.valueOf(6 * twipsPerInch));

  // first run in header's first paragraph, to be for first text box
  run = paragraph.createRun(); 

  // create inline text box in run
  CTGroup ctGroup = CTGroup.Factory.newInstance();

  CTShape ctShape = ctGroup.addNewShape();
  ctShape.setStyle("width:80pt;height:24pt");
  CTTxbxContent ctTxbxContent = ctShape.addNewTextbox().addNewTxbxContent();
  XWPFParagraph textboxparagraph = new XWPFParagraph(ctTxbxContent.addNewP(), (IBody)header);
  XWPFRun textboxrun = textboxparagraph.createRun();
  textboxrun.setText("The TextBox 1...");
  textboxrun.setFontSize(10);

  Node ctGroupNode = ctGroup.getDomNode(); 
  CTPicture ctPicture = CTPicture.Factory.parse(ctGroupNode);
  CTR cTR = run.getCTR();
  cTR.addNewPict();
  cTR.setPictArray(0, ctPicture);

  // add tab to run
  run.addTab();

  // second run in header's first paragraph, to be for logo picture
  run = paragraph.createRun();  

  // add the picture in the headers run
  String imgFile="Logo.png";
  XWPFPicture picture = run.addPicture(new FileInputStream(imgFile), XWPFDocument.PICTURE_TYPE_PNG, imgFile, Units.toEMU(195), Units.toEMU(22));

  String blipID = "";
  for(XWPFPictureData picturedata : header.getAllPackagePictures()) {
   blipID = header.getRelationId(picturedata);
  }
  picture.getCTPicture().getBlipFill().getBlip().setEmbed(blipID);

  // add tab to run
  run.addTab();

  // third run in header's first paragraph, to be for second text box
  run = paragraph.createRun();  

  // create inline text box in run
  ctGroup = CTGroup.Factory.newInstance();

  ctShape = ctGroup.addNewShape();
  ctShape.setStyle("width:80pt;height:24pt");
  ctTxbxContent = ctShape.addNewTextbox().addNewTxbxContent();
  textboxparagraph = new XWPFParagraph(ctTxbxContent.addNewP(), (IBody)header);
  textboxrun = textboxparagraph.createRun();
  textboxrun.setText("The TextBox 2...");
  textboxrun.setFontSize(10);

  ctGroupNode = ctGroup.getDomNode(); 
  ctPicture = CTPicture.Factory.parse(ctGroupNode);
  cTR = run.getCTR();
  cTR.addNewPict();
  cTR.setPictArray(0, ctPicture);

  // create header end


  // create footer start
  XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);

  paragraph = footer.getParagraphArray(0);
  if (paragraph == null) paragraph = header.createParagraph();
  paragraph.setAlignment(ParagraphAlignment.CENTER);

  run = paragraph.createRun();  
  run.setText("The Footer:");


  doc.write(new FileOutputStream("test.docx"));

 }
}