java实现加水印功能

1-Word加水印

在这里插入图片描述
在这里插入图片描述
实现原理:
● 通过页眉页脚生成文字水印或图片水印,然后设置页眉页脚的高度以及旋转角度来设置水印。

源代码:
1、引入pom依赖

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.14</version>
</dependency>

<dependency>
	<groupId>com.luhuiguo</groupId>
	<artifactId>aspose-words</artifactId>
	<version>22.4</version>
	<type>pom</type>
</dependency>

2、重写apache中的XWPFHeaderFooterPolicy类。
● 注意:包名为org.apache.poi.xwpf.model

package org.apache.poi.xwpf.model;
/**
 * Created at 2023年9月10日
 * Created by Alexander
 */

import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.office.office.STConnectType;
import com.microsoft.schemas.vml.*;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLDocumentPart.RelationPart;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.HdrDocument.Factory;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr.Enum;

import java.util.Iterator;
import java.util.Map;

/**
 * <p>Author: Alexander的搬砖工地</p>
 * <p>Date: 2023年9月15日</p>
 */
public class XWPFHeaderFooterPolicy {
	public static final Enum DEFAULT;
	public static final Enum EVEN;
	public static final Enum FIRST;
	private XWPFDocument doc;
	private XWPFHeader firstPageHeader;
	private XWPFFooter firstPageFooter;
	private XWPFHeader evenPageHeader;
	private XWPFFooter evenPageFooter;
	private XWPFHeader defaultHeader;
	private XWPFFooter defaultFooter;

	public XWPFHeaderFooterPolicy(XWPFDocument doc) {
		this(doc, (CTSectPr) null);
	}

	public XWPFHeaderFooterPolicy(XWPFDocument doc, CTSectPr sectPr) {
		if (sectPr == null) {
			CTBody i = doc.getDocument().getBody();
			sectPr = i.isSetSectPr() ? i.getSectPr() : i.addNewSectPr();
		}

		this.doc = doc;

		CTHdrFtrRef ref;
		org.apache.poi.POIXMLDocumentPart relatedPart;
		Enum type;
		int var11;
		for (var11 = 0; var11 < sectPr.sizeOfHeaderReferenceArray(); ++var11) {
			ref = sectPr.getHeaderReferenceArray(var11);
			relatedPart = doc.getRelationById(ref.getId());
			XWPFHeader ftr = null;
			if (relatedPart != null && relatedPart instanceof XWPFHeader) {
				ftr = (XWPFHeader) relatedPart;
			}

			try {
				type = ref.getType();
			} catch (XmlValueOutOfRangeException var10) {
				type = STHdrFtr.DEFAULT;
			}

			this.assignHeader(ftr, type);
		}

		for (var11 = 0; var11 < sectPr.sizeOfFooterReferenceArray(); ++var11) {
			ref = sectPr.getFooterReferenceArray(var11);
			relatedPart = doc.getRelationById(ref.getId());
			XWPFFooter var12 = null;
			if (relatedPart != null && relatedPart instanceof XWPFFooter) {
				var12 = (XWPFFooter) relatedPart;
			}

			try {
				type = ref.getType();
			} catch (XmlValueOutOfRangeException var9) {
					 type = STHdrFtr.DEFAULT;
					 }

					 this.assignFooter(var12, type);
					 }

					 }

					 private void assignFooter(XWPFFooter ftr, Enum type) {
					 if (type == STHdrFtr.FIRST) {
					 this.firstPageFooter = ftr;
					 } else if (type == STHdrFtr.EVEN) {
					 this.evenPageFooter = ftr;
					 } else {
					 this.defaultFooter = ftr;
					 }

					 }

					 private void assignHeader(XWPFHeader hdr, Enum type) {
					 if (type == STHdrFtr.FIRST) {
					 this.firstPageHeader = hdr;
					 } else if (type == STHdrFtr.EVEN) {
					 this.evenPageHeader = hdr;
					 } else {
					 this.defaultHeader = hdr;
					 }

					 }

					 public XWPFHeader createHeader(Enum type) {
					 return this.createHeader(type, (XWPFParagraph[]) null);
					 }

					 public XWPFHeader createHeader(Enum type, XWPFParagraph[] pars) {
					 XWPFHeader header = this.getHeader(type);
					 //存在hdader则覆盖
					 //	        if(header == null) {
					 HdrDocument hdrDoc = Factory.newInstance();
					 XWPFRelation relation = XWPFRelation.HEADER;
					 int i = this.getRelationIndex(relation);
					 XWPFHeader wrapper = (XWPFHeader) this.doc.createRelationship(relation, XWPFFactory.getInstance(), i);
					 wrapper.setXWPFDocument(this.doc);
					 CTHdrFtr hdr = this.buildHdr(type, wrapper, pars);
					 wrapper.setHeaderFooter(hdr);
					 hdrDoc.setHdr(hdr);
					 this.assignHeader(wrapper, type);
					 header = wrapper;
					 //	        }

					 return header;
					 }

					 public XWPFFooter createFooter(Enum type) {
					 return this.createFooter(type, (XWPFParagraph[]) null);
					 }

					 public XWPFFooter createFooter(Enum type, XWPFParagraph[] pars) {
					 XWPFFooter footer = this.getFooter(type);
					 //	        if (footer == null) {
					 FtrDocument ftrDoc = (FtrDocument) FtrDocument.Factory.newInstance();
					 XWPFRelation relation = XWPFRelation.FOOTER;
					 int i = this.getRelationIndex(relation);
					 XWPFFooter wrapper = (XWPFFooter) this.doc.createRelationship(relation, XWPFFactory.getInstance(), i);
					 wrapper.setXWPFDocument(this.doc);
					 CTHdrFtr ftr = this.buildFtr(type, wrapper, pars);
					 wrapper.setHeaderFooter(ftr);
					 ftrDoc.setFtr(ftr);
					 this.assignFooter(wrapper, type);
					 footer = wrapper;
					 //	        }

					 return footer;
					 }

					 private int getRelationIndex(XWPFRelation relation) {
					 int i = 1;
					 Iterator var3 = this.doc.getRelationParts().iterator();

					 while (var3.hasNext()) {
					 RelationPart rp = (RelationPart) var3.next();
					 if (rp.getRelationship().getRelationshipType().equals(relation.getRelation())) {
					 ++i;
					 }
					 }

					 return i;
					 }

					 private CTHdrFtr buildFtr(Enum type, XWPFHeaderFooter wrapper, XWPFParagraph[] pars) {
					 CTHdrFtr ftr = this.buildHdrFtr(pars, wrapper);
					 this.setFooterReference(type, wrapper);
					 return ftr;
					 }

					 private CTHdrFtr buildHdr(Enum type, XWPFHeaderFooter wrapper, XWPFParagraph[] pars) {
					 CTHdrFtr hdr = this.buildHdrFtr(pars, wrapper);
					 this.setHeaderReference(type, wrapper);
					 return hdr;
					 }

					 private CTHdrFtr buildHdrFtr(XWPFParagraph[] paragraphs, XWPFHeaderFooter wrapper) {
					 CTHdrFtr ftr = wrapper._getHdrFtr();
					 if (paragraphs != null) {
					 for (int i = 0; i < paragraphs.length; ++i) {
					 ftr.addNewP();
					 ftr.setPArray(i, paragraphs[i].getCTP());
					 }
					 }

					 return ftr;
					 }

					 private void setFooterReference(Enum type, XWPFHeaderFooter wrapper) {
					 CTHdrFtrRef ref = this.doc.getDocument().getBody().getSectPr().addNewFooterReference();
					 ref.setType(type);
					 ref.setId(this.doc.getRelationId(wrapper));
					 }

					 private void setHeaderReference(Enum type, XWPFHeaderFooter wrapper) {
					 CTHdrFtrRef ref = this.doc.getDocument().getBody().isSetSectPr() ? this.doc.getDocument().getBody().getSectPr().addNewHeaderReference() : this.doc.getDocument().getBody().addNewSectPr().addNewHeaderReference();
					 ref.setType(type);
					 ref.setId(this.doc.getRelationId(wrapper));
					 }

					 public XWPFHeader getFirstPageHeader() {
					 return this.firstPageHeader;
					 }

					 public XWPFFooter getFirstPageFooter() {
					 return this.firstPageFooter;
					 }

					 public XWPFHeader getOddPageHeader() {
					 return this.defaultHeader;
					 }

					 public XWPFFooter getOddPageFooter() {
					 return this.defaultFooter;
					 }

					 public XWPFHeader getEvenPageHeader() {
					 return this.evenPageHeader;
					 }

					 public XWPFFooter getEvenPageFooter() {
					 return this.evenPageFooter;
					 }

					 public XWPFHeader getDefaultHeader() {
					 return this.defaultHeader;
					 }

					 public XWPFFooter getDefaultFooter() {
					 return this.defaultFooter;
					 }

					 public XWPFHeader getHeader(int pageNumber) {
					 return pageNumber == 1 && this.firstPageHeader != null ? this.firstPageHeader : (pageNumber % 2 == 0 && this.evenPageHeader != null ? this.evenPageHeader : this.defaultHeader);
					 }

					 public XWPFHeader getHeader(Enum type) {
					 return type == STHdrFtr.EVEN ? this.evenPageHeader : (type == STHdrFtr.FIRST ? this.firstPageHeader : this.defaultHeader);
					 }

					 public XWPFFooter getFooter(int pageNumber) {
					 return pageNumber == 1 && this.firstPageFooter != null ? this.firstPageFooter : (pageNumber % 2 == 0 && this.evenPageFooter != null ? this.evenPageFooter : this.defaultFooter);
					 }

					 public XWPFFooter getFooter(Enum type) {
					 return type == STHdrFtr.EVEN ? this.evenPageFooter : (type == STHdrFtr.FIRST ? this.firstPageFooter : this.defaultFooter);
					 }

					 public void createWatermark(String text,Map<String,Object> params) {
					 XWPFParagraph[] pars = new XWPFParagraph[]{this.getWatermarkParagraph(text, 1,params)};
					 this.createHeader(DEFAULT, pars);
					 pars[0] = this.getWatermarkParagraph(text, 2,params);
					 this.createHeader(FIRST, pars);
					 pars[0] = this.getWatermarkParagraph(text, 3,params);
					 this.createHeader(EVEN, pars);
					 }

					 /**
					 * 原方法备份
					 * @param text
					 * @param idx
					 * @return
					 */
					 private XWPFParagraph getWatermarkParagraph123(String text, int idx) {
					 CTP p = (CTP) CTP.Factory.newInstance();
					 byte[] rsidr = this.doc.getDocument().getBody().getPArray(0).getRsidR();
					 byte[] rsidrdefault = this.doc.getDocument().getBody().getPArray(0).getRsidRDefault();
					 p.setRsidP(rsidr);
					 p.setRsidRDefault(rsidrdefault);
					 CTPPr pPr = p.addNewPPr();
					 pPr.addNewPStyle().setVal("Header");
					 CTR r = p.addNewR();
					 CTRPr rPr = r.addNewRPr();
					 rPr.addNewNoProof();
					 CTPicture pict = r.addNewPict();
					 CTGroup group = (CTGroup) CTGroup.Factory.newInstance();
					 CTShapetype shapetype = group.addNewShapetype();
					 shapetype.setId("_x0000_t136");
					 shapetype.setCoordsize("1600,21600");
					 shapetype.setSpt(136.0F);
					 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:1;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("black");
					 shape.setStroked(STTrueFalse.FALSE);
					 CTTextPath shapeTextPath = shape.addNewTextpath();
					 shapeTextPath.setStyle("font-family:&quot;Cambria&quot;;font-size:1pt");
					 shapeTextPath.setString(text);
					 pict.set(group);
					 return new XWPFParagraph(p, this.doc);
					 }

					 /**
					 * 重写方法
					 * @param text
					 * @param idx
					 * @return
					 */
					 private XWPFParagraph getWatermarkParagraph(String text, int idx,Map<String,Object> params) {
					 CTP p = (CTP) CTP.Factory.newInstance();
					 byte[] rsidr = this.doc.getDocument().getBody().getPArray(0).getRsidR();
					 byte[] rsidrdefault = this.doc.getDocument().getBody().getPArray(0).getRsidRDefault();
					 p.setRsidP(rsidr);
					 p.setRsidRDefault(rsidrdefault);
					 CTPPr pPr = p.addNewPPr();
					 pPr.addNewPStyle().setVal("Header");
					 CTR r = p.addNewR();
					 if (idx == 1) {
					 //margin-left和margin-top调整位置,height 和width调整大小
					 setCTR(r, text, idx, "position:absolute;" +
					 "left:0pt;" +
					 "margin-left:35pt;" + // 左外边距
					 "margin-top:200pt;" + // 上边距
					 "mso-position-horizontal-relative:margin;" +
					 "mso-position-vertical-relative:margin;" +
					 "rotation:330.0" +//(360-30) +// 旋转角度
					 ";height:60pt;" + // 文字高度
					 "width:360pt;" + // 文字宽度
					 "mso-width-relative:page;" +
					 "mso-height-relative:page",params);

					 } else {
					 setCTR(r, text, idx, "position:absolute;left:0pt;mso-position-horizontal-relative:margin;mso-position-vertical-relative:margin;rotation:-2949120f;height:60pt;width:360pt;mso-width-relative:page;mso-height-relative:page",params);
					 }
					 return new XWPFParagraph(p, this.doc);
					 }

					 /**
					 * 添加水印
					 * @param r
					 * @param text
					 * @param idx
					 * @param style
					 */
					 private void setCTR(CTR r, String text, int idx, String style, Map<String,Object> params) {
					 CTRPr rPr = r.addNewRPr();
					 rPr.addNewNoProof();
					 CTPicture pict = r.addNewPict();
					 CTGroup group = (CTGroup) CTGroup.Factory.newInstance();
					 CTShapetype shapetype = group.addNewShapetype();
					 shapetype.setId("_x0000_t136");
					 shapetype.setCoordsize("1600,21600");
					 shapetype.setSpt(136.0F);// 水印内容框
					 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(style);
					 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("#CC00FF");
					 // 透明度
					 //        Double alpha1 = Double.parseDouble("0.5");
					 //        String alpha = Double.toString(alpha1*100000);
					 shape.setOpacity("50000");

					 shape.setStroked(STTrueFalse.FALSE);
					 CTTextPath shapeTextPath = shape.addNewTextpath();
					 shapeTextPath.setStyle("font-family:&quot;Cambria&quot;;font-size:1pt");
					 shapeTextPath.setString(text);
					 pict.set(group);
					 }

					 static {
					 DEFAULT = STHdrFtr.DEFAULT;
					 EVEN = STHdrFtr.EVEN;
					 FIRST = STHdrFtr.FIRST;
					 }
					 }

3、主类

public class WaterMarkUtils {
    private static String inputPath  = "F:/临时/测试2.docx";
    private static String inputPathToDocx  = "F:/临时/测试444.docx";
    private static String outPath  = "F:/临时/测试结果.docx";
    private static String markStr = "Garbage水印!";

    public static void main(String[] args) {
        Map<String, Object> params = new HashMap<>();
        String type = inputPath.substring((inputPath.lastIndexOf(".") + 1));
        if ("doc".equals(type)) {
            docToDocx(inputPath,inputPathToDocx);
            setWordWaterMark(inputPathToDocx,outPath,markStr,params);
        } else if ("docx".equals(type)) {
            setWordWaterMark(inputPath, outPath, markStr,params);
        } else {
            System.out.println("格式有误!");
        }
    }

    /**
     * doc文档转docx
     * @param inPath doc原文件路径
     * @param outPath 转为docx的路径
     */
    public static void docToDocx(String inPath, String outPath) {
        try {
            File file = new File(outPath);
            FileOutputStream os = new FileOutputStream(file);
            Document doc = new Document(inPath);
            doc.save(os, SaveFormat.DOCX);// 这里可以写你想要装换的类型:DOC, DOCX, PDF,HTML
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置水印
     * @param inputPath 输入的docx路径
     * @param outPath 文件保存路径
     * @param markStr 水印内容
     * @param params 其他参数(预留传入其他参数,如透明度、颜色等等)
     */
    public static void setWordWaterMark(String inputPath, String outPath, String markStr, Map<String,Object> params) {
        File inputFile = new File(inputPath);
        XWPFDocument doc = null;
        try {
            // 延迟解析比率
            ZipSecureFile.setMinInflateRatio(-1.0d);
            doc = new XWPFDocument(new FileInputStream(inputFile));
        } catch (FileNotFoundException e) {
            System.out.println( "源文件不存在");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println( "读取源文件IO异常");
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println( "不支持的文档格式");
            e.printStackTrace();
        }
        org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
        if (headerFooterPolicy == null) {
            headerFooterPolicy = doc.createHeaderFooterPolicy();
        }
        //添加水印
        headerFooterPolicy.createWatermark(markStr,params);
        File file = new File(outPath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                System.out.println( "创建输出文件失败");
                e.printStackTrace();
            }
        }
        OutputStream os = null;
        try {
            os = new FileOutputStream(outPath);
            doc.write(os);
        } catch (FileNotFoundException e) {
            System.out.println( "创建输出文件失败");
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println( "添加文档水印失败");
            e.printStackTrace();
        } finally {
               if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (doc != null) {
                    try {
                        doc.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    }
}

2-PPT加水印

在这里插入图片描述
1、导入依赖

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-scratchpad</artifactId>
	<version>4.1.2</version>
</dependency>

2、工具类
● 工具类中参数主要为水印内容、透明度、旋转角度。
● 如果需要其他参数,可直接改为map来传递参数去扩展。

package cn.end.less.utils;

import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.sl.usermodel.VerticalAlignment;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class PPTWatermarkUtil {

	public static void addWatermark(String path, String outpath, String watermarkText, float alpha, int rotation) throws Exception {
		// 读取PPT文件
		FileInputStream fis = new FileInputStream(path);
		HSLFSlideShow ppt = new HSLFSlideShow(fis);
		fis.close();

		// 添加水印
		for (HSLFSlide slide : ppt.getSlides()) {
			Dimension pageSize = slide.getSlideShow().getPageSize();
			Integer width = (int) pageSize.getWidth();
			Integer height = (int) pageSize.getHeight();
			// 在每张幻灯片上添加文本框
			HSLFTextBox textBox = slide.createTextBox();
			textBox.setAnchor(new java.awt.Rectangle(0, 0, width, height));// 设置文本框大小和位置
			textBox.setVerticalAlignment(VerticalAlignment.MIDDLE);// 设置文本框的文字上下左右居中

			// 在文本框中添加文本
			HSLFTextParagraph paragraph = textBox.getTextParagraphs().get(0);
			HSLFTextRun textRun = paragraph.getTextRuns().get(0);

			textRun.setText(watermarkText);// 水印内容
			textRun.setFontSize(48d);// 字体大小
			textRun.setFontColor(new Color(128, 128, 128, (int) (alpha * 255)));// 设置字体颜色
			textRun.setBold(true);// 粗体
			textRun.setItalic(true);// 斜体

			// 设置文本框的旋转角度
			Rectangle2D anchor = textBox.getAnchor();
			double centerX = anchor.getX() + anchor.getWidth() / 2;// 文本框中心点的位置
			double centerY = anchor.getY() + anchor.getHeight() / 2;
			textBox.setRotation(rotation);// 设置文本框旋转角度
			double newCenterX = textBox.getAnchor().getX() + textBox.getAnchor().getWidth() / 2;// 文本框中心点在幻灯片中心点的偏移量
			double newCenterY = textBox.getAnchor().getY() + textBox.getAnchor().getHeight() / 2;
			double dx = newCenterX - centerX;
			double dy = newCenterY - centerY;// 旋转后文本框中心点与旋转前中心点的偏移量
			textBox.setAnchor(new java.awt.Rectangle((int) (anchor.getX() - dx),
													 (int) (anchor.getX() - dy),
													 (int) anchor.getWidth(),
													 (int) anchor.getHeight()));
		}

		// 保存PPT文件
		FileOutputStream fos = new FileOutputStream(outpath);
		ppt.write(fos);
		fos.close();
	}
}

3、主程序

private static String path= "F:\\临时\\测试.pptx";
private static String outpath= "F:\\临时\\测试11.pptx";


public  static void main(String[] args) throws Exception {
	PPTWatermarkUtil.addWatermark(path, outpath, "我是水印啊", 0.5f, 360-30);
}

其他:
方式二+方式三

package cn.end.less.config;


import cn.end.less.utils.PPTWatermarkUtil;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.sl.usermodel.PictureData;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class PptWatermark {
    private static String path= "F:\\临时\\测试.ppt";
    private static String outpath= "F:\\临时\\测试结果.ppt";


    public  static void main(String[] args) throws Exception {
		// 方式二
        setPPTWaterMark(path,outpath,"我是水印啊");
		// 方式三
        test1();
    }


    public static void test1() throws Exception{
        // 读取PPT文件
        FileInputStream fis = new FileInputStream(path);
        HSLFSlideShow ppt = new HSLFSlideShow(fis);
        fis.close();

        // 添加水印
        for (HSLFSlide slide : ppt.getSlides()) {
            Dimension pageSize = slide.getSlideShow().getPageSize();
            Integer width = (int) pageSize.getWidth();
            Integer height = (int) pageSize.getHeight();

            // 在每张幻灯片上添加文本框
            HSLFTextBox textBox = slide.createTextBox();
            textBox.setRotation(360-45);// 设置文本框旋转角度
            textBox.setAnchor(new Rectangle(0, height/4,width , height));

            // 在文本框中添加文本
            HSLFTextRun textRun = textBox.getTextParagraphs().get(0).getTextRuns().get(0);
            textRun.setText("我是水印啊");
            textRun.setFontSize(48d);
            textRun.setFontColor(new Color(0,0,0,128));
            textRun.setBold(true);
            textRun.setItalic(true);
        }

        // 保存PPT文件
        FileOutputStream fos = new FileOutputStream(outpath);
        ppt.write(fos);
        fos.close();
    }

    /**
     * PPT设置图片水印
     */
    public static void setPPTWaterMark(String path, String targetpath, String markStr) {
        HSLFSlideShow slideShow = null;
        try {
            slideShow = new HSLFSlideShow(new FileInputStream(path));
        } catch (IOException e) {
            throw new RuntimeException("setPPTWaterMark fail:获取PPT文件失败");
        }
        ByteArrayOutputStream os = null;
        FileOutputStream out = null;
        try {
            //获取水印
            os = getImage(markStr);
            // 将水印图片添加到幻灯片中,返回的对象中包括了图片的元数据信息
            PictureData pictureData1 = slideShow.addPicture(os.toByteArray(), PictureData.PictureType.PNG);
            // 将水印图片添加到每一页幻灯片中
            for (HSLFSlide slide : slideShow.getSlides()) {
                HSLFPictureShape pictureShape = slide.createPicture(pictureData1);
                Dimension pageSize = slide.getSlideShow().getPageSize();
//                Rectangle2D anchor = pictureShape.getAnchor();// 锚点
                pictureShape.setAnchor(new Rectangle2D.Double(0, 0, pageSize.getWidth(), pageSize.getHeight()));//设置图片的位置和大小 方法
            }
            out = new FileOutputStream(targetpath);
            slideShow.write(out);
        } catch (IOException e) {
            throw new RuntimeException("添加水印文件异常:生成ppt水印文件失败");
        } finally {
            if (slideShow != null) {
                try {
                    slideShow.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 获取水印文字图片流
     */
    private static ByteArrayOutputStream getImage(String text) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            // 导出到字节流B
            BufferedImage image = createWaterMarkImageBig(text);
            ImageIO.write(image, "png", os);
        } catch (Exception e) {
//            log.error("getImage fail: 创建水印图片IO异常", e);
//            throw new Exception(ResultCode.FAILURE, "getImage fail: 创建水印图片IO异常");
        }
        return os;
    }

    /**
     * 根据文字生成水印图片(大号 平铺)
     */
    public static BufferedImage createWaterMarkImageBig(String text) {
        Integer width = 1000; // 水印宽度
        Integer height = 800; // 水印高度
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取bufferedImage对象
        Font font = new Font("宋体", Font.PLAIN, 70);
        Graphics2D g2d = image.createGraphics();
        image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g2d.dispose();
        g2d = image.createGraphics();
        //设置字体颜色和透明度
        g2d.setColor(new Color(0, 0, 0, 60));
        //设置字体
        g2d.setStroke(new BasicStroke(1));
        //设置字体类型  加粗 大小
        g2d.setFont(font);
        //设置倾斜度
        g2d.rotate(Math.toRadians(-30), (double) image.getWidth() / 2, (double) image.getHeight() / 2);
        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(text, context);
        double x = (width - bounds.getWidth()) / 2;
        double y = (height - bounds.getHeight()) / 2;
        double ascent = -bounds.getY();
        double baseY = y + ascent;
        //写入水印文字原定高度过小,所以累计写水印,增加高度
        g2d.drawString(text, (int) x, (int) baseY);
        //设置透明度
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        //释放对象
        g2d.dispose();
        return image;
    }

}

3-Excel加水印

在这里插入图片描述

实现原理:
● Excel水印只能通过生成图片,并将图片置于Excel底层。

代码
1、依赖

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.14</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>ooxml-schemas</artifactId>
	<version>1.4</version>
</dependency>

2、工具类

package cn.end.less.utils;

import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

import static java.awt.image.BufferedImage.TYPE_INT_ARGB;

/**
 * @author Alexander
 * @date 2023/9/7 17:02:44
 */
public class ExcelUtil {
    /**
     * 
     * @param inputPath 输入路径
     * @param outputPath 输出路径
     * @param watermarkText 水印内容
     */
    public static void addWatermark(String inputPath,String outputPath,String watermarkText){
        try {
            // 读取Excel文件
            FileInputStream fis = new FileInputStream(inputPath);
            XSSFWorkbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(fis);

            // 设置文本和字体大小
            Font font = new Font("宋体",Font.PLAIN,36);
            int height = 467;
            int width = 987;

            float alpha = 0.5f;// 透明度
            Color textColor = new Color(128, 128, 128, (int) (alpha * 255));// 文本颜色和透明度

            // 绘制水印图像
            BufferedImage watermarkImage = drawText(watermarkText, font, textColor, Color.white, height, width);
            ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
            ImageIO.write(watermarkImage, "png", byteArrayOut);

            // 将水印图像添加到Excel文件中
            int pictureIdx = workbook.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_PNG);
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                XSSFSheet xssfSheet =  workbook.getSheetAt(i);
                String rID = xssfSheet.addRelation(null, XSSFRelation.IMAGE_PNG, workbook.getAllPictures().get(pictureIdx))
                        .getRelationship().getId();
                //将背景图片设置为工作表
                xssfSheet.getCTWorksheet().addNewPicture().setId(rID);
            }

            // 保存带水印的Excel到输出文件夹
            File outputDir = new File(outputPath);
            if (!outputDir.exists()) {
                outputDir.mkdirs();
            }
            String outputFilePath = outputPath + "/测试Excel.xls";

            FileOutputStream fos = new FileOutputStream(new File(outputFilePath));
            workbook.write(fos);
            fos.close();

            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理水印文字
     * @param text 水印内容
     * @param font 颜色
     * @param textColor 文字颜色
     * @param backColor 背景颜色
     * @param height 高度
     * @param width 宽度
     * @return
     */
    private static BufferedImage drawText(String text, Font font, Color textColor, Color backColor, double height, double width) {
        BufferedImage img = new BufferedImage((int) width, (int) height, TYPE_INT_ARGB);
        Graphics2D loGraphic = img.createGraphics();

        FontMetrics loFontMetrics = loGraphic.getFontMetrics(font);
        int liStrWidth = loFontMetrics.stringWidth(text);
        int liStrHeight = loFontMetrics.getHeight();

        loGraphic.setColor(backColor);
        loGraphic.fillRect(0, 0, (int) width, (int) height);// 填充文本的位置
        loGraphic.translate(((int) width - liStrWidth) / 2, ((int) height - liStrHeight) / 2);
        loGraphic.rotate(Math.toRadians(-45));// 旋转角度
        loGraphic.translate(-((int) width - liStrWidth) / 4, -((int) height - liStrHeight) / 4);
        loGraphic.setFont(font);// 字体
        loGraphic.setColor(textColor);// 颜色和透明度
        loGraphic.drawString(text, ((int) width - liStrWidth) / 4, ((int) height - liStrHeight) / 2);
        loGraphic.drawString(text, ((int) width - liStrWidth) / 2, ((int) height - liStrHeight) / 4);
        loGraphic.drawString(text, ((int) width - liStrWidth) / 6, ((int) height - liStrHeight) / 20);
        loGraphic.dispose();
        return img;
    }
}

3、测试主方法

package cn.end.less.utils;

public class ExcelTest {
    private static String inputPath  = "F:/临时/测试.xlsx";
    private static String outputPath  = "F:/临时/测试结果";
    private static String watermarkText = "我是水印呐!";

    public static void main(String[] args)throws Exception{
        long l = System.currentTimeMillis();
        ExcelTestUtil1.addWatermark(inputPath,outputPath,watermarkText);
        long l1 = System.currentTimeMillis();
        System.out.println("用时:"+(l1-l)/1000);
    }

}

4-PDF加水印

在这里插入图片描述

源代码:
1、依赖

<dependency>
  <groupId>com.itextpdf</groupId>
  <artifactId>itextpdf</artifactId>
  <version>5.5.13.1</version>
</dependency>

2、实现类

import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.HashMap;

/**
 * @author Alexander
 * @date 2023/9/18 9:38:51
 */
public class PdfUtil {
    /**
     * pdf加水印
     * @param inputPath 输入路径
     * @param outPath 输出路径
     * @param markStr 水印内容
     * @throws Exception
     */
    public static void setPdfWatermark(String inputPath, String outPath, String markStr)
            throws Exception{
        File file = new File(outPath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        BufferedOutputStream bufferOut = null;
        try {
            bufferOut = new BufferedOutputStream(new FileOutputStream(file));
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }

        PdfReader reader = new PdfReader(inputPath);
        PdfStamper stamper = new PdfStamper(reader, bufferOut);

        PdfContentByte content;
        BaseFont base = null;// 设置字体库
        try {
            base = BaseFont.createFont("C:\\Windows\\Fonts\\SIMSUN.TTC,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        } catch (Exception e) {
            e.printStackTrace();
        }
        PdfGState gs = new PdfGState();
        // 获取文件总页数
        int total = reader.getNumberOfPages() + 1;
        for (int i = 1; i < total; i++) {
            content = stamper.getOverContent(i);// 在内容上方加水印
            gs.setFillOpacity(0.2f); // 透明度

            content.beginText();
            content.setFontAndSize(base, 50);// 字体大小

            content.setRGBColorFill(220, 20, 60); // 颜色

            content.setTextMatrix(100, 250);
            content.showTextAligned(Element.ALIGN_CENTER, markStr, 250, 400, 55);// 旋转角度
            content.endText();
        }
        stamper.close();
        try {
            bufferOut.flush();
            bufferOut.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

3、测试

public static void main(String[] args) {
    try {
        setPdfWatermark("F:\\临时\\测试.pdf", "F:\\临时\\测试结果.pdf", "我是水印");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值