Java 实现 文档 添加 水印 工具类

2023-12-14 21:23:06

一、pom 文件引用


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

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

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.12.0</version>
        </dependency>

        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.14.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.0</version>
            <exclusions>
                <!--解决含嵌入文件ppt转换报错 ArrayStoreException-->
                <exclusion>
                    <artifactId>xmlbeans</artifactId>
                    <groupId>org.apache.xmlbeans</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.16</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>

二、代码展示

2.1,ImageUtil 图片工具类

package cn.piesat.space.watermark.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

/**
 * @author: wangjing
 * @createTime: 2023-12-05 15:01
 * @version: 1.0.0
 * @Description: 图片工具类
 */
public class ImageUtil {

    /**
     * 调整图片尺寸
     *
     * @param inputPath 原图片地址
     * @param outPath   新图片地址
     * @param newWidth  新图片宽
     * @param newHeight 新图片高
     */
    public static void resizeImage(String inputPath, String outPath, Integer newWidth, Integer newHeight) {
        try {
            BufferedImage bufferedImage = readPicture(inputPath);

            // 创建新的 BufferedImage,并设置绘制质量
            BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = resizedImage.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            // 绘制原始图像到新的 BufferedImage,并进行缩放
            Image scaledImage = bufferedImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
            g2d.drawImage(scaledImage, 0, 0, null);
            g2d.dispose();

            // 保存新的图片
            ImageIO.write(resizedImage, "jpg", new File(outPath));
            System.out.println("图片尺寸调整完成!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 读取图片
     *
     * @param path
     * @return
     */
    public static BufferedImage readPicture(String path) {
        try {
            // 尝试获取本地
            return readLocalPicture(path);
        } catch (Exception e) {
            // 尝试获取网路
            return readNetworkPicture(path);
        }
    }

    /**
     * 读取本地图片
     *
     * @param path
     * @return
     */
    public static BufferedImage readLocalPicture(String path) {
        if (null == path) {
            throw new RuntimeException("本地图片路径不能为空");
        }
        // 读取原图片信息 得到文件
        File srcImgFile = new File(path);
        try {
            // 将文件对象转化为图片对象
            return ImageIO.read(srcImgFile);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 读取网络图片
     *
     * @param path 网络图片地址
     */
    public static BufferedImage readNetworkPicture(String path) {
        if (null == path) {
            throw new RuntimeException("网络图片路径不能为空");
        }
        try {
            // 创建一个URL对象,获取网络图片的地址信息
            URL url = new URL(path);
            // 将URL对象输入流转化为图片对象 (url.openStream()方法,获得一个输入流)
            BufferedImage bugImg = ImageIO.read(url.openStream());
            if (null == bugImg) {
                throw new RuntimeException("网络图片地址不正确");
            }
            return bugImg;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

2.1,DocumentWaterMarkUtils?文档水印工具类

package cn.piesat.space.watermark.util;

import cn.piesat.space.watermark.enums.WatermarkTypeEnum;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.microsoft.schemas.vml.CTShape;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
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.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.xmlbeans.XmlObject;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.xml.namespace.QName;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Field;


/**
 * @author: wangjing
 * @createTime: 2023-12-05 15:01
 * @version: 1.0.0
 * @Description: 文档水印工具类
 */
@Slf4j
public class DocumentWaterMarkUtils {


    /**
     * 水印默认字体
     */
    private static Font defaultFont = new Font("宋体", Font.PLAIN, 70);
    /**
     * 水印默认字体颜色
     */
    private static Color defaultColor = new Color(0, 0, 0, 60);

    /**
     * 水印透明度
     */
    private static float alpha = 0.5f;
    /**
     * 水印之间的间隔
     */
    private static final int xMove = 200;
    /**
     * 水印之间的间隔
     */
    private static final int yMove = 200;

    public static void main(String[] args) {
        String watermarkText = "测试水印";
        String watermarkImage = "/Users/wangjing/Desktop/watermark/test.jpeg";

        // pdf
        String pdfInputPath = "/Users/wangjing/Desktop/watermark/pdf/test.pdf";
        String pdfOutPath = "/Users/wangjing/Desktop/watermark/pdf/test2.pdf";
        addPdfWatermark(pdfInputPath, pdfOutPath, watermarkText);

        // ppt
        String pptInputPath = "/Users/wangjing/Desktop/watermark/ppt/test.pptx";
        // excel 文字水印
        String pptOutPath = "/Users/wangjing/Desktop/watermark/ppt/test2.pptx";
        addPPTWatermark(pptInputPath, pptOutPath, 1, watermarkText, defaultFont, defaultColor);
        // excel 图片水印
        String pptOutPathImage = "/Users/wangjing/Desktop/watermark/ppt/test3.pptx";
        addPPTWatermark(pptInputPath, pptOutPathImage, 2, watermarkImage, null, null);

        // excel
        String watermarkImageExcel = "/Users/wangjing/Desktop/watermark/image/test1.jpg";

        String excelInputPath = "/Users/wangjing/Desktop/watermark/excel/test.xlsx";
        // excel 文字水印
        String excelOutPath = "/Users/wangjing/Desktop/watermark/excel/test2.xlsx";
        addExcelWatermark(excelInputPath, excelOutPath, 1, watermarkText, defaultFont, defaultColor);
        // excel 图片水印
        String excelOutPathImage = "/Users/wangjing/Desktop/watermark/excel/test3.xlsx";
        addExcelWatermark(excelInputPath, excelOutPathImage, 2, watermarkImageExcel, null, null);


        //word 添加文字水印
        String wordInputPath = "/Users/wangjing/Desktop/watermark/word/test.docx";
        String wordOutPath = "/Users/wangjing/Desktop/watermark/word/test2.docx";
        addWordWatermark(wordInputPath, wordOutPath, watermarkText, "#D3D3D3", true, false);
    }


    /**
     * pdf设置文字水印
     *
     * @param inputPath
     * @param outPath
     * @param watermark
     */
    public static void addPdfWatermark(String inputPath, String outPath, String watermark) {
        // 创建输出文件
        File file = new File(outPath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error("addPdfWatermark fail: 创建输出文件IO异常", e);
                throw new RuntimeException("addPdfWatermark fail: 创建输出文件IO异常");
            }
        }
        BufferedOutputStream outBufferedOutputStream = null;
        try {
            outBufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            log.error("addPdfWatermark fail: 源文件不存在", e);
            throw new RuntimeException("addPdfWatermark fail: 源文件不存在");
        }

        PdfStamper pdfStamper = null;
        int total = 0;
        PdfContentByte content;
        com.itextpdf.text.Rectangle pageSizeWithRotation = null;
        BaseFont base = null;
        PdfReader inputPdfReader = null;
        try {
            inputPdfReader = new PdfReader(inputPath);
            // 解决PdfReader not opened with owner password
            Field f = PdfReader.class.getDeclaredField("ownerPasswordUsed");
            f.setAccessible(true);
            f.set(inputPdfReader, Boolean.TRUE);
            pdfStamper = new PdfStamper(inputPdfReader, outBufferedOutputStream);
            total = inputPdfReader.getNumberOfPages() + 1;
            base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
        } catch (IOException e) {
            log.error("addPdfWatermark fail:", e);
            throw new RuntimeException("addPdfWatermark fail:IOException");
        } catch (DocumentException e) {
            log.error("addPdfWatermark fail:", e);
            throw new RuntimeException("addPdfWatermark fail: DocumentException");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        // 获取水印文字的高度和宽度
        Integer textH = 0;
        Integer textW = 0;
        JLabel label = new JLabel();
        label.setText(watermark);
        FontMetrics metrics = label.getFontMetrics(label.getFont());
        textH = metrics.getHeight();
        textW = metrics.stringWidth(label.getText());
        PdfGState gs = new PdfGState();
        for (Integer i = 1; i < total; i++) {
            //在内容上方加水印
            content = pdfStamper.getOverContent(i);
            gs.setFillOpacity(alpha);
            content.saveState();
            content.setGState(gs);
            content.beginText();
            content.setFontAndSize(base, 20);
            // 获取每一页的高度、宽度
            pageSizeWithRotation = inputPdfReader.getPageSizeWithRotation(i);
            float pageHeight = pageSizeWithRotation.getHeight();
            float pageWidth = pageSizeWithRotation.getWidth();

            // 根据纸张大小多次添加, 水印文字成30度角倾斜
            for (int height = -5 + textH; height < pageHeight; height = height + yMove) {
                for (int width = -5 + textW; width < pageWidth + textW; width = width + xMove) {
                    content.showTextAligned(Element.ALIGN_LEFT, watermark, width - textW, height - textH, 30);
                }
            }
            content.endText();
        }


        // 管理所有流
        try {
            pdfStamper.close();
            outBufferedOutputStream.flush();
            outBufferedOutputStream.close();
            inputPdfReader.close();
        } catch (IOException e) {
            log.error("addPdfWatermark fail:", e);
            throw new RuntimeException("addPdfWatermark fail: 关闭流异常,IOException");
        } catch (DocumentException e) {
            log.error("addPdfWatermark fail:", e);
            throw new RuntimeException("addPdfWatermark fail: 关闭流异常,DocumentException");
        }
    }

    /**
     * PPT 添加水印
     *
     * @param inputPath     原ppt地址
     * @param targetpath    新ppt地址
     * @param watermarkType 水印类型(1:文字水印;2:图片水印)
     * @param watermark     水印
     * @param font          字体
     * @param color         颜色
     */
    public static void addPPTWatermark(String inputPath, String targetpath, Integer watermarkType, String watermark,
                                       Font font, Color color) {
        XMLSlideShow slideShow = null;
        try {
            slideShow = new XMLSlideShow(new FileInputStream(inputPath));
        } catch (IOException e) {
            log.error("addPPTWatermark fail:", e);
            throw new RuntimeException("addPPTWatermark fail: 获取PPT文件失败");
        }
        ByteArrayOutputStream os = null;
        FileOutputStream out = null;
        try {
            //获取水印
            os = getWatermarkImage(watermarkType, watermark, font, color, 1280, 720);

            PictureData pictureData = slideShow.addPicture(os.toByteArray(), PictureData.PictureType.PNG);

            for (XSLFSlideMaster xslfSlideMaster : slideShow.getSlideMasters()) {
                XSLFPictureShape pictureShape = xslfSlideMaster.createPicture(pictureData);
//                pictureShape.setAnchor(new java.awt.Rectangle(0, 0, -1 , -1));
                pictureShape.setAnchor(pictureShape.getAnchor());
            }

            out = new FileOutputStream(targetpath);
            slideShow.write(out);
        } catch (IOException e) {
            log.error("addPPTWatermark fail:" + e);
            throw new RuntimeException("addPPTWatermark fail: 生成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();
                }
            }
        }
    }

    /**
     * excel 添加水印
     *
     * @param inputPath     原excel地址
     * @param outPath       新excel地址
     * @param watermarkType 水印类型:1:文本水印;2:图片水印;
     * @param watermark     水印(文字或图片URL)
     * @param font          字体
     * @param color         颜色
     */
    public static void addExcelWatermark(String inputPath, String outPath, Integer watermarkType, String watermark,
                                         Font font, Color color) {
        //读取excel文件
        XSSFWorkbook workbook = null;
        try {
            workbook = new XSSFWorkbook(new FileInputStream(inputPath));
        } catch (FileNotFoundException e) {
            log.error("addExcelWaterMark fail: 源文件不存在", e);
            throw new RuntimeException("addExcelWaterMark fail: 源文件不存在");
        } catch (IOException e) {
            log.error("addExcelWaterMark fail: 读取源文件IO异常", e);
            throw new RuntimeException("addExcelWaterMark fail: 读取源文件IO异常");
        }
        OutputStream fos = null;
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {

            //获取水印
            os = getWatermarkImage(watermarkType, watermark, font, color, 1000, 800);

            int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
            // 获取每个Sheet表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                XSSFSheet xssfSheet = workbook.getSheetAt(i);
                String rID =
                        xssfSheet.addRelation(null, XSSFRelation.IMAGES, workbook.getAllPictures().get(pictureIdx)).getRelationship().getId();
                xssfSheet.getCTWorksheet().addNewPicture().setId(rID);
            }

            // Excel文件生成后存储的位置。
            File file = new File(outPath);
            fos = new FileOutputStream(file);
            workbook.write(fos);
        } catch (Exception e) {
            log.error("addExcelWaterMark fail: 创建输出文件IO异常", e);
            throw new RuntimeException("addExcelWaterMark fail: 创建输出文件IO异常");
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * word 添加文字水印
     *
     * @param inputPath      原文件地址
     * @param outPath        新文件地址
     * @param watermark      水印文字
     * @param watermarkColor 水印字体颜色
     * @param incline        是否倾斜(true 倾斜,false 不倾斜)
     * @param readable       是否设置仅可读(true 仅可读,false 可编辑)
     */
    public static void addWordWatermark(String inputPath, String outPath, String watermark, String watermarkColor,
                                        Boolean incline, Boolean readable) {
        // 根据URL 获取 XWPFDocument 对象
        XWPFDocument xwpfDocument = null;
        try {
            xwpfDocument = new XWPFDocument(new FileInputStream(new File(inputPath)));
        } catch (FileNotFoundException fileNotFoundException) {
            log.error("addWordWaterMark fail: ", fileNotFoundException);
            throw new RuntimeException("addWordWaterMark fail: 源文件不存在");
        } catch (IOException ioException) {
            log.error("addWordWaterMark fail: ", ioException);
            throw new RuntimeException("addWordWaterMark fail: 读取源文件IO异常");
        } catch (Exception exception) {
            log.error("addWordWaterMark fail: ", exception);
            throw new RuntimeException("addWordWaterMark fail: 不支持的文档格式");
        }

        XWPFHeaderFooterPolicy headerFooterPolicy = xwpfDocument.getHeaderFooterPolicy();
        if (headerFooterPolicy == null) {
            //兼容处理
            headerFooterPolicy = xwpfDocument.createHeaderFooterPolicy();
        }

        //调用API添加水印,效果不好为水平居中
        headerFooterPolicy.createWatermark(watermark);

        //处理后续文档更新水印逻辑
        XWPFHeader xwpfHeader = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);

        XWPFParagraph xwpfParagraph = xwpfHeader.getParagraphArray(0);

        //设置水印样式和位置,保持倾斜角度更好看和实用
        xwpfParagraph.getCTP().newCursor();
        XmlObject[] xmlobjects = xwpfParagraph.getCTP().getRArray(0).getPictArray(0).selectChildren(
                new QName("urn:schemas-microsoft-com:vml", "shape"));
        if (xmlobjects.length > 0) {
            CTShape ctshape = (CTShape) xmlobjects[0];
            // 水印字体颜色
            ctshape.setFillcolor(watermarkColor);
            // 水印是否倾斜
            if (incline) {
                ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
            }
        }

        // 设置文档只读
        if (readable) {
            xwpfDocument.enforceReadonlyProtection();
        }

        File file = new File(outPath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error("addWordWaterMark fail: 创建输出文件IO异常", e);
                throw new RuntimeException("addWordWaterMark fail: 创建输出文件失败");
            }
        }
        try {
            xwpfDocument.write(new FileOutputStream(outPath));
        } catch (FileNotFoundException e) {
            log.error("addWordWaterMark fail: 输出文件不存在", e);
            throw new RuntimeException("addWordWaterMark fail: 创建输出文件失败");
        } catch (IOException e) {
            log.error("addWordWaterMark fail: ", e);
            throw new RuntimeException("addWordWaterMark fail");
        } finally {
            if (xwpfDocument != null) {
                try {
                    xwpfDocument.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 获取水印图片文件流
     *
     * @param watermarkType 水印类型(1:文字水印;2:图片水印)
     * @param watermark     水印
     * @param font          字体
     * @param color         颜色
     * @param width         图片宽
     * @param height        图片高
     * @return
     */
    private static ByteArrayOutputStream getWatermarkImage(Integer watermarkType, String watermark, Font font,
                                                           Color color, Integer width, Integer height) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            // 导出到字节流B
            BufferedImage bufferedImage = null;
            if (WatermarkTypeEnum.TEXT_WATERMARK.getCode().equals(watermarkType)) {
                bufferedImage = createWaterMarkImageBig(watermark, font, color, width, height);
            } else {
                // 图片水印
                bufferedImage = ImageUtil.readPicture(watermark);
            }
            ImageIO.write(bufferedImage, "png", os);
        } catch (IOException e) {
            log.error("testToImage fail: 创建水印图片IO异常", e);
            throw new RuntimeException("testToImage fail: 创建水印图片IO异常");
        }
        return os;
    }

    /**
     * 根据文字生成水印图片(大号 平铺)
     *
     * @param text  文本文字
     * @param font  字体
     * @param color 颜色
     * @return
     */
    public static BufferedImage createWaterMarkImageBig(String text, Font font, Color color, Integer width,
                                                        Integer height) {
        // 获取bufferedImage对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();
        image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g2d.dispose();
        g2d = image.createGraphics();
        //设置字体颜色和透明度
        g2d.setColor(color);
        //设置字体
        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.1,word 水印

3.2,excel 水印

3.2.1,文字水印

3.2.2,图片水印

3.3,ppt 水印

3.3.1,文字水印

3.3.2,图片水印

3.4,PDF 水印

注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!

文章来源:https://blog.csdn.net/wang_jing_jing/article/details/134933999
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。