java实现pdf水印详解,支持换行、旋转且样式不会错乱,贼透彻
业务需求代码实现思路效果图本地代码实现一、前期准备二、pdf水印生成简单样例(基础)三、showTextAligned方法解读四、根据需求实现水印
业务需求
在客户点击链接评价完后生成相应评价数据的pdf文件,并且添加水印,水印添加完成后进行第三方签名。水印名称为项目名称,字体默认,字号12,颜色浅灰色,水印文字排列为8 * 3(一行3个水印,一页8行),水印30度旋转,且支持文字换行,换行后文字居中。
代码实现思路
因为是公司项目,为了方便整理成了3步骤实现,第一步生成评价数据的pdf文件,第二步添加水印,第三步进行第三方签名,这篇文章主要分析水印相关的实现和详细步骤拆分,看完自己就可以根据需求定制水印,想放哪儿就放哪儿,怎么好看你就能怎么整。
效果图
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/56d30dcf13e54dc4b756cfbc7dc75462.png)
本地代码实现
一、前期准备
依赖:
com.itextpdf
itextpdf
5.4.3
com.itextpdf
itext-asian
5.2.0
一个pdf文件
二、pdf水印生成简单样例(基础)
public static void main(String[] args) throws Exception {
ReducePdfTestService reducePdfService = new ReducePdfTestService();
reducePdfService.setPdfWaterMarForFileTest("D:/file/todest/",
"test.pdf", "测试水印");
}
/**
* 给已经输出的pdf文件添加水印
* @param filePath
* @param fileName
* @param
* @throws Exception
*/
public void setPdfWaterMarForFileTest(String filePath, String fileName , String waterText) throws Exception {
// 输入PDF文件路径
String inputFile = filePath + fileName;
// 输出PDF文件路径
String outputFile = filePath +"temp_" + fileName;
// 创建PdfReader对象读取原始PDF文件
PdfReader reader = new PdfReader(inputFile);
// 创建PdfStamper对象,用于添加水印
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
// 用于添加水印的主要对象
PdfContentByte waterMar;
// 创建水印字体
BaseFont base = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
// 设置水印透明度
PdfGState gs = new PdfGState();
// 设置填充字体不透明度
gs.setFillOpacity(0.12f);
gs.setStrokeOpacity(0.3f);
// 获取pdf页数
int n = reader.getNumberOfPages();
// 添加水印到每一页
for (int i = 1; i
// 每次增加230px和水印宽度的一半,加水印宽度的一半是让第一个水印距离页面左侧有一些填充,更加美观
float xFloat = x * 230 + (float)(textW / 2);
System.out.println("x坐标为 = " + xFloat);
// x坐标为 = 24.0 x坐标为 = 254.0 x坐标为 = 484.0
waterMar.showTextAligned(Element.ALIGN_LEFT, waterText, xFloat, (float) textH / 2, 0);
}
// 设置水印结束
waterMar.endText();
效果图 之后进行整个页面的水印效果,其实就是在上面的基础上再嵌套一个for循环,动态的改变y的坐标值即可。
// 开始设置水印
waterMar.beginText();
for (int y = 0; y
// 每次增加230px和水印宽度的一半,加水印宽度的一半是让第一个水印距离页面左侧有一些填充,更加美观
float xFloat = x * 230 + (float)(textW / 2);
System.out.println("x坐标为 = " + xFloat);
// 每次增加110px和水印字体高度的2倍,加字体高度2倍也是为了让第一个水印距离页面底部有一些填充
float yFloat = y * 110 + (float) textH * 2;
System.out.println("y坐标为 = " + yFloat);
waterMar.showTextAligned(Element.ALIGN_LEFT, waterText, xFloat, yFloat, 0);
}
}
// 设置水印结束
waterMar.endText();
效果图 之后我们悄悄将最后一个参数改为30,对应需求的旋转30度,基本就实现了效果。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/dad4f7e3b0cb4709b9e7554791c27ea8.png)
你以为到这儿就完了吗?其实好戏才刚刚开始 从实际需求出发,现在的写法有很多问题,第一:如果水印字数过多样式会错乱且没有支持换行;第二:代码过于死板,不灵活,假如现在业务说要求字号变大或者旋转角度、对齐方式改变,我们依旧需要动态调整里面的参数,也就是x和y的坐标值,如果要求排列方式变化那就更麻烦了。 这是水印字体过长时出现的情况,样式错乱,接下来处理换行。 思路:实际上还是对x和y坐标的修改,我们指定一下一行允许展示的最多字数(初版,后期会用宽度进行计算),按照字数进行分割,在加一层for循环即可实现。
分割字符串的方法
public static String[] stringToStringArray(String text, int length) {
//检查参数是否合法
if (StringUtils.isEmpty(text)) {
return null;
}
if (length
if (i
splitArr[i] = text.substring(i * length);
}
}
return splitArr;
}
改造的水印方法
// 开始设置水印
waterMar.beginText();
String[] marTextArray = stringToStringArray(waterText, 15);
for (int y = 0; y
for (int t = 0; t |