java实现加水印功能

news2024/11/14 12:06:54

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();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

家具购物小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;家具分类管理&#xff0c;家具新品管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;家具新品&#xff0c;家具公告&#xff0…

给配置环境变量的小白们的一个tips

告诉什么也不懂的计算机小白包括我&#xff0c;配置环境变量的时候&#xff0c;系统变量配置好之后&#xff0c;path变量一定要去users里加&#xff0c;不要在系统变量里加&#xff0c;不然查版本号的时候你就会像我一样在命令行里傻傻的 你加到系统变量的path后&#xff0c;在…

Linux网络——深入理解传入层协议TCP

目录 一、前导知识 1.1 TCP协议段格式 1.2 TCP全双工本质 二、三次握手 2.1 标记位 2.2 三次握手 2.3 捎带应答 2.4 标记位 RST 三、四次挥手 3.1 标记位 FIN 四、确认应答(ACK)机制 五、超时重传机制 六 TCP 流量控制 6.1 16位窗口大小 6.2 标记位 PSH 6.3 标记…

昇思25天学习打卡营第10天|xiaoyushao

从今天开始做一些实践应用&#xff0c;今天分享的是FCN图像语义分割。 全卷积网络&#xff08;Fully Convolutional Networks&#xff0c;FCN&#xff09;是UC Berkeley的Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图…

值得买科技与MiniMax达成官方合作伙伴关系,共建融合生态

7月29日&#xff0c;值得买科技与大模型公司MiniMax宣布达成官方合作伙伴关系。 MiniMax旗下大模型产品海螺AI现已接入值得买“消费大模型增强工具集”&#xff0c;基于海螺AI比价策略&#xff0c;用户可通过海螺AI“悬浮球”功能实现快速比价及跳转购买。 此次合作也标志着值…

2023河南萌新联赛第(二)场 南阳理工学院

A. 国际旅行Ⅰ 题目&#xff1a; 思路&#xff1a; 因为题意上每个国家可以相互到达&#xff0c;所以只需要排序&#xff0c;输出第k小的值就可以了。 AC代码&#xff1a; #include<bits/stdc.h> #define int long long #define IOS ios::sync_with_stdio(0);cin.tie…

springboot短视频推荐系统-计算机毕业设计源码21503

摘 要 本论文基于协同过滤算法&#xff0c;旨在设计并实现一种基于SpringBoot框架的短视频推荐系统。该系统主要分为平台用户和管理员两类角色&#xff0c;用户可以注册、登录、浏览短视频内容&#xff0c;并根据个人兴趣收藏喜爱的视频。管理员则可以管理系统数据、用户和内容…

3.1.数据增广

数据增广 ​ 以图片为例&#xff0c;在不同的灯光&#xff0c;色温&#xff0c;以及灯光反射的影响下&#xff0c;对识别可能会造成很大影响。这时候我们希望样本有更多的多样性&#xff0c;则可以在语言里面加入各种不同的背景噪音&#xff0c;或者改变图片的颜色和形状 1.常…

【2024蓝桥杯/C++/B组/进制】

题目 代码 #include <bits/stdc.h> using namespace std;// 定义一个字符串 str&#xff0c;其内容为 "8100178706957568" string str "8100178706957568";// 函数 check 用于检查传入的字符串是否全部由数字组成 bool check(const string& st…

Java(二十七)---二叉搜索树以及Map和Set

文章目录 前言1.二叉搜索树1.1.概念1.2.操作--- 插入1.3.操作---搜索1.4.操作---删除1.6.性能分析1.7 和 java 类集的关系 2.搜索2.1.概念和场景2.2.模型 3.Map的使用3.1.关于Map的说明3.2.Map.Entry<K,V>的说明3.3.Map中常用的方法3.4.TreeMap的使用案例 4.Set的使用4.1…

探索 Milvus 存储系统:如何评估和优化 Milvus 存储性能

欢迎来到探索 Milvus 系列。Milvus 是一款支持水平扩展和具备出色性能的开源向量数据库。Milvus 的核心是其强大的存储系统&#xff0c;是数据持久化和存储的关键基础。该系统包括几个关键组成部分&#xff1a;元数据存储&#xff08;meta storage&#xff09;、消息存储&#…

Vs2022+QT+Opencv 一些需要注意的地方

要在vs2022创建QT项目&#xff0c;先要安装一个插件Qt Visual Studio Tools&#xff0c;根据个人经验选择LEGACY Qt Visual Studio Tools好一些&#xff0c;看以下内容之前建议先在vs2022中配置好opencv&#xff0c;配置方式建议以属性表的形式保存在硬盘上。 设置QT路径 打开v…

数学建模--差值算法

目录 插值方法的种类 应用实例 编程实现 算法实现 拉格朗日插值算法 ​编辑 多项式差值算法 样条插值 牛顿插值算法 插值算法在数据预测中的最新应用和案例研究是什么&#xff1f; 如何比较不同插值方法&#xff08;如线性插值、多项式插值&#xff09;在实际工程问…

bjtu数据库课程设计--基于Spring Boot框架的门店点餐系统

一、安装与配置 1 安装与配置 下载IntelliJ IDEA&#xff0c;需要下载安装jdk1.8.0_152&#xff0c;安装tomcat-9.0.88&#xff0c;安装MySQL8.0数据库。安装成功后打开IntelliJ IDEA&#xff0c;使用 Spring Boot 2.6.13框架&#xff0c;服务器URL窗口使用start.aliyun.com&a…

AI副业玩法:开启你的智能赚钱之路

在这个数码时代&#xff0c;人工智能&#xff08;AI&#xff09;已经不仅仅是科技巨头的专利&#xff0c;它逐渐渗透到我们生活的方方面面。如今&#xff0c;越来越多的人开始利用AI技术进行副业尝试&#xff0c;既拓宽了收入来源&#xff0c;也提升了自我技能。那么&#xff0…

【前端 07】JavaScript中的数组对象

JavaScript中的数组对象 在JavaScript中&#xff0c;数组&#xff08;Array&#xff09;对象是一种非常基础且强大的数据结构&#xff0c;用于在单个变量中存储多个值。这些值可以是任何数据类型&#xff0c;包括数字、字符串、甚至是其他数组&#xff08;多维数组&#xff09…

实验2-4-2 求N分之一序列前N项和**注意小细节

//实验2-4-2 求N分之一序列前N项和//计算序列 1 1/2 1/3 ... 的前N项之和。#include<stdio.h> #include<math.h> int main(){int N;double sum0.0;scanf("%d",&N);for(int a1;a<N;a)sum(1.0/a);//这里必须是1.0 不可以是1&#xff01;&#x…

【管理咨询宝藏150】MBB咨询顾问的结构化PPT训练课程

【管理咨询宝藏150】MBB咨询顾问的结构化PPT训练课程 【格式】PDF版本 【关键词】MBB、麦肯锡、罗兰贝格、咨询顾问 【核心观点】 - 在项目的开始阶段你着手发展有效的金字塔式的演示文稿—我们的重点在最后两个步骤&#xff1b;我们用金字塔结构&#xff1a;通过把核心的信息…

使用nginx解决本地环境访问线上接口跨域问题

前言 前端项目开发过程中&#xff0c;经常会遇到各种各样的跨域问题。 虽然大部分时候&#xff0c;由脚手架自带的proxy功能即可解决问题&#xff0c;如webpack&#xff0c;vite等&#xff1b;但是若没有通过脚手架搭建项目&#xff0c;或者必须使用某些特殊规则转发时&#…

<数据集>手机识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;16172张 标注数量(xml文件个数)&#xff1a;16172 标注数量(txt文件个数)&#xff1a;16172 标注类别数&#xff1a;1 标注类别名称&#xff1a;[Phone] 使用标注工具&#xff1a;labelImg 标注规则&#xff1a;…