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 {// 导出到字节流BBufferedImage 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://xiahunao.cn/news/3279823.html

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

相关文章

在linux编译JsonCpp 1.9.5

编译方法 mkdir jsoncpp-Sandbox ; cd jsoncpp-Sandbox git clone https://github.com/open-source-parsers/jsoncpp.git mkdir jsoncpp-build mkdir jsoncpp-install cd ./jsoncpp-build/ cmake ../jsoncpp/ -DCMAKE_INSTALL_PREFIX/home/vis/work/SourceCode/jsoncpp-Sandbo…

智能体一键生成个性化贺卡

文章目录 一、前言二、创建智能体编辑名称头像简介人物设定开场白引导示例高级配置调试发布 三、总结 一、前言 欢迎来到节日的温馨角落&#xff01;我是您的节日贺卡助手&#xff0c;专为您打造独一无二的节日祝福。无论是温馨的问候&#xff0c;还是创意的惊喜&#xff0c;我…

【Threejs进阶教程-着色器篇】5. 2D SDF(二)圆形波纹效果

2D SDF 圆形波纹效果 关于本Shader教程前四篇地址&#xff0c;请按顺序学习本博客使用模板代码中的Shader模板绘制第一圈波纹绘制多圈波纹fract函数 让光波动起来使用uniform控制最终效果追加uniform&#xff0c;以及lil.gui控制器修改片元着色器最终效果 完整源码 关于本Shad…

leetcode日记(63)颜色分类

感觉就是排序问题&#xff1f;我使用的是时间复杂度比较高的简单粗暴排序法&#xff0c;时间复杂度O&#xff08;n^2&#xff09;。 class Solution { public:void sortColors(vector<int>& nums) {int nnums.size();for(int i0;i<n;i){for(int ji1;j<n;j){if…

鸿蒙应用框架开发【选择并查看文档与媒体文件】 本地数据与文件

选择并查看文档与媒体文件 介绍 应用使用ohos.file.picker、ohos.file.fs等接口&#xff0c;实现了picker拉起文档编辑保存、拉起系统相册图片查看、拉起视频并播放的功能。 效果预览 使用说明&#xff1a; 在首页&#xff0c;应用显示查看最近打开文件功能的跳转按钮&…

APP自动化测试 ------ 滑动和拖拽事件操作!

前言 Appium自动化测试中的常见模拟操作涵盖了多种用户交互行为&#xff0c;这些操作对于自动化测试框架来说至关重要&#xff0c;因为它们能够模拟真实用户的使用场景&#xff0c;从而验证应用程序的功能和稳定性。 今天讲解滑动和拖拽事件操作&#xff1a; 1、swipe滑动事…

java-数据结构与算法-02-数据结构-07-优先队列

1. 概念 队列是一种先进先出的结构&#xff0c;但是有些时候&#xff0c;要操作的数据带有优先级&#xff0c;一般出队时&#xff0c;优先级较高的元素先出队&#xff0c;这种数据结构就叫做优先级队列。 比如&#xff1a;你在打音游的时候&#xff0c;你的朋友给你打了个电话…

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

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

nginx反向代理和负载均衡+安装jdk-22.0.2

ps -aux|grep nginx //查看进程 nginx 代理 nginx代理是负载均衡的基础 主机&#xff1a;192.168.118.60 这台主机只发布了web服务&#xff0c;没有做代理的任何操作 修改一下index.html中的内容 echo "this is java web server" > /usr/local/nginx/htm…

JVM性能调优全指南:高流量电商系统的最佳实践

1.G1(Garbage-First) 官网: G1 Garbage Collection G1收集器是Java 7中引入的垃圾收集器,用于替代CMS(Concurrent Mark-Sweep)收集器。它主要针对大内存、多核CPU环境下的应用场景,具有以下特点: 分代收集:G1仍然保留了分代的概念,但新生代和老年代不再是物理隔离的,…

线程的同步互斥

互斥 互斥保证了在一个时间内只有一个线程访问一个资源。 先看一段代码&#xff1a;三个线程同时对全局变量val进行--&#xff0c;同时val每自减一次其线程局部存储的全局变量 #include <iostream> #include <thread> #include <vector> #include <uni…

Java之Java基础十六(反射)

一、什么是反射 一般情况下&#xff0c;我们在使用某个类之前已经确定它到底是个什么类了&#xff0c;拿到手就直接可以使用 new 关键字来调用构造方法进行初始化&#xff0c;之后使用这个类的对象来进行操作。 Writer writer new Writer(); writer.setName("aaa"…

WPF的MVVM架构:如何通过数据绑定简化UI逻辑

WPF的MVVM架构&#xff1a;如何通过数据绑定简化UI逻辑 目录 MVVM模式概述数据绑定在MVVM中的作用实现MVVM模式的步骤MVVM模式中的常见问题与解决方案实践示例总结 MVVM模式概述 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种设计模式&#xff0c;用于WPF应用程序…

超声波传感器 - 从零开始认识各种传感器【第十九期】

超声波传感器|从零开始认识各种传感器 1、什么是超声波传感器 超声波传感器是一种利用超声波来进行距离测量和目标检测的传感器。它通过发送&#xff0c;超声波脉冲&#xff0c;并测量超声波从传感器发射到目标物体并返回的时间来计算目标物体与传感器之间的距离。 超声波传感…

echarts无数据的展示内容,用graphic属性配置

echarts无数据的展示内容&#xff0c;用graphic属性配置 当echarts无数据的时候&#xff0c;图表展示的是个空白部分&#xff0c;感觉会有点丑&#xff0c;影响页面美观&#xff0c;这时候翻阅了echarts的官网&#xff0c;让我找到个配置项&#xff0c;试试发现还可以&#xf…

Notion支持直接绑定自己的域名,有何工具可替代为公开网站自定义域名?

Notion最近大招频出&#xff0c;推出新功能——自定义域名。只需简单几步&#xff0c;xxx.notion.site秒变你的专属域名&#xff08;月费仅需10美金&#xff09;。推特上的独立内容创作者/初创公司&#xff0c;用它来打造品牌、分享资料模板&#xff0c;甚至实现盈利。 Notion的…

你还在为PDF转Word烦恼?试试这四款免费工具吧!

悄咪咪问一句&#xff0c;大家在平时上班时最头疼的事情有哪些&#xff1f;我想会有很多朋友也有pdf如何在线转换word文档的免费方式&#xff0c;毕竟这些办公文档是非常常见的问题了&#xff0c;所以今天就专门准备这么一篇文章来分享我个人喜欢的四款好用工具&#xff1a; 第…

做知识付费项目还能做吗?知识付费副业项目如何做?能挣多少钱?

hello,我是阿磊&#xff0c;一个20年的码农&#xff0c;6年前代码写不动了&#xff0c;转型专职做副业项目研究&#xff0c;为劳苦大众深度挖掘互联网副业项目&#xff0c;共同富裕。 现在做知识付费项目还能做吗&#xff1f; 互联网虚拟资源项目我一直在做&#xff0c;做了有…

【单片机毕业设计选题24088】-基于STM32的智能家居控制系统

系统功能: 系统操作说明&#xff1a; 上电后OLED显示 “欢迎使用智能家居系统请稍后”&#xff0c;两秒后显示Connecting...表示 正在连接阿里云&#xff0c;正常连接阿里云后显示第一页面&#xff0c;如长时间显示Connecting...请 检查WiFi网络是否正确。 第一页面第一行…

使用runlink通过容器打印出容器的启动命令

1、Runlike简介 Runlike:通过容器打印出容器的启动命令&#xff0c;然后发现自己需要手动重新运行一些容器的人来说&#xff0c;这是一个真正的节省时间。 2、Docker镜像安装 2.1 构建Runlike容器 [rootlocalhost ~]# docker run --rm -v /var/run/docker.sock:/var/run/do…