使用 iText 库给PDF文件加水印

iText 库介绍

iText 是一款流行的 Java PDF 库,它可以用来创建、读取、修改和提取 PDF 内容。iText 提供了许多 API,包括添加文本水印的功能。

注释:创建一个Springboot来测试 iText的使用,创建项目不做过多介绍

需要的依赖

       <!-- iText 是一款流行的 Java PDF-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>

        <!-- hutool  -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.8</version>
        </dependency>

水印样式封装

创建 ITextAttributes 用于封装pdf水印样式

package com.test.testdemo.itext;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import lombok.Data;

import java.io.IOException;

/**
 * @Author Chenry.r
 * @Date 9/9/2023 下午10:11
 * @Version 1.0
 * @Description <p>备注:封装pdf水印样式</p>
 */
@Data
public class ITextAttributes {

    //字体样式
    private BaseFont fontStyle = BaseFont.createFont();
    //字体大小
    private float fontSize = 36f;
    //字体颜色
    private BaseColor fontColor = BaseColor.LIGHT_GRAY;
    //水印位置
    private int location = Element.ALIGN_CENTER;
    //水印内容
    private String showTxt = "Chenry.r制作,欢迎查看";
    //坐标以及旋转角度
    private float x = 300, y = 400, rotation = 45;


    public ITextAttributes() throws DocumentException, IOException {
    }

    public ITextAttributes(BaseFont fontStyle, float fontSize, BaseColor fontColor, int location, String showTxt, float x, float y, float rotation) throws DocumentException, IOException {
        this.fontStyle = fontStyle;
        this.fontSize = fontSize;
        this.fontColor = fontColor;
        this.location = location;
        this.showTxt = showTxt;
        this.x = x;
        this.y = y;
        this.rotation = rotation;
    }
}

封装工具类

创建 ItextWatermarkUtil 封装水印添加工具类
注意:这里你添加的水印如果有汉字的话可能要下载一个simsun.ttf字体放到 resources\fonts\simsun.ttf目录下
下载:simsun.ttf(微软宋体)
链接: https://pan.baidu.com/s/1-a7rZp6NIO0jaFr4adIWEw 提取码: 45xd

package com.test.testdemo.util;

import cn.hutool.core.io.IoUtil;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.test.testdemo.itext.ITextAttributes;
import org.springframework.core.io.ClassPathResource;

import java.io.*;

/**
 * @Author Chenry.r
 * @Date 9/9/2023 下午10:16
 * @Version 1.0
 * @Description <p>备注:pdf添加水印工具类</p>
 */
public class ItextWatermarkUtil {

    /**
     * @param pdfPath:    要处理的pdf路径
     * @param outPath:    输出pdf文件路径
     * @param attributes:
     * @Des: 这个方法处理不了中文水印, 可能因为我的
     * @Author: Chenry.r
     * @Date: 9/9/2023 下午11:07
     */
    public static void addWaterMark1(String pdfPath, String outPath, ITextAttributes attributes) {
        try {
            System.out.println("--------------开始添加水印--------------------");
            // 读取原始 PDF 文件
            PdfReader reader = new PdfReader(pdfPath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outPath));
            // 获取 PDF 中的页数
            int pageCount = reader.getNumberOfPages();
            // 添加水印
            for (int i = 1; i <= pageCount; i++) {
                PdfContentByte contentByte = stamper.getUnderContent(i); // 或者 getOverContent()
                contentByte.beginText();
                contentByte.setFontAndSize(attributes.getFontStyle(), attributes.getFontSize());
                contentByte.setColorFill(attributes.getFontColor());
                contentByte.showTextAligned(attributes.getLocation(), attributes.getShowTxt(), attributes.getX(), attributes.getY(), attributes.getRotation());
                contentByte.endText();
                System.out.println("--------------已完成第" + (i) + "页的水印添加--------------------");
            }
            // 保存修改后的 PDF 文件并关闭文件流
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("--------------添加水印完成--------------------");
        }

    }

    /**
     * @param pdfPath:    要处理的pdf路径
     * @param outPath:    输出pdf文件路径
     * @param attributes:
     * @Des: 处理带汉字的水印
     * @Author: Chenry.r
     * @Date: 9/9/2023 下午11:06
     */
    public static void addWaterMark2(String pdfPath, String outPath, ITextAttributes attributes) {
        try {
            System.out.println("--------------开始添加水印--------------------");
            // 读取原始 PDF 文件
            PdfReader reader = new PdfReader(pdfPath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outPath));
            // 获取 PDF 中的页数
            int pageCount = reader.getNumberOfPages();
            // 添加水印
            PdfContentByte content = null;
            byte[] fontBytes = IoUtil.readBytes(new ClassPathResource("fonts/simsun.ttf").getInputStream());
            for (int i = 1; i <= pageCount; i++) {
                content = stamper.getOverContent(i);
                content.beginText();
                content.setFontAndSize(BaseFont.createFont("simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true, fontBytes, null), attributes.getFontSize());
                content.setColorFill(attributes.getFontColor());
                content.showTextAligned(attributes.getLocation(), attributes.getShowTxt(), attributes.getX(), attributes.getY(), attributes.getRotation());
                content.endText();
                System.out.println("--------------已完成第" + (i) + "页的水印添加--------------------");
            }
            // 保存修改后的 PDF 文件并关闭文件流
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("--------------添加水印完成--------------------");
        }

    }

    /**
     * @param inputStream:  PDF输入流
     * @param outputStream: PDF输出流
     * @param watermark:    水印内容
     * @Des: 使用流的形式给PDF文件添加水印
     * @Author: Chenry.r
     * @Date: 9/9/2023 下午11:17
     */
    private static void addPdfWatermark(InputStream inputStream, OutputStream outputStream, String watermark) {
        // 使用iText向PDF文件添加水印
        try {
            System.out.println("--------------开始添加水印--------------------");
            PdfReader pdfReader = new PdfReader(inputStream);
            PdfStamper stamper = new PdfStamper(pdfReader, outputStream);
            int total = pdfReader.getNumberOfPages();
            PdfContentByte content = null;
            byte[] fontBytes = IoUtil.readBytes(new ClassPathResource("fonts/simsun.ttf").getInputStream());
            PdfGState gs = new PdfGState();
            for (int i = 1; i <= total; i++) {
                content = stamper.getOverContent(i);
                gs.setFillOpacity(0.3f);
                content.setGState(gs);
                content.beginText();
                content.setColorFill(BaseColor.RED);
                content.setFontAndSize(BaseFont.createFont("simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true, fontBytes, null), 30F);
                content.showTextAligned(Element.ALIGN_CENTER, watermark, 300F, 400F, 45F);
                content.endText();
            }
            stamper.close();
            pdfReader.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("--------------添加水印完成--------------------");
        }
    }

    public static void main(String[] args) throws IOException, DocumentException {

        //  测试addPdfWatermark方法
        InputStream inputStream = new FileInputStream("D:\\Users\\ThisPc\\桌面\\我的文件\\量身定制版-Java基础面试题.pdf");
        OutputStream outputStream = new FileOutputStream("D:\\Users\\ThisPc\\桌面\\新建文件夹\\量身定制版-Java基础面试题.pdf");
        String watermark = "Chenry.r制作,欢迎查看2023年9月9日";
        addPdfWatermark(inputStream, outputStream, watermark);
        //  测试addWaterMark、addWaterMark2方法
        //addWaterMark2("D:\\Users\\ThisPc\\桌面\\我的文件\\量身定制版-Java基础面试题.pdf", "D:\\Users\\ThisPc\\桌面\\新建文件夹\\量身定制版-Java基础面试题.pdf", new ITextAttributes());
    }
}

内容笔记

1、在添加水印之前,需要读取原始 PDF 文件:

PdfReader reader = new PdfReader("original.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("output.pdf"));

2、然后,遍历 PDF 中的所有页面,并使用 PdfContentByte 添加水印:

// 获取 PDF 中的页数
int pageCount = reader.getNumberOfPages();

// 添加水印
for (int i = 1; i <= pageCount; i++) {
    PdfContentByte contentByte = stamper.getUnderContent(i); // 或者 getOverContent()
    contentByte.beginText();
    contentByte.setFontAndSize(BaseFont.createFont(), 36f);
    contentByte.setColorFill(BaseColor.LIGHT_GRAY);
    contentByte.showTextAligned(Element.ALIGN_CENTER, "Watermark", 300, 400, 45);
    contentByte.endText();
}

3、最后,需要保存修改后的 PDF 文件并关闭文件流:

stamper.close();
reader.close();

4、示例:

package com.test.testdemo.test;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;

import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @Author Chenry.r
 * @Date 10/9/2023 上午12:47
 * @Version 1.0
 * @Description <p>备注:示例</p>
 */
public class ItextWatermark {

    public static void main(String[] args) throws IOException, DocumentException {
        // 读取原始 PDF 文件
        PdfReader reader = new PdfReader("D:\\Users\\ThisPc\\桌面\\我的文件\\量身定制版-Java基础面试题.pdf");
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("D:\\Users\\ThisPc\\桌面\\新建文件夹\\量身定制版-Java基础面试题-水印.pdf"));

        // 获取 PDF 中的页数
        int pageCount = reader.getNumberOfPages();

        // 添加水印
        for (int i = 1; i <= pageCount; i++) {
            PdfContentByte contentByte = stamper.getUnderContent(i); // 或者 getOverContent()
            contentByte.beginText();
            contentByte.setFontAndSize(BaseFont.createFont(), 36f);
            contentByte.setColorFill(BaseColor.LIGHT_GRAY);
            contentByte.showTextAligned(Element.ALIGN_CENTER, "Watermark", 300, 400, 45);
            contentByte.endText();
        }

        // 保存修改后的 PDF 文件并关闭文件流
        stamper.close();
        reader.close();
    }
}