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
java">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:"Cambria";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:"Cambria";font-size:1pt");shapeTextPath.setString(text);pict.set(group);}static {DEFAULT = STHdrFtr.DEFAULT;EVEN = STHdrFtr.EVEN;FIRST = STHdrFtr.FIRST;}}
3、主类
java">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来传递参数去扩展。
java">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、主程序
javascript">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);
}
其他:
方式二+方式三
java">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、工具类
java">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、测试主方法
javascript">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、实现类
java">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、测试
javascript">public static void main(String[] args) {try {setPdfWatermark("F:\\临时\\测试.pdf", "F:\\临时\\测试结果.pdf", "我是水印");} catch (Exception e) {e.printStackTrace();}
}