一、使用场景
给pdf每页文章加水印,包括单文字水印、单图片水印、多文字平铺水印、多图片平铺水印。
文字水印要求:可以设置文字字体(可以自定义,导入系统字体文件)、字号、颜色,水印居中显示,可以设置旋转角度,透明度。
图片水印要求:可以设置旋转角度,透明度,缩放。
二、效果展示
单水印效果:
多水印效果:
三、代码实现
1.引入依赖
<!--pdf水印相关-->
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.0-RC1</version>
</dependency>
<dependency>
<groupId>org.ofdrw</groupId>
<artifactId>ofdrw-full</artifactId>
<version>1.17.6</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<!-- 中文水印的字体支持 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!--pdf水印相关结束-->
2.水印工具类
package cnki.bdms.utils;
import cn.hutool.core.io.FileUtil;
import cnki.bdms.common.util.StringUtil;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.util.Matrix;
import org.ofdrw.core.annotation.pageannot.AnnotType;
import org.ofdrw.core.basicType.ST_Box;
import org.ofdrw.font.FontName;
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.edit.Annotation;
import org.ofdrw.layout.element.canvas.FontSetting;
import org.ofdrw.reader.OFDReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: WaterMarkUtil
* @Description: (文档加文字水印,图片水印,支持pdf,ofd文件)
* @author: SongBin
* @date: 2022年7月6日 上午11:08:05
*/
public class WaterMarkUtil {
private static Logger log = LoggerFactory.getLogger(WaterMarkUtil.class);
/**
* @param args
*/
public static void main(String[] args) {
try {
// 测试添加图片水印
//水印图片路径
String iconPath = "d:/cvtest/watermark.png";
//源文件路径
String strSourcePdfPath = "d:/cvtest/非技术也能看懂的NLP入门科普.pdf";
//目标文件路径
String strTargetPdfPath_1 = "d:/cvtest/pdfbox_img_1.pdf";
String strTargetPdfPath_2 = "d:/cvtest/itextpdf_img_9.pdf";
String strTargetPdfPath_21 = "d:/cvtest/itextpdf_img_1.pdf";
//透明度,小数。例如,0.7f
float floatAlpha = 0.4f;
//旋转角度
int intDegree = 45;
//水印的位置,横轴
Integer intIconLocateX = 380;
//水印的位置,纵轴
Integer intIconLocateY = 100;
//缩放比例
float scalePercent = 1.0f;
// //pdfbox居中固定每页水印位置
WaterMarkUtil.waterMarkByIcon4Pdf(iconPath, strSourcePdfPath, strTargetPdfPath_1,
floatAlpha, intDegree ,scalePercent);
//
// //pdfbox平铺图片水印
WaterMarkUtil.waterMarkByItextPdf(iconPath, strSourcePdfPath, strTargetPdfPath_2,
floatAlpha, intDegree,scalePercent);
//itextpdf居中固定每页水印位置
WaterMarkUtil.oneWaterMarkByItextPdf(iconPath, strSourcePdfPath, strTargetPdfPath_21,
floatAlpha, intDegree,scalePercent);
} catch (Exception e) {
e.printStackTrace();
}
try {
// 测试添加文字水印
//源文件路径
String strSourcePdfPath = "d:/cvtest/非技术也能看懂的NLP入门科普.pdf";
//目标文件路径
String strTargetPdfPath_3 = "d:/cvtest/pdfbox_txt_9.pdf";
String strTargetPdfPath_4 = "d:/cvtest/pdfbox_txt_1.pdf";
String strTargetPdfPath_5 = "d:/cvtest/itextpdf_txt_9.pdf";
String strTargetPdfPath_6 = "d:/cvtest/itextpdf_txt_1.pdf";
//透明度,小数。例如,0.7f
float floatAlpha = 0.5f;
//文字旋转角度
int intDegree = 45;
//字体名称。默认“宋体”
String strFontName = "simsun.ttc";
//字号
int intFontSize = 16;
//水印文字内容
String strWaterMarkText = "我的网络股份有限公司";
//字体颜色
Field field = Color.class.getField("gray");
Color color = (Color) field.get(null);
// // pdfbox实现平铺文字水印
WaterMarkUtil.waterMarkByText4Pdf(strSourcePdfPath, strTargetPdfPath_3,
strWaterMarkText,
floatAlpha, intDegree,
strFontName, intFontSize, color);
//// // pdfbox实现定点单文字水印
WaterMarkUtil.waterMarkByText4Pdf(strSourcePdfPath, strTargetPdfPath_4,
strWaterMarkText,
floatAlpha, intDegree,
strFontName, intFontSize, color,null,null);
BaseColor color1 = BaseColor.GRAY.GRAY;
// // itextpdf实现平铺文字水印
WaterMarkUtil.waterMarkByITextPdf(strSourcePdfPath, strTargetPdfPath_5,
strWaterMarkText,
floatAlpha, intDegree,
strFontName, intFontSize, color1);
// // itextpdf实现定点单文字水印
WaterMarkUtil.oneWaterMarkByITextPdf(strSourcePdfPath, strTargetPdfPath_6,
strWaterMarkText,
floatAlpha, intDegree,
strFontName, intFontSize, color1);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 给pdf添加水印
*
* @param strIconPath 水印图片路径
* @param strSourceImgPath 源文件路径
* @param strTargetImgPath 目标文件路径
*/
public static boolean waterMarkByIcon4Pdf(String strIconPath, String strSourceImgPath, String strTargetImgPath) {
return waterMarkByIcon4Pdf(strIconPath, strSourceImgPath, strTargetImgPath,
0, 0,0);
}
/**
* 给PDF添加单图片水印、可设置水印图片旋转角度
*
* @param strIconPath 水印图片路径
* @param strSourcePdfPath 源文件路径
* @param strTargetPdfPath 目标文件路径
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 旋转角度
* @param intIconLocateX 水印的位置,横轴
* @param intIconLocateY 水印的位置,纵轴
*/
public static boolean waterMarkByIcon4Pdf(String strIconPath, String strSourcePdfPath, String strTargetPdfPath,
float floatAlpha, int intDegree,
float scalePercent
) {//Integer intIconLocateX, Integer intIconLocateY,
try {
if (floatAlpha == 0) {
floatAlpha = 0.5f;
}
// if (intIconLocateX == null) {
// intIconLocateX = 380;
// }
// if (intIconLocateY == null) {
// intIconLocateY = 100;
// }
if (scalePercent == 0) {
scalePercent = 1.0f;
}
File file = new File(strSourcePdfPath);
PDDocument doc = Loader.loadPDF(file);
for (int i = 0; i < doc.getNumberOfPages(); i++) {
PDPage page = doc.getPage(i);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);
PDImageXObject pdImage = PDImageXObject.createFromFile(strIconPath, doc);
PDExtendedGraphicsState pdExtGfxState = new PDExtendedGraphicsState();
// 设置透明度
pdExtGfxState.setNonStrokingAlphaConstant(floatAlpha);
pdExtGfxState.setAlphaSourceFlag(true);
pdExtGfxState.getCOSObject().setItem(COSName.BM, COSName.MULTIPLY);
contentStream.setGraphicsStateParameters(pdExtGfxState);
/***让插入图片水印居中**************/
float floatIconWidth = pdImage.getWidth() * scalePercent;
float floatIconHeight = pdImage.getHeight() * scalePercent;
float x_pos = page.getCropBox().getWidth();
float y_pos = page.getCropBox().getHeight();
float x_adjusted = ( x_pos - floatIconWidth ) / 2;
float y_adjusted = ( y_pos - floatIconHeight ) / 2;
// Matrix mt = new Matrix(1f, 0f, 0f, -1f, page.getCropBox().getLowerLeftX(), page.getCropBox().getUpperRightY());
// Matrix mt = Matrix.getRotateInstance(Math.toRadians(45), x_adjusted, y_adjusted);
// mt.rotate(45);
/***让插入图片水印居中**************/
// contentStream.transform(mt);
contentStream.transform(Matrix.getRotateInstance(Math.toRadians(intDegree), x_adjusted, y_adjusted));
contentStream.drawImage(pdImage, x_adjusted, y_adjusted, floatIconWidth, floatIconHeight);
// contentStream.drawImage(pdImage, intIconLocateX, intIconLocateY, intIconWidth, intIconHeight);
contentStream.close();
}
doc.save(strTargetPdfPath);
doc.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 给PDF添加居中单图片水印、可设置水印图片旋转角度
*
* @param strIconPath 水印图片路径
* @param strSourcePdfPath 源文件路径
* @param strTargetPdfPath 目标文件路径
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 旋转角度
* @param scalePercent 缩放比例
*/
public static boolean oneWaterMarkByItextPdf(String strIconPath, String strSourcePdfPath, String strTargetPdfPath,
float floatAlpha, int intDegree, float scalePercent) {
intDegree = intDegree * -1;
if (floatAlpha == 0) {
floatAlpha = 0.5f;
}
if (scalePercent == 0) {
scalePercent = 1.0f;
}
BufferedOutputStream bos = null;
PdfReader reader = null;
PdfStamper stamper = null;
try {
File file = new File(strTargetPdfPath);
if (!file.exists()) {
FileUtil.file(file);
}
bos = new BufferedOutputStream(new FileOutputStream(file));
reader = new PdfReader(strSourcePdfPath);
stamper = new PdfStamper(reader, bos);
// byte[] ownerPassword = "12345".getBytes();
// int permissions = PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_MODIFY_CONTENTS|PdfWriter.ALLOW_PRINTING;
// stamper.setEncryption(null, ownerPassword, PdfWriter.ALLOW_MODIFY_CONTENTS, false);
// stamper.setEncryption(null, null, permissions,false);
int total = reader.getNumberOfPages();
PdfContentByte waterMar;
PdfGState gs = new PdfGState();
long startTime = System.currentTimeMillis();
log.info("PDF加图片水印>> start");
for (int i = 1; i <= total; i++) {
waterMar = stamper.getOverContent(i);
// 设置图片透明度
gs.setFillOpacity(floatAlpha);
// 设置笔触字体不透明度
gs.setStrokeOpacity(floatAlpha);
waterMar.saveState();
waterMar.restoreState();
// 开始水印处理
waterMar.beginText();
// 设置水印颜色
waterMar.setColorFill(BaseColor.GRAY);
// 设置透明度
waterMar.setGState(gs);
com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(strIconPath);
// 设置旋转弧度
// image.setRotation(40);// 旋转 弧度
// 设置旋转角度
image.setRotationDegrees(intDegree);// 旋转 角度
// 边框固定
//image.scaleToFit(200, 200);
// 设置等比缩放
image.scalePercent(scalePercent*100);
// 自定义大小
//image.scaleAbsolute(70,70);
/***让插入图片水印居中**************/
float w = image.getScaledWidth();
float h = image.getScaledHeight();
float x, y;
com.itextpdf.text.Rectangle pagesize = reader.getPageSizeWithRotation(i);
x = (pagesize.getLeft() + pagesize.getRight()) / 2;
y = (pagesize.getTop() + pagesize.getBottom()) / 2;
// 水印图片位置
image.setAbsolutePosition(x - (w / 2), y - (h / 2));
/***让插入图片水印居中**************/
// 附件加上水印图片
waterMar.addImage(image);
// 完成水印添加
waterMar.endText();
// stroke
waterMar.stroke();
}
long endTime = System.currentTimeMillis();
log.info("PDF加图片水印>> ok 所用时间:[{}]",(endTime-startTime)+"ms");
} catch (Exception e) {
log.error("", e);
return false;
} finally {
try {
if (stamper != null) {
stamper.close();
}
if (reader != null) {
reader.close();
}
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
/**
* 给PDF平铺添加图片水印、可设置水印图片旋转角度
*
* @param strIconPath 水印图片路径
* @param strSourcePdfPath 源文件路径
* @param strTargetPdfPath 目标文件路径
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 旋转角度
* @param scalePercent 缩放比例
*/
public static boolean waterMarkByItextPdf(String strIconPath, String strSourcePdfPath, String strTargetPdfPath,
float floatAlpha, int intDegree, float scalePercent) {
if (floatAlpha == 0) {
floatAlpha = 0.5f;
}
if (scalePercent == 0) {
scalePercent = 1.0f;
}
BufferedOutputStream bos = null;
PdfReader reader = null;
PdfStamper stamper = null;
try {
File file = new File(strTargetPdfPath);
if (!file.exists()) {
FileUtil.file(file);
}
bos = new BufferedOutputStream(new FileOutputStream(file));
reader = new PdfReader(strSourcePdfPath);
stamper = new PdfStamper(reader, bos);
int total = reader.getNumberOfPages();
PdfContentByte waterMar;
PdfGState gs = new PdfGState();
long startTime = System.currentTimeMillis();
log.info("PDF加图片水印>> start");
for (int i = 1; i <= total; i++) {
waterMar = stamper.getOverContent(i);
// 设置图片透明度
gs.setFillOpacity(floatAlpha);
// 设置笔触字体不透明度
gs.setStrokeOpacity(floatAlpha);
waterMar.saveState();
// 开始水印处理
waterMar.beginText();
// 设置水印颜色
waterMar.setColorFill(BaseColor.GRAY);
// 设置透明度
waterMar.setGState(gs);
com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(strIconPath);
float h = image.getWidth();
for (int k = 0; k <= 10; k++) {//列数
// 获取旋转实例
for (int j = 0; j < 20; j++) {//行数
// 水印图片位置
image.setAbsolutePosition(k * h * 2, j * h);
// 设置旋转弧度
image.setRotation(40);// 旋转 弧度
// 设置旋转角度
image.setRotationDegrees(intDegree);// 旋转 角度
// 边框固定
// image.scaleToFit(200, 200);
// 设置等比缩放
image.scalePercent(scalePercent*100);
// 自定义大小
// image.scaleAbsolute(70,70);
// 附件加上水印图片
waterMar.addImage(image);
}
}
// 完成水印添加
waterMar.endText();
// stroke
waterMar.stroke();
}
long endTime = System.currentTimeMillis();
log.info("PDF加图片水印>> ok 所用时间:[{}]",(endTime-startTime)+"ms");
} catch (Exception e) {
log.error("", e);
return false;
} finally {
try {
if (stamper != null) {
stamper.close();
}
if (reader != null) {
reader.close();
}
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
/**
* 给PDF添加平铺水印文字、可设置水印文字的旋转角度
*
* @param strSourcePdfPath 源文件路径和文件名
* @param strTargetPdfPath 加水印完毕后的新图片路径和文件名
* @param strWaterMarkText 水印文字内容
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 文字旋转角度
* @param strFontName 字体名称。默认“宋体”
* @param intFontSize 字号。例如,90
* @param color 字体颜色。
* @return
*/
public static boolean waterMarkByText4Pdf(String strSourcePdfPath, String strTargetPdfPath,
String strWaterMarkText,
float floatAlpha, Integer intDegree,
String strFontName, Integer intFontSize, Color color) {
File fileInputPdf = new File(strSourcePdfPath);
strTargetPdfPath = strTargetPdfPath.replaceAll("\\\\", "/");
try {
//打开pdf文件
PDDocument pdDocument = Loader.loadPDF(fileInputPdf);
pdDocument.setAllSecurityToBeRemoved(true);
// 水印文字字体
if (strFontName == null || "".equals(strFontName)) {
strFontName = "STSONG.TTF";
}
// 水印透明度
if (floatAlpha == 0) {
floatAlpha = 0.5f;
}
// 水印文字大小
if (intFontSize == null) {
intFontSize = 40;
}
float floatFontSize = intFontSize;
File file = new File(strSourcePdfPath);
PDDocument doc = Loader.loadPDF(file);
PDFont pdfFont = PDType0Font.load(doc, new FileInputStream(System.getProperty("user.dir") + "/font/" + strFontName), true);
// 设置透明度
PDExtendedGraphicsState pdExtGfxState = new PDExtendedGraphicsState();
pdExtGfxState.setNonStrokingAlphaConstant(floatAlpha);
pdExtGfxState.setAlphaSourceFlag(true);
pdExtGfxState.getCOSObject().setItem(COSName.BM, COSName.MULTIPLY);
for (int i = 0; i < doc.getNumberOfPages(); i++) {
PDPage page = doc.getPage(i);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);
contentStream.setGraphicsStateParameters(pdExtGfxState);
// 水印颜色
contentStream.setNonStrokingColor(color);
contentStream.beginText();
// 设置字体大小
contentStream.setFont(pdfFont, floatFontSize);
// 根据水印文字大小长度计算横向坐标需要渲染几次水印
float h = strWaterMarkText.length() * floatFontSize;
for (int k = 0; k <= 10; k++) {
for (int j = 0; j < 20; j++) {
// 获取旋转实例
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(intDegree), k * h * 2, j * h));
contentStream.showText(strWaterMarkText);
}
}
contentStream.endText();
contentStream.restoreGraphicsState();
contentStream.close();
}
doc.save(strTargetPdfPath);
doc.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 给PDF添加定点单水印文字、可设置水印文字的旋转角度
*
* @param strSourcePdfPath 源文件路径和文件名
* @param strTargetPdfPath 加水印完毕后的新图片路径和文件名
* @param strWaterMarkText 水印文字内容
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 文字旋转角度
* @param strFontName 字体名称。默认“宋体”
* @param intFontSize 字号。例如,90
* @param color 字体颜色。
* @return
*/
public static boolean waterMarkByText4Pdf(String strSourcePdfPath, String strTargetPdfPath,
String strWaterMarkText,
float floatAlpha, Integer intDegree,
String strFontName, Integer intFontSize, Color color,
Integer intIconLocateX, Integer intIconLocateY) {
if (intIconLocateX == null) {
intIconLocateX = 500;
}
if (intIconLocateY == null) {
intIconLocateY = 500;
}
File fileInputPdf = new File(strSourcePdfPath);
strTargetPdfPath = strTargetPdfPath.replaceAll("\\\\", "/");
try {
//打开pdf文件
PDDocument pdDocument = Loader.loadPDF(fileInputPdf);
pdDocument.setAllSecurityToBeRemoved(true);
// 水印文字字体
if (strFontName == null || "".equals(strFontName)) {
strFontName = "simsun.ttc";
}
// 水印透明度
if (floatAlpha == 0) {
floatAlpha = 0.5f;
}
// 水印文字大小
if (intFontSize == null) {
intFontSize = 40;
}
float floatFontSize = intFontSize;
File file = new File(strSourcePdfPath);
PDDocument doc = Loader.loadPDF(file);
PDFont pdfFont = PDType0Font.load(doc, new FileInputStream(System.getProperty("user.dir") + "/font/" + strFontName), true);
// 设置透明度
PDExtendedGraphicsState pdExtGfxState = new PDExtendedGraphicsState();
pdExtGfxState.setNonStrokingAlphaConstant(floatAlpha);
pdExtGfxState.setAlphaSourceFlag(true);
pdExtGfxState.getCOSObject().setItem(COSName.BM, COSName.MULTIPLY);
for (int i = 0; i < doc.getNumberOfPages(); i++) {
PDPage page = doc.getPage(i);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);
contentStream.setGraphicsStateParameters(pdExtGfxState);
// 水印颜色
contentStream.setNonStrokingColor(color);
contentStream.beginText();
// 设置字体大小
contentStream.setFont(pdfFont, floatFontSize);
// 获取旋转实例
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(intDegree), intIconLocateX, intIconLocateY));
contentStream.showText(strWaterMarkText);
contentStream.endText();
contentStream.restoreGraphicsState();
contentStream.close();
}
doc.save(strTargetPdfPath);
doc.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* ItextPdf实现 给PDF添加平铺水印文字、可设置水印文字的旋转角度
*
* @param strSourcePdfPath 源文件路径和文件名
* @param strTargetPdfPath 加水印完毕后的新图片路径和文件名
* @param strWaterMarkText 水印文字内容
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 文字旋转角度
* @param strFontName 字体名称。默认“宋体”
* @param intFontSize 字号。例如,90
* @param color 字体颜色。
* @return
*/
public static boolean waterMarkByITextPdf(String strSourcePdfPath, String strTargetPdfPath,
String strWaterMarkText,
float floatAlpha, Integer intDegree,
String strFontName, Integer intFontSize, BaseColor color) {
boolean result = true;
BufferedOutputStream bos = null;
PdfReader reader = null;
PdfStamper stamper = null;
try {
File file = new File(strTargetPdfPath);
if (!file.exists()) {
FileUtil.file(file);
}
bos = new BufferedOutputStream(new FileOutputStream(file));
reader = new PdfReader(strSourcePdfPath);
stamper = new PdfStamper(reader, bos);
int total = reader.getNumberOfPages();
PdfContentByte waterMar;
PdfGState gs = new PdfGState();
long startTime = System.currentTimeMillis();
log.info("PDF加图片水印>> start");
for (int i = 1; i <= total; i++) {
waterMar = stamper.getOverContent(i);
// 设置图片透明度
gs.setFillOpacity(floatAlpha);
// 设置笔触字体不透明度
gs.setStrokeOpacity(floatAlpha);
waterMar.saveState();
// 开始水印处理
waterMar.beginText();
// 设置水印颜色
waterMar.setColorFill(color);
// 设置透明度
waterMar.setGState(gs);
// 设置水印字体参数及大小
//模板文件地址
String fontDest = null;
try {
//根据操作系统的不同,获取不同的上传路径
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){
fontDest = ResourceUtils.getURL("classpath:font/").getPath().substring(1);
}else {
fontDest = ResourceUtils.getURL("classpath:font/").getPath();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// waterMar.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED), intFontSize);
// BaseFont bfChinese_H = BaseFont.createFont(System.getProperty("user.dir") + "/font/simsun.ttc,0", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
BaseFont bfChinese_H = BaseFont.createFont("D:\\gitworks\\shanghai\\bdcDataShare\\bdcDataSharePro\\target\\classes\\font\\simkai.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
waterMar.setFontAndSize(bfChinese_H,intFontSize);
waterMar.setTextMatrix(20, 100);
float h = strWaterMarkText.length() * intFontSize;
for (int k = 0; k <= 10; k++) {//列数
// 获取旋转实例
for (int j = 0; j < 20; j++) {//行数
//设置水印对齐方式 水印内容 X坐标 Y坐标 旋转角度
waterMar.showTextAligned(Element.ALIGN_CENTER, strWaterMarkText, k * h * 2, j * h, intDegree);
}
}
// 完成水印添加
waterMar.endText();
// stroke
waterMar.stroke();
}
long endTime = System.currentTimeMillis();
log.info("PDF加图片水印>> ok 所用时间:[{}]",(endTime-startTime)+"ms");
} catch (Exception e) {
log.error("", e);
result = false;
} finally {
try {
if (stamper != null) {
stamper.close();
}
if (reader != null) {
reader.close();
}
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
/**
* 给PDF添加定点单水印文字、可设置水印文字的旋转角度
*
* @param strSourcePdfPath 源文件路径和文件名
* @param strTargetPdfPath 加水印完毕后的新图片路径和文件名
* @param strWaterMarkText 水印文字内容
* @param floatAlpha 透明度,小数。例如,0.7f
* @param intDegree 文字旋转角度
* @param strFontName 字体名称。默认“宋体”
* @param intFontSize 字号。例如,90
* @param color 字体颜色。
* @return
*/
public static boolean oneWaterMarkByITextPdf(String strSourcePdfPath, String strTargetPdfPath,
String strWaterMarkText,
float floatAlpha, Integer intDegree,
String strFontName, Integer intFontSize, BaseColor color) {//,Integer intIconLocateX, Integer intIconLocateY
intDegree = intDegree * -1;
boolean result = true;
// if (intIconLocateX == null) {
// intIconLocateX = 500;
// }
// if (intIconLocateY == null) {
// intIconLocateY = 500;
// }
BufferedOutputStream bos = null;
PdfReader reader = null;
PdfStamper stamper = null;
try {
File file = new File(strTargetPdfPath);
if (!file.exists()) {
FileUtil.file(file);
}
bos = new BufferedOutputStream(new FileOutputStream(file));
reader = new PdfReader(strSourcePdfPath);
stamper = new PdfStamper(reader, bos);
int total = reader.getNumberOfPages();
PdfContentByte waterMar;
PdfGState gs = new PdfGState();
long startTime = System.currentTimeMillis();
log.info("PDF加图片水印>> start");
// 设置水印字体参数及大小
//模板文件地址
String fontDest = null;
try {
//根据操作系统的不同,获取不同的上传路径
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){
fontDest = ResourceUtils.getURL("classpath:font/").getPath().substring(1);
}else {
fontDest = ResourceUtils.getURL("classpath:font/").getPath();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// waterMar.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED), intFontSize);
BaseFont bfChinese_H = BaseFont.createFont(fontDest + getFont(strFontName), BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
// BaseFont bfChinese_H = BaseFont.createFont("D:\\gitworks\\shanghai\\bdcDataShare\\bdcDataSharePro\\target\\classes\\font\\STXINGKA.TTF", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
for (int i = 1; i <= total; i++) {
waterMar = stamper.getOverContent(i);
// 设置图片透明度
gs.setFillOpacity(floatAlpha);
// 设置笔触字体不透明度
gs.setStrokeOpacity(floatAlpha);
waterMar.saveState();
// 开始水印处理
waterMar.beginText();
// 设置水印颜色
waterMar.setColorFill(color);
// 设置透明度
waterMar.setGState(gs);
waterMar.setFontAndSize(bfChinese_H,intFontSize);
/***让插入文字水印居中**************/
float w = strWaterMarkText.length() * intFontSize;;
float h = intFontSize;
float x, y;
com.itextpdf.text.Rectangle pagesize = reader.getPageSizeWithRotation(i);
x = (pagesize.getLeft() + pagesize.getRight()) / 2;
y = (pagesize.getTop() + pagesize.getBottom()) / 2;
// 设置水印对齐方式 水印内容 X坐标 Y坐标 旋转角度
waterMar.showTextAligned(Element.ALIGN_CENTER, strWaterMarkText, x, y, intDegree);
/***让插入文字水印居中**************/
// 完成水印添加
waterMar.endText();
// stroke
waterMar.stroke();
}
long endTime = System.currentTimeMillis();
log.info("PDF加图片水印>> ok 所用时间:[{}]",(endTime-startTime)+"ms");
} catch (Exception e) {
log.error("", e);
result = false;
} finally {
try {
if (stamper != null) {
stamper.close();
}
if (reader != null) {
reader.close();
}
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
private static String getFont(String fontName){
Map<String,String> fontMap = new HashMap<>();
fontMap.put("仿宋","simfang.ttf");
fontMap.put("微软雅黑","msyh.ttc,0");
fontMap.put("宋体","simsun.ttc,0");
fontMap.put("新宋体","simsun.ttc,1");
fontMap.put("楷体","simkai.ttf");
fontMap.put("华文彩云","STCAIYUN.TTF");
fontMap.put("等线","Deng.ttf");
fontMap.put("黑体","simhei.ttf");
fontMap.put("Arial","arial.ttf");
fontMap.put("Microsoft Himalaya","himalaya.ttf");
fontMap.put("Microsoft JhengHei UI","msjh.ttc,1");
fontMap.put("Microsoft JhengHei","msjh.ttc,0");
fontMap.put("Microsoft New Tai Lue","ntailu.ttf");
fontMap.put("Microsoft PhagsPa","phagspa.ttf");
fontMap.put("Microsoft Sans Serif","micross.ttf");
fontMap.put("Microsoft Tai Le","taile.ttf");
fontMap.put("Microsoft YaHei UI","msyh.ttc,1");
fontMap.put("Microsoft Yi Baiti","msyi.ttf");
String fontVal = fontMap.get(fontName);
if(StringUtil.isBlank(fontVal)){
fontVal = "simsun.ttc,0";
}
return fontVal;
}
/**
* 根据文字生成png图片,并返回图片路径
*
* @param strWaterMarkText 水印文字内容
* @param font 字体(Font对象)
* @param colorFont 字体颜色(Color对象)
* @param intDegree 旋转角度,整数
* @param strWaterMarkPng 水印文件路径和文件名
* @return 水印文件的File对象
*/
public static File createWaterMarkPng(String strWaterMarkText, Font font, Color colorFont, Integer intDegree, String strWaterMarkPng) {
JLabel label = new JLabel(strWaterMarkText);
FontMetrics metrics = label.getFontMetrics(font);
int intTextWidth = metrics.stringWidth(label.getText());//文字水印的宽
int intTextLength = strWaterMarkText.length();
int intOneTextWidth = intTextWidth / intTextLength;
// 单个字斜边长
BigDecimal bdTextLength = BigDecimal.valueOf(intOneTextWidth);
Map<String, BigDecimal> mapTextGougu = getGouGu(bdTextLength, intDegree);
// 对边长
BigDecimal bdTextWidth = mapTextGougu.get("bdGou");
int intOneTextX = bdTextWidth.intValue();
// 临边长
BigDecimal bdTextHeight = mapTextGougu.get("bdGu");
int intOneTextY = bdTextHeight.intValue();
// 斜边长
BigDecimal bdLength = BigDecimal.valueOf(intTextWidth);
Map<String, BigDecimal> mapGougu = getGouGu(bdLength, intDegree);
// 对边长
BigDecimal bdHight = mapGougu.get("bdGou");
int intHight = bdHight.intValue() + intOneTextWidth;
// 临边长
BigDecimal bdWidth = mapGougu.get("bdGu");
int intWidth = bdWidth.intValue() + intOneTextWidth;
// 创建图片
BufferedImage image = new BufferedImage(intWidth, intHight, BufferedImage.TYPE_INT_BGR);
Graphics2D g = image.createGraphics();
// 设置透明
image = g.getDeviceConfiguration().createCompatibleImage(intWidth, intHight, Transparency.TRANSLUCENT);
g = image.createGraphics();
// 设置字体
g.setFont(font);
// 设置字体颜色
g.setColor(colorFont);
// 设置对线段的锯齿状边缘处理
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (null != intDegree) {
// 设置水印旋转
g.rotate(Math.toRadians(intDegree));
}
// 图片的高 除以 文字水印的宽 ——> 打印的行数(以文字水印的宽为间隔)
int intRowsNumber = intHight / intTextWidth;
// 图片的宽 除以 文字水印的宽 ——> 每行打印的列数(以文字水印的宽为间隔)
int intColumnsNumber = intWidth / intTextWidth;
// 防止图片太小而文字水印太长,所以至少打印一次
if (intRowsNumber < 1) {
intRowsNumber = 1;
}
if (intColumnsNumber < 1) {
intColumnsNumber = 1;
}
for (int j = 0; j < intRowsNumber; j++) {
for (int i = 0; i < intColumnsNumber; i++) {
// 画出水印,并设置水印位置
g.drawString(strWaterMarkText,
i * intTextWidth + j * intTextWidth + intOneTextX,
-i * intTextWidth + j * intTextWidth + intOneTextY);
}
}
g.dispose();
File fileWaterMarkPng = new File(strWaterMarkPng);
try {
// 输出png图片
ImageIO.write(image, "png", fileWaterMarkPng);
} catch (IOException e) {
e.printStackTrace();
}
return fileWaterMarkPng;
}
/**
* 勾股定理,通过斜边长度、角度,计算对边(勾)和临边(股)的长度
*
* @param bdXian 斜边(弦)长度
* @param intDegree 斜边角度
* @return Map对象,bdGou:对边(勾)长度;dbGu:临边(股)长度
*/
private static Map<String, BigDecimal> getGouGu(BigDecimal bdXian, int intDegree) {
Map<String, BigDecimal> mapReturn = new HashMap<>();
// 角度转换为弧度制
double dblRadians = Math.toRadians(intDegree);
// 正弦值
BigDecimal bdSin = BigDecimal.valueOf(Math.sin(dblRadians));
// 四舍五入保留2位小数
bdSin = bdSin.setScale(2, BigDecimal.ROUND_HALF_UP);
// 对边(勾)长
BigDecimal bdGou = bdXian.multiply(bdSin);
mapReturn.put("bdGou", bdGou);
//余弦值
BigDecimal bdCos = BigDecimal.valueOf(Math.cos(dblRadians));
//四舍五入保留2位小数
bdCos = bdCos.setScale(2, BigDecimal.ROUND_HALF_UP);
// 临边(股)长
BigDecimal bdGu = bdXian.multiply(bdCos);
mapReturn.put("bdGu", bdGu);
return mapReturn;
}
/**
* 为OFD添加图片水印
*
* @param strWaterMarkIcon 水印图片文件路径和文件名
* @param strInputFile 输入的OFD文件
* @param strOutputFile 输出的OFD文件(加水印)
* @param dblAlpha 透明度
* @param intDegree 旋转角度
* @param dblIconLocateX 水印X轴位置
* @param dblIconLocateY 水印Y轴位置
* @param dblIconWidth 水印宽度
* @param dblIconHeight 水印高度
* @return
*/
public static boolean waterMarkByIcon4Ofd(String strWaterMarkIcon, String strInputFile, String strOutputFile,
double dblAlpha, Integer intDegree,
double dblIconLocateX, double dblIconLocateY,
double dblIconWidth, double dblIconHeight) {
Path pathInput = Paths.get(strInputFile);
Path pathOutput = Paths.get(strOutputFile);
Path pathIcon = Paths.get(strWaterMarkIcon);
try (OFDReader reader = new OFDReader(pathInput);
OFDDoc ofdDoc = new OFDDoc(reader, pathOutput)) {
int intPages = reader.getNumberOfPages();
Double dblWidth = ofdDoc.getPageLayout().getWidth();
Double dblHeight = ofdDoc.getPageLayout().getHeight();
Annotation annotation = new Annotation(new ST_Box(0d, 0d, dblWidth, dblHeight), AnnotType.Watermark, ctx -> {
ctx.setGlobalAlpha(dblAlpha);
ctx.save();
ctx.rotate(-intDegree);
ctx.drawImage(pathIcon,
dblIconLocateX, dblIconLocateY,
dblIconWidth, dblIconHeight);
ctx.restore();
});
for (int i = 1; i <= intPages; i++) {
ofdDoc.addAnnotation(i, annotation);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 为OFD文件添加文字水印
*
* @param strInputFile 输入文件路径和文件名
* @param strOutputFile 输出文件路径和文件名(完成加水印)
* @param strWaterMarkText 水印文字内容
* @param floatFontSize 字号
* @param dblAlpha 透明度
* @param colorFont 文字颜色
* @param intDegree 旋转角度
* @throws IOException
*/
public static boolean waterMarkByText4Ofd(String strInputFile, String strOutputFile,
String strWaterMarkText,
float floatFontSize, double dblAlpha, Color colorFont,
Integer intDegree) {
Path pathInput = Paths.get(strInputFile);
Path pathOutput = Paths.get(strOutputFile);
float h = strWaterMarkText.length() * floatFontSize;
try (OFDReader reader = new OFDReader(pathInput);
OFDDoc ofdDoc = new OFDDoc(reader, pathOutput)) {
int intPages = reader.getNumberOfPages();
double dblWidth = ofdDoc.getPageLayout().getWidth();
double dblHeight = ofdDoc.getPageLayout().getHeight();
final double dblBorderLength = Math.max(dblHeight, dblWidth);
Annotation annotation = new Annotation(new ST_Box(0d, 0d, dblBorderLength, dblBorderLength), AnnotType.Watermark, ctx -> {
FontSetting setting = new FontSetting(floatFontSize, FontName.SimSun.font());
ctx.setFillColor(colorFont.getRed(), colorFont.getGreen(), colorFont.getBlue())
.setFont(setting)
.setGlobalAlpha(dblAlpha);
//对ofd页面填充4行10列的水印,并顺时针旋转45°
for (int i = 0; i < dblBorderLength/h ; i++) {// 每行打印次数
for (int j = 0; j < dblBorderLength/20; j++) { // 打印的行数
ctx.save();
ctx.rotate(-intDegree);
ctx.translate(40 * i, j * 20); // 控制x、y轴间距
ctx.fillText(strWaterMarkText, i * h - dblBorderLength , j * h -dblBorderLength);
ctx.restore();
}
}
});
for (int i = 1; i <= intPages; i++) {
ofdDoc.addAnnotation(i, annotation);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 给图片添加水印、可设置水印图片旋转角度
*
* @param iconPath 水印图片路径
* @param srcImgPath 源图片路径
* @param targerPath 目标图片路径
* @param degree 水印图片旋转角度
* @param width 宽度(与左相比)
* @param height 高度(与顶相比)
* @param clarity 透明度(小于1的数)越接近0越透明
*/
public static void waterMarkImageByIcon(String iconPath, String srcImgPath,
String targerPath, Integer degree, Integer width, Integer height,
float clarity) {
OutputStream os = null;
try {
Image srcImg = ImageIO.read(new File(srcImgPath));
System.out.println("width:" + srcImg.getWidth(null));
System.out.println("height:" + srcImg.getHeight(null));
BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),
srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB);
// 得到画笔对象
// Graphics g= buffImg.getGraphics();
Graphics2D g = buffImg.createGraphics();
// 设置对线段的锯齿状边缘处理
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(
srcImg.getScaledInstance(srcImg.getWidth(null),
srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0,
null);
if (null != degree) {
// 设置水印旋转
g.rotate(Math.toRadians(degree),
(double) buffImg.getWidth() / 2,
(double) buffImg.getHeight() / 2);
}
// 水印图象的路径 水印一般为gif或者png的,这样可设置透明度
ImageIcon imgIcon = new ImageIcon(iconPath);
// 得到Image对象。
Image img = imgIcon.getImage();
float alpha = clarity; // 透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
alpha));
// 表示水印图片的位置
g.drawImage(img, width, height, null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
g.dispose();
os = new FileOutputStream(targerPath);
// 生成图片
ImageIO.write(buffImg, "JPG", os);
System.out.println("添加水印图片完成!");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != os) {
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//pdf转成image
public static boolean pdfToImage(String pdfFile, String targerPath){
boolean result = true;
File file = new File(pdfFile);
try {
PDDocument doc = Loader.loadPDF(file);
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for (int i = 0; i < pageCount; i++) {
// 方式1,第二个参数是设置缩放比(即像素)
//BufferedImage image = renderer.renderImageWithDPI(i, 296);
// 方式2,第二个参数是设置缩放比(即像素)
BufferedImage image = renderer.renderImage(i, 2.5f);
ImageIO.write(image, "PNG", new File(targerPath));
}
} catch (IOException e) {
e.printStackTrace();
result = false;
}
return result;
}
/**
* pdf添加水印
* @param inputFile 需要添加水印的文件
* @param outputFile 添加完水印的文件存放路径
* @param waterMarkName 需要添加的水印文字
* @param opacity 水印字体透明度
* @param fontsize 水印字体大小
* @param angle 水印倾斜角度(0-360)
* @param heightDensity 数值越大每页竖向水印越少
* @param widthDensity 数值越大每页横向水印越少
* @param cover 是否覆盖
* @return
*/
public static boolean addWaterMark(String inputFile, String outputFile, String waterMarkName,
float opacity, int fontsize, int angle, int heightDensity, int widthDensity,boolean cover) {
if (!cover){
File file=new File(outputFile);
if (file.exists()){
return true;
}
}
File file=new File(inputFile);
if (!file.exists()){
return false;
}
PdfReader reader = null;
PdfStamper stamper = null;
try {
int interval = -5;
reader = new PdfReader(inputFile);
stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
com.itextpdf.text.Rectangle pageRect = null;
PdfGState gs = new PdfGState();
//这里是透明度设置
gs.setFillOpacity(opacity);
//这里是条纹不透明度
gs.setStrokeOpacity(0.2f);
int total = reader.getNumberOfPages() + 1;
System.out.println("Pdf页数:" + reader.getNumberOfPages());
JLabel label = new JLabel();
FontMetrics metrics;
int textH = 0;
int textW = 0;
label.setText(waterMarkName);
metrics = label.getFontMetrics(label.getFont());
//字符串的高, 只和字体有关
textH = metrics.getHeight();
//字符串的宽
textW = metrics.stringWidth(label.getText());
PdfContentByte under;
//循环PDF,每页添加水印
for (int i = 1; i < total; i++) {
pageRect = reader.getPageSizeWithRotation(i);
under = stamper.getOverContent(i); //在内容上方添加水印
//under = stamper.getUnderContent(i); //在内容下方添加水印
under.saveState();
under.setGState(gs);
under.beginText();
//under.setColorFill(BaseColor.PINK); //添加文字颜色 不能动态改变 放弃使用
under.setFontAndSize(base, fontsize); //这里是水印字体大小
for (int height = textH; height < pageRect.getHeight() * 2; height = height + textH * heightDensity) {
for (int width = textW; width < pageRect.getWidth() * 1.5 + textW; width = width + textW * widthDensity) {
// rotation:倾斜角度
under.showTextAligned(Element.ALIGN_CENTER, waterMarkName, width - textW, height - textH, angle);
}
}
//添加水印文字
under.endText();
}
System.out.println("添加水印成功!");
return true;
} catch (IOException e) {
System.out.println("添加水印失败!错误信息为: " + e);
e.printStackTrace();
return false;
} catch (DocumentException e) {
System.out.println("添加水印失败!错误信息为: " + e);
e.printStackTrace();
return false;
} finally {
//关闭流
if (stamper != null) {
try {
stamper.close();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
reader.close();
}
}
}
}
注意:本文归作者所有,未经作者允许,不得转载