如何将水印添加到已经有标题的docx文件中。
所有示例代码都展示了如何使用空标题添加到文档中,但是如果文档已经有一个,代码将失败。
主要问题是在XWPFHeaderFoterPolicy. createHeader(…)中,因为如果存在标题,它会忽略调用,因此不会添加带有水印信息的段落。
public XWPFHeader createHeader(Enum type, XWPFParagraph[] pars) {
XWPFHeader header = getHeader(type);
if (header == null) {
HdrDocument hdrDoc = HdrDocument.Factory.newInstance();
XWPFRelation relation = XWPFRelation.HEADER;
int i = getRelationIndex(relation);
XWPFHeader wrapper = (XWPFHeader) doc.createRelationship(relation,
XWPFFactory.getInstance(), i);
wrapper.setXWPFDocument(doc);
CTHdrFtr hdr = buildHdr(type, wrapper, pars);
wrapper.setHeaderFooter(hdr);
hdrDoc.setHdr(hdr);
assignHeader(wrapper, type);
header = wrapper;
}
return header;
}
当createWatermark调用该方法时,它只是输入和输出什么都不做。
我没有找到同样的方法。我该如何纠正这一点?
XWPFHeaderFoterPolicy. createHeader
仅用于创建新标头。如果标头已经存在,则这些标头中不会更改任何内容。
如果您查看XWPFHeaderFoterPolicy
的源代码,就像您已经做过的那样,您将看到水印只是标题中段落中的WordArt形状。因此,您可以简单地在标题中已经存在的段落中创建这种WordArt形状。要做到这一点,请尝试理解XWPFHeaderFoterPolicy. getWatermark段落(String text,int idx)
并将其重写为setWatermarkIn段落(XWPF段落,String text)
。然后您可以在任何您想要的标题中获取或创建一个段落,并将水印放入该段落中。
以下完整示例显示了这一点。它使用apache poi 5.0.0
工作。使用apache poi 3.17
或apache poi 4.1.2
需要完成import
语句中注释的更改。
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import com.microsoft.schemas.office.office.*;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.openxmlformats.schemas.officeDocument.x2006.sharedTypes.STTrueFalse; // apache ppi 5.0.0
//import com.microsoft.schemas.vml.STTrueFalse; // apache poi 3.17 and apache poi 4.1.2
public class CreateWordHeaderWatermarkInExistingDocument {
private static void setWatermarkInParagraph(XWPFParagraph paragraph, String text) {
//CTP p = CTP.Factory.newInstance();
CTP p = paragraph.getCTP();
XWPFDocument doc = paragraph.getDocument();
CTBody ctBody = doc.getDocument().getBody();
byte[] rsidr = null;
byte[] rsidrdefault = null;
if (ctBody.sizeOfPArray() == 0) {
// TODO generate rsidr and rsidrdefault
} else {
CTP ctp = ctBody.getPArray(0);
rsidr = ctp.getRsidR();
rsidrdefault = ctp.getRsidRDefault();
}
p.setRsidP(rsidr);
p.setRsidRDefault(rsidrdefault);
CTPPr pPr = p.getPPr(); if (pPr == null) pPr = p.addNewPPr();
CTString pStyle = pPr.getPStyle(); if (pStyle == null) pStyle = pPr.addNewPStyle();
pStyle.setVal("Header");
// start watermark paragraph
CTR r = p.addNewR();
CTRPr rPr = r.addNewRPr();
rPr.addNewNoProof();
int idx = 1;
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("position:absolute;margin-left:0;margin-top:0;width:415pt;height:207.5pt;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");
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("#d8d8d8");
shape.setStyle(shape.getStyle() + ";rotation:315");
shape.setStroked(STTrueFalse.FALSE);
CTTextPath shapeTextPath = shape.addNewTextpath();
shapeTextPath.setStyle("font-family:"Cambria";font-size:1pt");
shapeTextPath.setString(text);
pict.set(group);
}
public static void main(String[] args) throws Exception {
//XWPFDocument doc= new XWPFDocument();
XWPFDocument doc= new XWPFDocument(new FileInputStream("./WordDocument.docx"));
// the body content
XWPFParagraph paragraph = doc.createParagraph();
XWPFRun run=paragraph.createRun();
run.setText("New text in body.");
// get or create the default header
XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
// get or create first paragraph in first header
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
// set watermark to that paragraph
setWatermarkInParagraph(paragraph, "Watermark default");
header = doc.createHeader(HeaderFooterType.EVEN);
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
setWatermarkInParagraph(paragraph, "Watermark even");
header = doc.createHeader(HeaderFooterType.FIRST);
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
setWatermarkInParagraph(paragraph, "Watermark first");
FileOutputStream out = new FileOutputStream("./WordDocumentWithWatermark.docx");
doc.write(out);
out.close();
doc.close();
}
}
基于Axel的出色回答,我编写了这段代码:
public DocumentTools addWatermark(String watermark) throws IOException {
addWatermark(watermark, "#d8d8d8", 315, HeaderFooterType.DEFAULT);
return this;
}
public DocumentTools addWatermark(String watermark, String color, float rotation, HeaderFooterType... hft) throws IOException {
if (hft.length == 0) {
hft = new HeaderFooterType[1];
hft[0] = HeaderFooterType.DEFAULT;
}
for (HeaderFooterType headerFooterType : hft) {
// get or create the default header
XWPFHeader header = doc.createHeader(headerFooterType);
// get or create first paragraph in first header
XWPFParagraph paragraph = header.getParagraphArray(0);
if (paragraph == null) {
paragraph = header.createParagraph();
}
// set watermark to that paragraph
setWatermarkInParagraph(paragraph, watermark, color, rotation);
}
return this;
}
//=====================================================
// Axel code with a minimal fix for color and rotation parameters.
//=====================================================
private static void setWatermarkInParagraph(XWPFParagraph paragraph, String text, String color, float rotation) {
//CTP p = CTP.Factory.newInstance();
CTP p = paragraph.getCTP();
XWPFDocument doc = paragraph.getDocument();
CTBody ctBody = doc.getDocument().getBody();
byte[] rsidr = null;
byte[] rsidrdefault = null;
if (ctBody.sizeOfPArray() == 0) {
// TODO generate rsidr and rsidrdefault
} else {
CTP ctp = ctBody.getPArray(0);
rsidr = ctp.getRsidR();
rsidrdefault = ctp.getRsidRDefault();
}
p.setRsidP(rsidr);
p.setRsidRDefault(rsidrdefault);
CTPPr pPr = p.getPPr();
if (pPr == null) {
pPr = p.addNewPPr();
}
CTString pStyle = pPr.getPStyle();
if (pStyle == null) {
pStyle = pPr.addNewPStyle();
}
pStyle.setVal("Header");
// start watermark paragraph
CTR r = p.addNewR();
CTRPr rPr = r.addNewRPr();
rPr.addNewNoProof();
int idx = 1;
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("position:absolute;margin-left:0;margin-top:0;width:415pt;height:207.5pt;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");
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(color);
shape.setStyle(shape.getStyle() + ";rotation:"+rotation);
shape.setStroked(STTrueFalse.FALSE);
CTTextPath shapeTextPath = shape.addNewTextpath();
shapeTextPath.setStyle("font-family:"Cambria";font-size:1pt");
shapeTextPath.setString(text);
pict.set(group);
}