Add watermark in word document using Apache POI

2019-07-23 02:55发布

问题:

I want to add text watermark in word document using Apache POI.

I have used headerFooterPolicy.createWatermark("Watermark"); but diagonal grayed text isn't displayed.

回答1:

The private XWPFParagraph getWatermarkParagraph(String text, int idx) is simply not finished until now. You can waiting until it gets ready or manipulating it using the low level objects after the default was created.

The needed settings are in CTShape.

Example:

import java.io.*;

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

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

public class CreateWordHeaderFooterWatermark {

 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:");

  // create header-footer
  XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
  if (headerFooterPolicy == null) headerFooterPolicy = doc.createHeaderFooterPolicy();

  // create default Watermark - fill color black and not rotated
  headerFooterPolicy.createWatermark("Watermark");

  // get the default header
  // Note: createWatermark also sets FIRST and EVEN headers 
  // but this code does not updating those other headers
  XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);
  paragraph = header.getParagraphArray(0);

  // get com.microsoft.schemas.vml.CTShape where fill color and rotation is set
  org.apache.xmlbeans.XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(
    new javax.xml.namespace.QName("urn:schemas-microsoft-com:vml", "shape"));

  if (xmlobjects.length > 0) {
   com.microsoft.schemas.vml.CTShape ctshape = (com.microsoft.schemas.vml.CTShape)xmlobjects[0];
   // set fill color
   ctshape.setFillcolor("#d8d8d8");
   // set rotation
   ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
   //System.out.println(ctshape);
  }

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

 }
}


回答2:

import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.office.office.STConnectType;
import com.microsoft.schemas.vml.CTFormulas;
import com.microsoft.schemas.vml.CTGroup;
import com.microsoft.schemas.vml.CTH;
import com.microsoft.schemas.vml.CTHandles;
import com.microsoft.schemas.vml.CTPath;
import com.microsoft.schemas.vml.CTShape;
import com.microsoft.schemas.vml.CTShapetype;
import com.microsoft.schemas.vml.CTTextPath;
import com.microsoft.schemas.vml.STExt;
import com.microsoft.schemas.vml.STTrueFalse;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;

public class MYXWPFHeaderFooterPolicy extends XWPFHeaderFooterPolicy {

    XWPFDocument doc;

    public MYXWPFHeaderFooterPolicy(XWPFDocument doc, CTSectPr sectPr) {
        super(doc, sectPr);
        this.doc = doc;
    }

    @Override
    public void createWatermark(String text) {
        XWPFParagraph[] pars = new XWPFParagraph[1];
        pars[0] = getWatermarkParagraph(text, 1);
        createHeader(DEFAULT, pars);
        pars[0] = getWatermarkParagraph(text, 2);
        createHeader(FIRST, pars);
        pars[0] = getWatermarkParagraph(text, 3);
        createHeader(EVEN, pars);
    }

    /*
     * This is the default Watermark paragraph; the only variable is the text message
     * TODO: manage all the other variables
     */
    private XWPFParagraph getWatermarkParagraph(String text, int idx) {
        CTP p = CTP.Factory.newInstance();
        byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
        byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
        p.setRsidP(rsidr);
        p.setRsidRDefault(rsidrdefault);
        CTPPr pPr = p.addNewPPr();
        pPr.addNewPStyle().setVal("Header");
        // start watermark paragraph
        CTR r = p.addNewR();
        CTRPr rPr = r.addNewRPr();
        rPr.addNewNoProof();
        CTPicture pict = r.addNewPict();
        CTGroup group = CTGroup.Factory.newInstance();
        CTShapetype shapetype = group.addNewShapetype();
        shapetype.setId("_x0000_t136");
        shapetype.setCoordsize("1600,21600");
        shapetype.setSpt(136);
        shapetype.setAdj("10800");
        shapetype.setPath2("m@7,0l@8,0m@5,21600l@6,21600e");
        CTFormulas formulas = shapetype.addNewFormulas();
        formulas.addNewF().setEqn("sum #0 0 10800");
        formulas.addNewF().setEqn("prod #0 2 1");
        formulas.addNewF().setEqn("sum 21600 0 @1");
        formulas.addNewF().setEqn("sum 0 0 @2");
        formulas.addNewF().setEqn("sum 21600 0 @3");
        formulas.addNewF().setEqn("if @0 @3 0");
        formulas.addNewF().setEqn("if @0 21600 @1");
        formulas.addNewF().setEqn("if @0 0 @2");
        formulas.addNewF().setEqn("if @0 @4 21600");
        formulas.addNewF().setEqn("mid @5 @6");
        formulas.addNewF().setEqn("mid @8 @5");
        formulas.addNewF().setEqn("mid @7 @8");
        formulas.addNewF().setEqn("mid @6 @7");
        formulas.addNewF().setEqn("sum @6 0 @5");
        CTPath path = shapetype.addNewPath();
        path.setTextpathok(STTrueFalse.T);
        path.setConnecttype(STConnectType.CUSTOM);
        path.setConnectlocs("@9,0;@10,10800;@11,21600;@12,10800");
        path.setConnectangles("270,180,90,0");
        CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
        shapeTypeTextPath.setOn(STTrueFalse.T);
        shapeTypeTextPath.setFitshape(STTrueFalse.T);
        CTHandles handles = shapetype.addNewHandles();
        CTH h = handles.addNewH();
        h.setPosition("#0,bottomRight");
        h.setXrange("6629,14971");
        CTLock lock = shapetype.addNewLock();
        lock.setExt(STExt.EDIT);
        CTShape shape = group.addNewShape();
        shape.setId("PowerPlusWaterMarkObject" + idx);
        shape.setSpid("_x0000_s102" + (4 + idx));
        shape.setType("#_x0000_t136");
        shape.setStyle("opacity: 0.5;position:absolute;margin-left:0;margin-top:0;width:415pt;height:207.5pt;rotation:315;z-index:-251654144;mso-wrap-edited:f;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin;rotation:315");
        shape.setWrapcoords("616 5068 390 16297 39 16921 -39 17155 7265 17545 7186 17467 -39 17467 18904 17467 10507 17467 8710 17545 18904 17077 18787 16843 18358 16297 18279 12554 19178 12476 20701 11774 20779 11228 21131 10059 21248 8811 21248 7563 20975 6316 20935 5380 19490 5146 14022 5068 2616 5068");
        shape.setFillcolor("#F8F8F8");
        shape.setStroked(STTrueFalse.FALSE);
        CTTextPath shapeTextPath = shape.addNewTextpath();
        shapeTextPath.setStyle("font-family:"Cambria";font-size:1pt");
        shapeTextPath.setString(text);
        pict.set(group);
        // end watermark paragraph
        return new XWPFParagraph(p, doc);
    }

}


回答3:

I used the example above :

import java.io.*;

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

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

public class CreateWordHeaderFooterWatermark {

 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:");

  // create header-footer
  XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
  if (headerFooterPolicy == null) headerFooterPolicy = doc.createHeaderFooterPolicy();

  // create default Watermark - fill color black and not rotated
  headerFooterPolicy.createWatermark("Watermark");

  // get the default header
  // Note: createWatermark also sets FIRST and EVEN headers 
  // but this code does not updating those other headers
  XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);
  paragraph = header.getParagraphArray(0);

  // get com.microsoft.schemas.vml.CTShape where fill color and rotation is set
  org.apache.xmlbeans.XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(
    new javax.xml.namespace.QName("urn:schemas-microsoft-com:vml", "shape"));

  if (xmlobjects.length > 0) {
   com.microsoft.schemas.vml.CTShape ctshape = (com.microsoft.schemas.vml.CTShape)xmlobjects[0];
   // set fill color
   ctshape.setFillcolor("#d8d8d8");
   // set rotation
   ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
   //System.out.println(ctshape);
  }

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

 }
}

But if your version of Apache-POI use the function :

XWPFHeader getHeader(int pageNumber)

You can't use the enumeration XWPFHeaderFooterPolicy.DEFAULT in

XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);

So you need to replace this function with

XWPFHeader header = headerFooterPolicy.getDefaultHeader();