java
复制代码
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.RandomUtil;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import org.springframework.util.Assert;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
public class PDFUtil {
// public static void pdfAddWaterMark(String inputFilePath, String outputFilePath, String waterMarkContent) {
// try{
// System.out.println("开始添加水印...");
// PdfStamper pdfStamper = null;
// PdfReader pdfReader = null;
//
// try {
// // 水印的高和宽
// int waterMarkHeight = 30;
// int watermarkWeight = 60;
//
// // 水印间隔距离
// int waterMarkInterval = 50;
//
// // 读取PDF文件流
// pdfReader = new PdfReader(inputFilePath);
//
// // 创建PDF文件的模板,可以对模板的内容修改,重新生成新PDF文件
// pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(outputFilePath));
//
// // 设置水印字体
// BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
//
// // 设置PDF内容的Graphic State 图形状态
// PdfGState pdfGraPhicState = new PdfGState();
// // 填充透明度
// pdfGraPhicState.setFillOpacity(0.1f);
// // 轮廓不透明度
// pdfGraPhicState.setStrokeOpacity(0.1f);
//
// // PDF页数
// int pdfPageNum = pdfReader.getNumberOfPages() + 1;
//
// // PDF文件内容字节
// PdfContentByte pdfContent;
//
// // PDF页面矩形区域
// Rectangle pageRectangle;
//
// for (int i = 1; i < pdfPageNum; i++) {
// // 获取当前页面矩形区域
// pageRectangle = pdfReader.getPageSizeWithRotation(i);
// // 获取当前页内容,getOverContent表示之后会在页面内容的上方加水印
// pdfContent = pdfStamper.getOverContent(i);
//
// // 获取当前页内容,getOverContent表示之后会在页面内容的下方加水印
// //pdfContent = pdfStamper.getUnderContent(i);
//
// pdfContent.saveState();
// // 设置水印透明度
// pdfContent.setGState(pdfGraPhicState);
//
// // 开启写入文本
// pdfContent.beginText();
// // 设置字体
// pdfContent.setFontAndSize(baseFont, 20);
//
// // 在高度和宽度维度每隔waterMarkInterval距离添加一个水印
// for (int height = waterMarkHeight; height < pageRectangle.getHeight(); height = height + waterMarkInterval) {
// for (int width = watermarkWeight; width < pageRectangle.getWidth() + watermarkWeight;
// width = width + waterMarkInterval) {
// // 添加水印文字并旋转30度角
// pdfContent.showTextAligned(Element.ALIGN_LEFT, waterMarkContent,
// width - watermarkWeight,
// height - waterMarkHeight,
// 30);
// }
// }
// // 停止写入文本
// pdfContent.endText();
//
// }
//
// System.out.println("导出成功");
// } catch (Exception e) {
// e.printStackTrace();
// }finally {
// pdfStamper.close();
// pdfReader.close();
// }
// pdfStamper.close();
// pdfReader.close();
//
// }catch (Exception e){
// e.printStackTrace();
//
// }
//
//
// }
public static Boolean pdfAddWaterMark(String inputFilePath, String outputFilePath, String waterMarkContent) {
System.out.println("开始添加水印...");
Boolean state = true;
PdfStamper pdfStamper = null;
PdfReader pdfReader = null;
InputStream inputStream = null;
try {
// 水印的高和宽
int waterMarkHeight = 30;
int watermarkWeight = 60;
// 水印间隔距离
int waterMarkInterval = 50;
// 使用流式读取 PDF 文件
inputStream = new FileInputStream(inputFilePath);
pdfReader = new PdfReader(inputStream);
// 创建 PDF 文件的模板,可以对模板的内容修改,重新生成新 PDF 文件
pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(outputFilePath));
// 设置水印字体
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
// 设置 PDF 内容的 Graphic State 图形状态
PdfGState pdfGraPhicState = new PdfGState();
pdfGraPhicState.setFillOpacity(0.1f); // 填充透明度
pdfGraPhicState.setStrokeOpacity(0.1f); // 轮廓不透明度
// PDF 页数
int pdfPageNum = pdfReader.getNumberOfPages();
// 逐页处理 PDF 文件
for (int i = 1; i <= pdfPageNum; i++) {
// 获取当前页面矩形区域
Rectangle pageRectangle = pdfReader.getPageSizeWithRotation(i);
// 获取当前页内容,getOverContent 表示之后会在页面内容的上方加水印
PdfContentByte pdfContent = pdfStamper.getOverContent(i);
pdfContent.saveState();
pdfContent.setGState(pdfGraPhicState); // 设置水印透明度
// 开启写入文本
pdfContent.beginText();
pdfContent.setFontAndSize(baseFont, 20);
// 在高度和宽度维度每隔 waterMarkInterval 距离添加一个水印
for (int height = waterMarkHeight; height < pageRectangle.getHeight(); height += waterMarkInterval) {
for (int width = watermarkWeight; width < pageRectangle.getWidth() + watermarkWeight; width += waterMarkInterval) {
// 添加水印文字并旋转 30 度角
pdfContent.showTextAligned(Element.ALIGN_LEFT, waterMarkContent,
width - watermarkWeight,
height - waterMarkHeight,
30);
}
}
// 停止写入文本
pdfContent.endText();
pdfContent.restoreState();
}
System.out.println("水印添加完成,文件已保存至: " + outputFilePath);
} catch (Exception e) {
e.printStackTrace();
state = false;
} finally {
// 关闭资源
if (pdfStamper != null) {
try {
pdfStamper.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (pdfReader != null) {
pdfReader.close();
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return state;
}
}
public static byte[] pdfAddWaterMark(byte[] inputPdfBytes, String waterMarkContent) {
System.out.println("开始添加水印...");
PdfStamper pdfStamper = null;
PdfReader pdfReader = null;
ByteArrayInputStream inputStream = null;
ByteArrayOutputStream outputStream = null;
try {
int waterMarkHeight = 30;
int watermarkWeight = 60;
int waterMarkInterval = 50;
inputStream = new ByteArrayInputStream(inputPdfBytes);
pdfReader = new PdfReader(inputStream);
outputStream = new ByteArrayOutputStream();
pdfStamper = new PdfStamper(pdfReader, outputStream);
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
PdfGState pdfGraPhicState = new PdfGState();
pdfGraPhicState.setFillOpacity(0.1f);
pdfGraPhicState.setStrokeOpacity(0.1f);
int pdfPageNum = pdfReader.getNumberOfPages();
for (int i = 1; i <= pdfPageNum; i++) {
Rectangle pageRectangle = pdfReader.getPageSizeWithRotation(i);
PdfContentByte pdfContent = pdfStamper.getOverContent(i);
pdfContent.saveState();
pdfContent.setGState(pdfGraPhicState);
pdfContent.beginText();
pdfContent.setFontAndSize(baseFont, 20);
for (int height = waterMarkHeight; height < pageRectangle.getHeight(); height += waterMarkInterval) {
for (int width = watermarkWeight; width < pageRectangle.getWidth() + watermarkWeight; width += waterMarkInterval) {
pdfContent.showTextAligned(Element.ALIGN_LEFT, waterMarkContent,
width - watermarkWeight,
height - waterMarkHeight,
30);
}
}
pdfContent.endText();
pdfContent.restoreState();
}
pdfStamper.close();
pdfStamper = null;
byte[] result = outputStream.toByteArray();
System.out.println("水印添加完成,输出大小: " + result.length + " bytes");
return result;
} catch (Exception e) {
throw new RuntimeException("PDF水印添加失败", e);
} finally {
if (pdfStamper != null) {
try {
pdfStamper.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (pdfReader != null) {
pdfReader.close();
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 添加图片水印 - 简化版本(使用默认参数)
* @param inputFilePath 输入PDF文件路径
* @param outputFilePath 输出PDF文件路径
* @param imageWaterMarkPath 水印图片路径
* @return 是否成功
*/
public static Boolean pdfAddImageWaterMark(String inputFilePath, String outputFilePath, String imageWaterMarkPath) {
return pdfAddImageWaterMark(inputFilePath, outputFilePath, imageWaterMarkPath, 0.3f, 3f);
}
/**
* 添加图片水印 - 简化版本(使用默认参数)
* @param inputPdfBytes 输入PDF字节数组
* @param imageWaterMarkBytes 水印图片字节数组
* @return 添加水印后的PDF字节数组
*/
public static byte[] pdfAddImageWaterMark(byte[] inputPdfBytes, byte[] imageWaterMarkBytes) {
return pdfAddImageWaterMark(inputPdfBytes, imageWaterMarkBytes, 0.3f, 3f);
}
/**
* 添加图片水印 - 文件路径方式
* @param inputFilePath 输入PDF文件路径
* @param outputFilePath 输出PDF文件路径
* @param imageWaterMarkPath 水印图片路径
* @param opacity 水印透明度 (0.0f - 1.0f)
* @param scale 图片缩放比例 (0.0f - 1.0f)
* @return 是否成功
*/
public static Boolean pdfAddImageWaterMark(String inputFilePath, String outputFilePath,
String imageWaterMarkPath, float opacity, float scale) {
System.out.println("开始添加图片水印...");
Boolean state = true;
PdfStamper pdfStamper = null;
PdfReader pdfReader = null;
InputStream pdfInputStream = null;
InputStream imageInputStream = null;
try {
// 水印间隔距离
int waterMarkInterval = 50;
// 使用流式读取 PDF 文件
pdfInputStream = new FileInputStream(inputFilePath);
pdfReader = new PdfReader(pdfInputStream);
// 读取水印图片
URL imageUrl = ResourceUtil.getResource("waterMark/waterMark.png");
Assert.notNull(imageUrl, "水印图片不存在");
Image waterMarkImage = Image.getInstance(imageUrl);
// 设置图片缩放
waterMarkImage.scalePercent(scale);
waterMarkImage.setRotationDegrees(30f);
// 获取图片实际尺寸
float imageWidth = waterMarkImage.getScaledWidth();
float imageHeight = waterMarkImage.getScaledHeight();
// 创建 PDF 文件的模板
pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(outputFilePath));
// 设置 PDF 内容的 Graphic State 图形状态
PdfGState pdfGraPhicState = new PdfGState();
pdfGraPhicState.setFillOpacity(opacity); // 填充透明度
pdfGraPhicState.setStrokeOpacity(opacity); // 轮廓不透明度
// PDF 页数
int pdfPageNum = pdfReader.getNumberOfPages();
// 逐页处理 PDF 文件
for (int i = 1; i <= pdfPageNum; i++) {
// 获取当前页面矩形区域
Rectangle pageRectangle = pdfReader.getPageSizeWithRotation(i);
float pageWidth = pageRectangle.getWidth();
float pageHeight = pageRectangle.getHeight();
// 获取当前页内容
PdfContentByte pdfContent = pdfStamper.getOverContent(i);
pdfContent.saveState();
pdfContent.setGState(pdfGraPhicState); // 设置水印透明度
// 在高度和宽度维度每隔 waterMarkInterval 距离添加一个水印图片
for (float height = imageHeight; height < pageHeight; height += waterMarkInterval + imageHeight) {
for (float width = imageWidth + RandomUtil.randomFloat(-50f, 50f); width < pageWidth + imageWidth; width += waterMarkInterval + RandomUtil.randomFloat(-50f,50f) + imageWidth) {
// 设置图片位置
waterMarkImage.setAbsolutePosition(
width - imageWidth,
height - imageHeight
);
// 添加图片到PDF内容
pdfContent.addImage(waterMarkImage);
}
}
pdfContent.restoreState();
}
System.out.println("图片水印添加完成,文件已保存至: " + outputFilePath);
} catch (Exception e) {
e.printStackTrace();
state = false;
} finally {
// 关闭资源
closeResources(pdfStamper, pdfReader, pdfInputStream, imageInputStream);
return state;
}
}
/**
* 添加图片水印 - 字节数组方式
* @param inputPdfBytes 输入PDF字节数组
* @param imageWaterMarkBytes 水印图片字节数组
* @param opacity 水印透明度 (0.0f - 1.0f)
* @param scale 图片缩放比例 (0.0f - 1.0f)
* @return 添加水印后的PDF字节数组
*/
public static byte[] pdfAddImageWaterMark(byte[] inputPdfBytes, byte[] imageWaterMarkBytes,
float opacity, float scale) {
System.out.println("开始添加图片水印...");
PdfStamper pdfStamper = null;
PdfReader pdfReader = null;
ByteArrayInputStream pdfInputStream = null;
ByteArrayInputStream imageInputStream = null;
ByteArrayOutputStream outputStream = null;
try {
// 水印间隔距离
int waterMarkInterval = 100;
pdfInputStream = new ByteArrayInputStream(inputPdfBytes);
pdfReader = new PdfReader(pdfInputStream);
// 读取水印图片
imageInputStream = new ByteArrayInputStream(imageWaterMarkBytes);
Image waterMarkImage = Image.getInstance(imageWaterMarkBytes);
// 设置图片缩放
waterMarkImage.scalePercent(scale * 100);
// 获取图片实际尺寸
float imageWidth = waterMarkImage.getScaledWidth();
float imageHeight = waterMarkImage.getScaledHeight();
outputStream = new ByteArrayOutputStream();
pdfStamper = new PdfStamper(pdfReader, outputStream);
// 设置 PDF 内容的 Graphic State 图形状态
PdfGState pdfGraPhicState = new PdfGState();
pdfGraPhicState.setFillOpacity(opacity);
pdfGraPhicState.setStrokeOpacity(opacity);
int pdfPageNum = pdfReader.getNumberOfPages();
for (int i = 1; i <= pdfPageNum; i++) {
Rectangle pageRectangle = pdfReader.getPageSizeWithRotation(i);
float pageWidth = pageRectangle.getWidth();
float pageHeight = pageRectangle.getHeight();
PdfContentByte pdfContent = pdfStamper.getOverContent(i);
pdfContent.saveState();
pdfContent.setGState(pdfGraPhicState);
// 在页面上平铺水印图片
for (float height = imageHeight; height < pageHeight; height += waterMarkInterval + imageHeight) {
for (float width = imageWidth; width < pageWidth + imageWidth; width += waterMarkInterval + imageWidth) {
waterMarkImage.setAbsolutePosition(
width - imageWidth,
height - imageHeight
);
pdfContent.addImage(waterMarkImage);
}
}
pdfContent.restoreState();
}
pdfStamper.close();
byte[] result = outputStream.toByteArray();
System.out.println("图片水印添加完成,输出大小: " + result.length + " bytes");
return result;
} catch (Exception e) {
throw new RuntimeException("PDF图片水印添加失败", e);
} finally {
closeResources(pdfStamper, pdfReader, pdfInputStream, imageInputStream);
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 公共资源关闭方法
*/
private static void closeResources(PdfStamper stamper, PdfReader reader, InputStream... streams) {
if (stamper != null) {
try {
stamper.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (reader != null) {
reader.close();
}
for (InputStream stream : streams) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}