随笔篇-多种类型文件加水印

1.前言

最近遇到要给pdf,excel,word,html文件加水印的需求,网上大部分实现的只是其中一种,并没有一个完整的实现方式,因此对现有的资料进行整合

支持pdf,excel,wordhtml文件多水印支持

2.依赖

文件水印是基于apach-poiitex来实现,因此需要导入一下依赖


    
        org.apache.poi
        poi-ooxml
        4.1.2
    

    
        org.apache.poi
        ooxml-schemas
        1.4
    

    
        com.itextpdf
        itext-asian
        5.2.0
    

    
        com.itextpdf
        itextpdf
        5.5.13.1
    

3.代码

文件加水印代码如下:

package com.tomato.util;

import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

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

/**
 * 

* Copyright: (C), 2022/3/27 10:47 *

* Company: tomato * * @author 秃头猿猿 * @version 1.0 */ public class WaterMarkUtils { private static final String fontName = "microsoft-yahei"; private static final String fontSize = "0.1pt"; private static final String fontColor = "#d0d0d0"; private static final Integer widthPerWord = 5; private static final String styleRotation = "-45"; private static Integer styleTop = 0; /** * pdf 增加水印 * * @param srcFile * @param destFile * @param waterMarkContent * @throws Exception */ public static void addPDFWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception { addPDFWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile), waterMarkContent); } public static void addPDFWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception { addPDFWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent); } public static void addPDFWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception { addPDFWaterMark(inputStream, new FileOutputStream(destFile), waterMarkContent); } /** * pdf 增加水印 * * @param inputStream 源文件流 * @param outputStream 目的文件流 * @param waterMarkContent 水印内容 * @throws Exception */ private static void addPDFWaterMark(InputStream inputStream, OutputStream outputStream, String... waterMarkContent) throws Exception { // 原PDF文件 PdfReader reader = new PdfReader(inputStream); // 输出的PDF文件内容 PdfStamper stamper = new PdfStamper(reader, outputStream); try { // 字体 来源于 itext-asian JAR包 BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); PdfGState gs = new PdfGState(); // 设置透明度 gs.setFillOpacity(0.3f); gs.setStrokeOpacity(0.4f); int totalPage = reader.getNumberOfPages() + 1; for (int i = 1; i < totalPage; i++) { // 内容上层 float x = reader.getPageSize(i).getWidth(); float y = reader.getPageSize(i).getHeight(); PdfContentByte content = stamper.getOverContent(i); content.beginText(); // 字体添加透明度 content.setGState(gs); // 添加字体大小等 content.setFontAndSize(baseFont, 15); // 一共七行,每行三个 for (int j = 0; j < 3; j++) { for (int k = 0; k < 7; k++) { int ji = 0; // 多个水印之间的间隔 for (String water : waterMarkContent) { //showTextAligned 方法的参数(文字对齐方式,位置内容,输出水印X轴位置,Y轴位置,旋转角度) content.showTextAligned(Element.ALIGN_CENTER, water, x / 3 * j + 90, y / 7 * k - ji, 25); ji = 20; } } } content.endText(); } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭 if (stamper != null) { stamper.close(); } if (reader != null) { reader.close(); } } } /** * excel 加水印 * * @param srcFile * @param destFile * @param waterMarkContent * @throws Exception */ public static void addExcelWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception { addExcelWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile), waterMarkContent); } public static void addExcelWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception { addExcelWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent); } public static void addExcelWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception { addExcelWaterMark(inputStream, new FileOutputStream(destFile), waterMarkContent); } /** * excel添加水印 * * @param inputStream 原始文件流 * @param outputStream 生成文件流 * @param waterMarkName 水印内容 */ public static void addExcelWaterMark(InputStream inputStream, OutputStream outputStream, String... waterMarkName) throws Exception { BufferedImage image = createWaterMarkImage(waterMarkName); // 导出到字节流B ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(image, "png", os); XSSFWorkbook workbook = new XSSFWorkbook(inputStream); int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG); POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx); for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表 XSSFSheet sheet = workbook.getSheetAt(i); PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName(); String relType = XSSFRelation.IMAGES.getRelation(); PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null); sheet.getCTWorksheet().addNewPicture().setId(pr.getId()); } workbook.write(outputStream); } public static void addWordWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception { addWordWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile), waterMarkContent); } public static void addWordWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception { addWordWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent); } public static void addWordWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception { addWordWaterMark(inputStream, new FileOutputStream(destFile), waterMarkContent); } /** * word加水印 * * @param inputStream * @param outputStream * @param customText * @throws Exception */ public static void addWordWaterMark(InputStream inputStream, OutputStream outputStream, String... customText) throws Exception { XWPFDocument doc = new XWPFDocument(inputStream); // 把整页都打上水印 for (int lineIndex = -5; lineIndex < 20; lineIndex++) { styleTop = 100 * lineIndex; waterMarkDocXDocument_0(doc, customText); } doc.write(outputStream); } public static void addHtmlWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception { addHtmlWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile, Boolean.TRUE), waterMarkContent); } public static void addHtmlWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception { addHtmlWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent); } public static void addHtmlWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception { addHtmlWaterMark(inputStream, new FileOutputStream(destFile, Boolean.TRUE), waterMarkContent); } public static void addHtmlWaterMark(InputStream inputStream, OutputStream outputStream, String... customText) throws Exception { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); PrintWriter pw = new PrintWriter(outputStream); String line = null; while ((line = bufferedReader.readLine()) != null) { pw.append(line); } String waterMarkCode = ""; int y = 20; for (String text : customText) { String replace = waterMarkCode.replace("{0}", text).replace("{1}", "watermark_y:" + y); pw.println(replace); y += 20; } pw.flush(); pw.close(); bufferedReader.close(); pw.close(); } /** * 为文档添加水印 * * @param doc 需要被处理的docx文档对象 * @param customText 需要添加的水印文字 */ private static void waterMarkDocXDocument_0(XWPFDocument doc, String... customText) { // 如果之前已经创建过 DEFAULT 的Header,将会复用 XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT); int size = header.getParagraphs().size(); if (size == 0) { header.createParagraph(); } CTP ctp = header.getParagraphArray(0).getCTP(); byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR(); byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault(); ctp.setRsidP(rsidr); ctp.setRsidRDefault(rsidrdefault); CTPPr ppr = ctp.addNewPPr(); ppr.addNewPStyle().setVal("Header"); // 开始加水印 CTR ctr = ctp.addNewR(); CTRPr ctrpr = ctr.addNewRPr(); ctrpr.addNewNoProof(); CTGroup group = CTGroup.Factory.newInstance(); CTShapetype shapetype = group.addNewShapetype(); CTTextPath shapeTypeTextPath = shapetype.addNewTextpath(); shapeTypeTextPath.setOn(STTrueFalse.T); shapeTypeTextPath.setFitshape(STTrueFalse.T); CTLock lock = shapetype.addNewLock(); lock.setExt(STExt.VIEW); CTShape shape = group.addNewShape(); shape.setId("PowerPlusWaterMarkObject"); shape.setSpid("_x0000_s102"); shape.setType("#_x0000_t136"); // 设置形状样式(旋转,位置,相对路径等参数) //shape.setStyle(getShapeStyle(customText)); shape.setFillcolor(fontColor); // 字体设置为实心 shape.setStroked(STTrueFalse.FALSE); // 绘制文本的路径 CTTextPath shapeTextPath = shape.addNewTextpath(); // 设置文本字体与大小 shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize); //shapeTextPath.setString(customText); //CTPicture pict = ctr.addNewPict(); // pict.set(group); int position = 0; for (String s : customText) { // 水印文字之间使用50个空格分隔 s = s + repeatString("\t", 45); // 一行水印重复水印文字次数 s = repeatString(s, 5); // 设置形状样式(旋转,位置,相对路径等参数) shape.setStyle(getShapeStyle(s, position)); shapeTextPath.setString(s); CTPicture pict = ctr.addNewPict(); pict.set(group); position += 30; } } /** * 构建Shape的样式参数 * * @param customText * @return */ private static String getShapeStyle(String customText, Integer position) { StringBuilder sb = new StringBuilder(); // 文本path绘制的定位方式 sb.append("position: ").append("absolute"); // 计算文本占用的长度(文本总个数*单字长度) sb.append(";width: ").append(customText.length() * widthPerWord).append("pt"); // 字体高度 sb.append(";height: ").append("10pt"); sb.append(";z-index: ").append("-251654144"); sb.append(";mso-wrap-edited: ").append("f"); // 设置水印的间隔,这是一个大坑,不能用top,必须要margin-top。 sb.append(";margin-top: ").append(styleTop + position); sb.append(";mso-position-horizontal-relative: ").append("page"); sb.append(";mso-position-vertical-relative: ").append("page"); sb.append(";mso-position-vertical: ").append("left"); sb.append(";mso-position-horizontal: ").append("center"); sb.append(";rotation: ").append(styleRotation); return sb.toString(); } /** * 将指定的字符串重复repeats次. */ private static String repeatString(String pattern, int repeats) { StringBuilder buffer = new StringBuilder(pattern.length() * repeats); Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append); return new String(buffer); } /** * 创建水印图片 * excel * * @param waterMark 水印内容 * @return */ public static BufferedImage createWaterMarkImage(String... waterMark) { String[] textArray = waterMark; Font font = new Font(fontName, Font.PLAIN, 20); Integer width = 300; Integer height = 100; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 背景透明 开始 Graphics2D g = image.createGraphics(); image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT); g.dispose(); // 背景透明 结束 g = image.createGraphics(); g.setColor(new Color(Integer.parseInt("#C5CBCF".substring(1), 16)));// 设定画笔颜色 g.setFont(font);// 设置画笔字体 g.shear(0.1, -0.26);// 设定倾斜度 // 设置字体平滑 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int y = 50; for (int i = 0; i < textArray.length; i++) { g.drawString(textArray[i], 0, y);// 画出字符串 y = y + font.getSize(); } g.dispose();// 释放画笔 return image; } }

4.演示

4.1 pdf

代码如下:

WaterMarkUtils.addPDFWaterMark(new File("D:\\Desktop\\watermark.pdf"),new File("D:\\Desktop\\watermark1.pdf"),"秃头猿猿","hello");

效果如下:

image-20220327105611251

4.2 word

代码如下:

WaterMarkUtils.addExcelWaterMark(new File("D:\\Desktop\\excel.xlsx"),new File("D:\\Desktop\\watermark1.xlsx"),"秃头猿猿","hello"); 

效果如下:

image-20220327105941116

4.3 word

代码如下:

WaterMarkUtils.addWordWaterMark(new File("D:\\Desktop\\word.docx"),new File("D:\\Desktop\\watermark1.docx"),"秃头猿猿","hello"); 

效果如下:

image-20220327110205727

4.4 html

代码如下:

WaterMarkUtils.addHtmlWaterMark(new File("D:\\Desktop\\watermark.html"),new File("D:\\Desktop\\watermark1.html"),"秃头猿猿","hello"); 

效果如下:

image-20220327110444661

你可能感兴趣的:(随笔篇-多种类型文件加水印)