Java实现 itext PDF文件打印水印(文字和图片水印)
itext PDF文件打印水印
前言:公司有个需求,打印的合同模板要加上水印,但是由于itext版本问题,网上千篇一律的方法基本都没办法有效使用,然后自己琢磨下,记录下实现水印的功能的笔记。多页上都加上水印,核心就是加上自定义处理器实现水印功能.
PS: 这个也不是适用于itextpdf的所有版本,项目中引用的版本是: com.itextpdf:kernel:7.2.3,如其他版本不适用请自行调整代码
1.实现文字水印
实现的效果:水印加上透明度,不影响原先的内容,文字45度倾斜,文体是自定义字体,然后就是平铺真个整个页面。
TextWatermarkEventHandler
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class TextWatermarkEventHandler implements IEventHandler {private String watermarkText;private PdfFont font;private float fontSize;private static final float WIDTH_SPACING = 20;private static final float HEIGHT_SPACING = 130;private static final float ANGLE = 45;private static final float TRANSPARENCY = 0.3f;// 构造函数,传入水印文字、字体、大小、水平间距、垂直间距和旋转角度public TextWatermarkEventHandler(String text, PdfFont font, float fontSize) {this.watermarkText = text;this.font = font;this.fontSize = fontSize;}@Overridepublic void handleEvent(Event event) {PdfDocumentEvent docEvent = (PdfDocumentEvent) event;PdfDocument pdfDoc = docEvent.getDocument();PdfPage page = docEvent.getPage();// 获取页面大小Rectangle pageSize = page.getPageSize();PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);// 计算可用的页面宽度和高度float availableWidth = pageSize.getWidth();float availableHeight = pageSize.getHeight();// 创建图形状态并设置透明度PdfExtGState gState = new PdfExtGState();gState.setFillOpacity(TRANSPARENCY); // 设置透明度为 0.3// 文字的宽度float textWidth = font.getWidth(watermarkText, fontSize);// 调整初始绘制位置float startXOffset = -textWidth; // 从负数开始float startYOffset = -availableWidth;  // 从负数开始// 绘制每一行水印文字for (float startY = startYOffset; startY < availableHeight + fontSize; startY += fontSize + HEIGHT_SPACING) {// 保存当前画布状态,确保透明度只影响水印canvas.saveState();// 设置透明度,仅影响水印canvas.setExtGState(gState);// 设置字体和大小canvas.setFontAndSize(font, fontSize);// 设置文字颜色(灰色水印)canvas.setFillColor(ColorConstants.LIGHT_GRAY);// 整行旋转canvas.concatMatrix((float) Math.cos(Math.toRadians(ANGLE)), (float) Math.sin(Math.toRadians(ANGLE)),(float) -Math.sin(Math.toRadians(ANGLE)), (float) Math.cos(Math.toRadians(ANGLE)),0, startY);// 绘制这一行的文字水印for (float x = startXOffset; x < availableWidth + textWidth; x += textWidth + WIDTH_SPACING) {canvas.beginText();canvas.moveText(x, 0);canvas.showText(watermarkText);canvas.endText();}// 恢复画布状态,确保透明度只影响水印canvas.restoreState();}// 释放画布资源canvas.release();}
}
调用TextWatermarkEventHandler监听器
// 自定义字体
String fontPath = WebUtils.getClasspath()+ File.separator+ "static" + File.separator + "font" + File.separator+"simsun.ttf";
PdfFont watermarkFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
TextWatermarkEventHandler watermarkEventHandler = new TextWatermarkEventHandler("你是个大聪明呀",watermarkFont,30);
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, watermarkEventHandler);
实现的效果(截取部分)

2.实现图片水印
实现的效果:水印加上透明度,不影响原先的内容,图片45度倾斜,图片进行缩放处理,然后就是平铺真个整个页面。(ps:此处的图片是经过缩放处理后的图片了)
ImageWatermarkEventHandler
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class ImageWatermarkEventHandler implements IEventHandler {private String imagePath;private static final float SCALE = 1;private static final float WIDTH_SPACING = 20;private static final float HEIGHT_SPACING = 130;private static final float ANGLE = 45;private static final float TRANSPARENCY = 0.3f;// 构造函数,传入水印图片路径public ImageWatermarkEventHandler(String imagePath) {this.imagePath = imagePath;}@Overridepublic void handleEvent(Event event) {// 获取事件类型PdfDocumentEvent docEvent = (PdfDocumentEvent) event;PdfDocument pdfDoc = docEvent.getDocument();PdfPage page = docEvent.getPage();// 获取页面尺寸Rectangle pageSize = page.getPageSize();PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);ImageData imageData = null;try {imageData = ImageDataFactory.create(imagePath);PdfImageXObject watermarkImage = new PdfImageXObject(imageData);// 获取图片的原始宽高,按比例缩放float imgWidth = watermarkImage.getWidth() ;float imgHeight = watermarkImage.getHeight() ;// 计算可用的页面宽度和高度float availableWidth = pageSize.getWidth();
//            float availableHeight = pageSize.getHeight();// 创建图形状态并设置透明度PdfExtGState gState = new PdfExtGState();gState.setFillOpacity(TRANSPARENCY); // 设置透明度为 0.3// 在页面上平铺水印图片for (float y = -availableWidth; y < pageSize.getHeight()*2; y += imgHeight + HEIGHT_SPACING) {for (float x = 0; x < pageSize.getWidth()*2; x += imgWidth + WIDTH_SPACING) {// 保存当前的画布状态canvas.saveState();// 设置水印的透明度canvas.setExtGState(gState);// 将图片水印旋转canvas.concatMatrix(Math.cos(Math.toRadians(ANGLE)),Math.sin(Math.toRadians(ANGLE)),-Math.sin(Math.toRadians(ANGLE)), Math.cos(Math.toRadians(ANGLE)),0, 0); // 旋转canvas.addXObjectAt(watermarkImage, x, y); // x, y 位置// 恢复画布状态canvas.restoreState();}}// 结束页面修改canvas.release();} catch (Exception e) {log.error("pdf添加水印报错:{}",e.getMessage());}}
}
调用TextWatermarkEventHandler监听器
String watermarkImagePath = WebUtils.getClasspath()+ File.separator+ "static" + File.separator + "image" + File.separator+"xxxx.jpg";
ImageWatermarkEventHandler watermarkEventHandler = new ImageWatermarkEventHandler(watermarkImagePath);
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, watermarkEventHandler);
实现的效果(截取部分)

相关文章:
 
Java实现 itext PDF文件打印水印(文字和图片水印)
itext PDF文件打印水印 前言:公司有个需求,打印的合同模板要加上水印,但是由于itext版本问题,网上千篇一律的方法基本都没办法有效使用,然后自己琢磨下,记录下实现水印的功能的笔记。多页上都加上水印&…...
 
面经之一:Synchronized与ReentrantLock区别
Synchronized与ReentrantLock是Java中用于实现线程同步的两种主要机制,它们各有特点和适用场景。以下是它们的主要区别: 实现方式: Synchronized:是Java语言内置的关键字,通过JVM层面的监视器(Monitor&…...
 
论文速读:面向单阶段跨域检测的域自适应YOLO(ACML2021)
原文标题:Domain Adaptive YOLO for One-Stage Cross-Domain Detection 中文标题:面向单阶段跨域检测的域自适应YOLO 1、Abstract 域转移是目标检测器在实际应用中推广的主要挑战。两级检测器的域自适应新兴技术有助于解决这个问题。然而,两…...
React中在map遍历中,给虚拟标签(<></>)加key
有时我们可能会需要在遍历时使用虚拟标签包裹内容,而不使用实际标签 ,这种时候会有一个问题,就是虚拟标签无法加key,这样控制台会一直有警告。 {[1,2,3,4].map(v><><div></div><div></div><…...
大数据生态守护:Hadoop的深度保护策略
PART 1 从Hadoop运行原理透视数据保护需求 1、Hadoop的定义与范畴 Hadoop,狭义而言,是一个专为大数据设计的分布式存储与计算平台,其核心组件包括HDFS(Hadoop分布式文件系统)、MapReduce(分布式计算框架&a…...
代码欣赏之:此题易错在 a+b 非要写成 a-fabs(b).因为这样就成了浮点值了,得不到准确数
代码欣赏之:此题易错在 ab 非要写成 a-fabs(b).因为这样就成了浮点值了,得不到准确数 7-23 小孩子才做选择,大人全都要 #include<stdio.h> #include<math.h> int main() {int a,b;scanf("%d %d",&a,&b);if(a&…...
 
ECharts饼图-环形图,附视频讲解与代码下载
引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我将带大家一起实现一个饼图图表,通过该图表我们可以直观地展示和分析数据。此外,我还将提供详…...
 
arcgis js 怎么加载geoserver发布的wms服务
arcgis js api加载wms服务,官方的参考样例: WMSLayer | Sample Code | ArcGIS Maps SDK for JavaScript 4.30 | Esri Developer 按照官方样例加载比较奇怪,我们平常习惯用url或者json的方式加载,稍微改一下就行,如下…...
 
前端_006_Vue2
文章目录 vue常用属性生命周期模版语法自定义组件全局注册 单文件组件路由 本文全部参考Vue2 简介:Vue是一个数据响应式,MVVM模型的JS框架 官网:https://v2.cn.vuejs.org/v2/guide/ API:https://v2.cn.vuejs.org/v2/api/#method…...
论多端数据互通网游的架构评估
摘要 在2023年,笔者参与了一款多端数据互通网络游戏的架构评估工作,并担任评估团队的核心成员。该游戏支持PC、移动设备和游戏机等多种终端,实现了数据的实时互通。本文通过该项目的评估实践,探讨了多端数据互通网游架构评估的关…...
 
网页HTML编写练习:华语榜中榜
网页效果 HTML代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice…...
C++ 编程基础:深入理解 `pair`(键值对) 和 `unordered_map`(无序映射)
C 编程基础:深入理解 pair(键值对) 和 unordered_map(无序映射) 在 C 标准库中,pair(键值对)和 unordered_map(无序映射)是两种常用的数据结构,它…...
 
高德动态地图
1.搭建页面结构 <div class"dataAllBorder02" style"position: relative; overflow: hidden;"><div class"map_title_box" style"height: 6%"><div class"map_title_innerbox"><div class"map_t…...
 
springboot集成camunda学习与使用
springboot集成camunda学习与使用.md 0、前言一、Spring Boot 集成camunda流程引擎1.新建全新的springboot工程2.添加pom.xml依赖3.启动Spring Boot工程4.切换成mysql数据库5.设计并部署一个BPMN流程6.camunda流程引擎测试6.1 通过camunda web控制台测试6.2 通过camunda rest接…...
 
微服务架构学习笔记
#1024程序员节|征文# 微服务架构作为现代软件开发中的热门技术架构,因其灵活性和可扩展性,逐渐成为许多企业系统设计的首选。以下是关于微服务的一些学习笔记,涵盖微服务的核心概念、优缺点、设计原则以及常用工具等方面。 1. 微服务是什么&…...
代码优化之简化if臃肿的判断条件
简化if判断条件 方法1: #include <iostream> #include <vector> #include <functional>// 封装参数的结构体 struct ConditionParams {int facenum;double zoomRatio;int iso;double facelv;int face_w;double qualityScore;int xx;int yy; };//…...
 
【OpenAI】第六节(语音生成与语音识别技术)从 ChatGPT 到 Whisper 的全方位指南
前言 在人工智能的浪潮中,语音识别技术正逐渐成为我们日常生活中不可或缺的一部分。随着 OpenAI 的 Whisper 模型的推出,语音转文本的过程变得前所未有的简单和高效。无论是从 YouTube 视频中提取信息,还是将播客内容转化为文本,…...
Docker 下备份恢复oracle
1.docker导出容器镜像 ##docker save -o 导出后的镜像名称.tar 容器名称|镜像id docker save -o oracle_11g.tar 3fa112fd3642 2.下载镜像上传镜像略 3.加载镜像 ##docker load -i <archive_file> docker load -i oracle11g11201.tar 4.添加版本号…...
oneplus3t-android_framework
0.确认oneplus6 root正常 oneplus6 root材料 oneplus6手机恢复出厂设置 , 或者 线刷 enchilada_22_K.52_210716_repack--HOS-10.0.11.zip : https://gitee.com/OnePlus6-brick-enchilada_22_K_52_210716_repack-HOS-10_0_11-zip OnePlus6Hydrogen_22…...
 
偷懒总结篇|贪心算法|动态规划|单调栈|图论
由于这周来不及了,先过一遍后面的思路,具体实现等下周再开始详细写。 贪心算法 这个图非常好 122.买卖股票的最佳时机 II(妙,拆分利润) 把利润分解为每天为单位的维度,需要收集每天的正利润就可以,收集正利润的区间…...
 
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
 
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
 
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
 
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
 
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
