前言
在工作或者个人文件处理的过程中,添加水印场景基本上是很常见的,为了防止文件被他人盗用等。
但是市面上很多文件添加水印又是需要付费的,所以我们利用开源依赖,自己去封装一下添加水印。
希望能帮助到你!
实现方式
添加依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
字体获取
如果需要该资源,则关注I am Walker,回复水印字体即可获取,或者直接获取项目源码也可以
下载后,记得将字体放在resources下
参数介绍
下载之后 将字体文件的路径 替换为自己路径即可
// 字体文件 下载后将其放在自己的resources下
private static final String FONT_STYPE_FILE = "simfang.ttf";
// 定义填充的不透明度,用于图形绘制时的透明度设置
private static final float FILL_OPACITY = 0.3f;
// 定义字体大小,用于文本绘制时设置字体的大小
private static final int FONT_SIZE = 30;
// 定义文本内边距,用于计算文本在图形中的位置
private static final float TEXT_PADDING = 40;
// 定义文本间距,用于计算多个文本之间的垂直间距
private static final float TEXT_SPACING = 50;
// 定义旋转角度,用于文本或图形的旋转,负值表示逆时针旋转
private static final int ROTATION_ANGLE = -45;
单个文件水印添加
/**
* author:walker
* time: 2024/12/1
* description: 获取字体文件
*/
private static String getBaseFontPath() throws IOException, DocumentException {
//
URL resource = ResourceUtil.getResource(FONT_STYPE_FILE);
String file = resource.getFile();
return file;
}
/**
* author:walker
* time: 2024/12/1
* description:
*
* @param inputFile 输入文件
* @param outputFile 输出文件
* @param waterMarkContent 水印内容
*/
public static void writeWaterPrint(String inputFile, String outputFile, String waterMarkContent) throws IOException, DocumentException {
if (inputFile == null || inputFile.isEmpty() || outputFile == null || outputFile.isEmpty()) {
throw new IllegalArgumentException("Input and output file paths must not be null or empty.");
}
// 判断输出文件是否存在 如果不存在则创建
File output = new File(outputFile);
if (!output.exists()) {
output.getParentFile().mkdirs();
output.createNewFile();
}
PdfReader reader = new PdfReader(inputFile);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
PdfGState gs = new PdfGState();
// 设置透明度
gs.setFillOpacity(FILL_OPACITY);
BaseFont font = BaseFont.createFont(getBaseFontPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
JLabel label = new JLabel();
label.setText(waterMarkContent);
FontMetrics metrics = label.getFontMetrics(label.getFont());
int textH = metrics.getHeight() * 2;
int textW = metrics.stringWidth(label.getText()) * 2;
int total = reader.getNumberOfPages() + 1;
PdfContentByte content;
for (int i = 1; i < total; i++) {
// **注意!这里是获取pdf最顶层,否则会使得部分pdf文档无法显示水印
content = stamper.getOverContent(i);
content.beginText();
content.setGState(gs);
content.setColorFill(BaseColor.LIGHT_GRAY);
content.setFontAndSize(font, FONT_SIZE);
// 开始写入水印
float pageWidth = reader.getPageSize(i).getWidth();
float pageHigh = reader.getPageSize(i).getHeight();
for (float heigh = TEXT_PADDING; heigh < pageHigh; heigh += textH * 4) {
for (float width = TEXT_PADDING; width < pageWidth; width += textW + TEXT_SPACING) {
content.showTextAligned(Element.ALIGN_LEFT, waterMarkContent, width, heigh, ROTATION_ANGLE);
}
}
content.endText();
}
stamper.close();
}
批量文件水印添加
/**
* author: walker
* time: 2024/12/1
* description: 批量为指定目录下的所有PDF文件添加水印
*
* @param inputDir 输入目录路径,包含需要添加水印的PDF文件
* @param outputDir 输出目录路径,用于存放添加了水印的PDF文件
* @param waterMarkContent 水印内容
*/
public static void batchWriteWaterPrint(String inputDir, String outputDir, String waterMarkContent) throws IOException, DocumentException {
File inputDirFile = new File(inputDir);
// 检查输入目录是否存在并且是一个目录
if (!inputDirFile.exists() || !inputDirFile.isDirectory()) {
throw new IllegalArgumentException("Input directory must exist and be a directory.");
}
// 创建输出目录(如果不存在)
File outputDirFile = new File(outputDir);
if (!outputDirFile.exists()) {
outputDirFile.mkdirs();
}
// 获取输入目录下的所有PDF文件
File[] files = inputDirFile.listFiles((dir, name) -> name.toLowerCase().endsWith(".pdf"));
if (files != null) {
for (File file : files) {
String inputFile = file.getAbsolutePath();
String outputFile = outputDir + File.separator + "水印版本_" + file.getName();
writeWaterPrint(inputFile, outputFile, waterMarkContent);
}
}
}
完整代码
package com.walker.util.writeWaterPrint;
import cn.hutool.core.io.resource.ResourceUtil;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
public class WriteWaterPrintUtil {
// 字体文件 下载后将其放在自己的resources下
private static final String FONT_STYPE_FILE = "simfang.ttf";
// 定义填充的不透明度,用于图形绘制时的透明度设置
private static final float FILL_OPACITY = 0.3f;
// 定义字体大小,用于文本绘制时设置字体的大小
private static final int FONT_SIZE = 30;
// 定义文本内边距,用于计算文本在图形中的位置
private static final float TEXT_PADDING = 40;
// 定义文本间距,用于计算多个文本之间的垂直间距
private static final float TEXT_SPACING = 50;
// 定义旋转角度,用于文本或图形的旋转,负值表示逆时针旋转
private static final int ROTATION_ANGLE = -45;
public static void main(String[] args) throws DocumentException, IOException {
writeWaterPrint("D:\\mymeida\\面试题\\16.内存溢出.pdf", "D:\\mymeida\\面试题\\output\\16.内存溢出.pdf", "I am Walker");
// batchWriteWaterPrint("D:\\mymeida\\面试题", "D:\\mymeida\\面试题\\output", "I am Walker");
}
/**
* author: walker
* time: 2024/12/1
* description: 批量为指定目录下的所有PDF文件添加水印
*
* @param inputDir 输入目录路径,包含需要添加水印的PDF文件
* @param outputDir 输出目录路径,用于存放添加了水印的PDF文件
* @param waterMarkContent 水印内容
*/
public static void batchWriteWaterPrint(String inputDir, String outputDir, String waterMarkContent) throws IOException, DocumentException {
File inputDirFile = new File(inputDir);
// 检查输入目录是否存在并且是一个目录
if (!inputDirFile.exists() || !inputDirFile.isDirectory()) {
throw new IllegalArgumentException("Input directory must exist and be a directory.");
}
// 创建输出目录(如果不存在)
File outputDirFile = new File(outputDir);
if (!outputDirFile.exists()) {
outputDirFile.mkdirs();
}
// 获取输入目录下的所有PDF文件
File[] files = inputDirFile.listFiles((dir, name) -> name.toLowerCase().endsWith(".pdf"));
if (files != null) {
for (File file : files) {
String inputFile = file.getAbsolutePath();
String outputFile = outputDir + File.separator + "水印版本_" + file.getName();
writeWaterPrint(inputFile, outputFile, waterMarkContent);
}
}
}
/**
* author:walker
* time: 2024/12/1
* description: 获取字体文件
*/
private static String getBaseFontPath() throws IOException, DocumentException {
//
URL resource = ResourceUtil.getResource(FONT_STYPE_FILE);
String file = resource.getFile();
return file;
}
/**
* author:walker
* time: 2024/12/1
* description:
*
* @param inputFile 输入文件
* @param outputFile 输出文件
* @param waterMarkContent 水印内容
*/
public static void writeWaterPrint(String inputFile, String outputFile, String waterMarkContent) throws IOException, DocumentException {
if (inputFile == null || inputFile.isEmpty() || outputFile == null || outputFile.isEmpty()) {
throw new IllegalArgumentException("Input and output file paths must not be null or empty.");
}
// 判断输出文件是否存在 如果不存在则创建
File output = new File(outputFile);
if (!output.exists()) {
output.getParentFile().mkdirs();
output.createNewFile();
}
PdfReader reader = new PdfReader(inputFile);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
PdfGState gs = new PdfGState();
// 设置透明度
gs.setFillOpacity(FILL_OPACITY);
BaseFont font = BaseFont.createFont(getBaseFontPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
JLabel label = new JLabel();
label.setText(waterMarkContent);
FontMetrics metrics = label.getFontMetrics(label.getFont());
int textH = metrics.getHeight() * 2;
int textW = metrics.stringWidth(label.getText()) * 2;
int total = reader.getNumberOfPages() + 1;
PdfContentByte content;
for (int i = 1; i < total; i++) {
// **注意!这里是获取pdf最顶层,否则会使得部分pdf文档无法显示水印
content = stamper.getOverContent(i);
content.beginText();
content.setGState(gs);
content.setColorFill(BaseColor.LIGHT_GRAY);
content.setFontAndSize(font, FONT_SIZE);
// 开始写入水印
float pageWidth = reader.getPageSize(i).getWidth();
float pageHigh = reader.getPageSize(i).getHeight();
for (float heigh = TEXT_PADDING; heigh < pageHigh; heigh += textH * 4) {
for (float width = TEXT_PADDING; width < pageWidth; width += textW + TEXT_SPACING) {
content.showTextAligned(Element.ALIGN_LEFT, waterMarkContent, width, heigh, ROTATION_ANGLE);
}
}
content.endText();
}
stamper.close();
}
}
水印效果
项目源码
如果需要源码,可以关注一下公众号 I am Walker,回复项目源码即可
最后
最后:我是Walker,一个热爱分享的程序员,希望我的输出能够帮助到你
对编程、副业有兴趣的同学,可以链接我、微信:walkershen1998
拉你进"程序员交流群"