掌握iText:轻松处理PDF文档-高级篇-添加水印

在这里插入图片描述
在这里插入图片描述

前言

iText作为一个功能强大、灵活且广泛应用的PDF处理工具,在实际项目中发挥着重要作用。通过这些文章,读者可以深入了解如何利用iText进行PDF的创建、编辑、加密和提取文本等操作,为日常开发工作提供了宝贵的参考和指导。

掌握iText:轻松处理PDF文档-基础篇

掌握iText:轻松处理PDF文档-进阶篇

需求描述

可能你会经常遇到类似的场景, 为了保护敏感信息和版权,需要在PDF文件上添加水印,在类似这样的需求上再作一个延伸,可能就是两种情况:第一种,程序在处理数据后,生成新的pdf文档的同时增加水印;第二种,pdf文档已经存在,需要在导出的时候,给已经存在的pdf文档增加水印。那么这两种需求,如果使用iText5,应该怎么实现呢?

iText的依赖

在maven的pom.xml中配置:

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.3</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>

生成新的pdf文档的同时增加水印

程序在处理数据后,生成新的pdf文档的同时增加水印,具体的步骤如下:
1.创建一个大小为A4纸、横向显示的PDF文档。
2.创建PdfWriter对象,用于将文档内容写入到PDF文件中。
3.打开文档。
4.创建第一页(可省略)。
5.获取水印的PdfContentByte对象。
6.调用setWaterMar方法,在水印画布上设置水印内容和样式。
7.循环100次,在文档中添加一段文字。
8.关闭文档和PdfWriter对象。
9.输出成功生成PDF文件的消息。
其中 setWaterMar 方法封装了具体的水印设置逻辑,具体逻辑如下:
1.检查水印画布是否为空。
2.开始设置水印文本。
3.设置水印的透明度。
4.创建PdfGState对象,设置填充字体的不透明度为0.4f。
5.设置水印的字体和大小。
6.设置水印的对齐方式、位置和旋转角度。
7.设置水印的颜色。
8.结束设置水印文本。

// 往pdf文档中写入文本内容时,添加水印
@Test
public void test() throws FileNotFoundException, DocumentException {
    //实现A4纸页面 并且横向显示(不设置则为纵向)
    Document document = new Document(PageSize.A4.rotate());
    PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("e:/pdf-test/test-v1.pdf"));
    // 打开文档
    document.open();
    // 创建第一页(如果只有一页的话,这一步可以省略)
    document.newPage();
    // 加入水印,水印内容:x+y=z
    PdfContentByte waterMar = pdfWriter.getDirectContentUnder();
    this.setWaterMar(waterMar, "x+y=z");
    for (int i = 0; i < 100; i++) {
        // 加入文档内容
        document.add(new Paragraph("my first pdf demo"));
    }
    // 关闭文档
    document.close();
    pdfWriter.close();
}
private void setWaterMar(PdfContentByte waterMar, String waterContent) {
    if (waterMar == null) {
        return;
    }
    // 开始设置水印
    waterMar.beginText();
    // 设置水印透明度
    PdfGState gs = new PdfGState();
    // 设置填充字体不透明度为0.4f
    gs.setFillOpacity(0.4f);
    try {
        // 设置水印字体参数及大小(字体参数,字体编码格式,是否将字体信息嵌入到pdf中(一般不需要嵌入),字体大小)
        waterMar.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED), 60);
        // 设置透明度
        waterMar.setGState(gs);
        // 设置水印对齐方式 水印内容 X坐标 Y坐标 旋转角度
        waterMar.showTextAligned(Element.ALIGN_RIGHT, waterContent, 500, 430, 45);
        // 设置水印颜色
        waterMar.setColorFill(BaseColor.GRAY);
        //结束设置
        waterMar.endText();
        waterMar.stroke();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (DocumentException e) {
        throw new RuntimeException(e);
    }
}

效果如下:
在这里插入图片描述

给已经生成的pdf文档增加水印

1.指定输入和输出的 PDF 文件路径。
2.创建 PdfReader 对象,用于读取原始 PDF 文件。
3.创建 PdfStamper 对象,用于添加水印,并传入原始 PDF 文件和输出 PDF 文件的路径。
4.获取原始 PDF 文件的页数。
5.加载自定义字体 HongLeiXingShuJianTi-2.otf。我这里是从字体天下网(https://www.fonts.net.cn)下载一个字体,可以使用你拥有的其他字体,需要注意字体版权问题,我下载这个是商用免费。
6.设置水印的字体大小和旋转角度。
7.准备向每一页添加水印。
8.循环迭代每一页,获取当前页的 PdfContentByte 对象,即用于绘制内容的画布。
9.调用 setWaterMar 方法,在当前页的画布上添加水印。
10.关闭 PdfStamper 和 PdfReader 对象,释放资源。
11.输出一条成功添加水印的消息。
其中 setWaterMar 方法封装了具体的水印设置逻辑,具体逻辑如下:
1.设置水印的填充颜色为浅灰色。
2.开始绘制文本。
3.设置文本的字体和大小。
4.使用嵌套循环,将水印文本重复添加到当前页的多个位置上。
5.结束绘制文本。

@Test
public void test2() {
    try {
        // 输入PDF文件路径
        String inputFile = "e:/pdf-test/test.pdf";
        // 输出PDF文件路径
        String outputFile = "e:/pdf-test/test-v2.pdf";
        // 创建PdfReader对象读取原始PDF文件
        PdfReader reader = new PdfReader(inputFile);
        // 创建PdfStamper对象,用于添加水印
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
        // 设置水印属性
        int n = reader.getNumberOfPages();
        URL resource = getClass().getClassLoader().getResource("HongLeiXingShuJianTi-2.otf");
        FontFactory.register(resource.getPath(), "HongLeiXingShuJianTi-2.otf");
        BaseFont baseFont = BaseFont.createFont("HongLeiXingShuJianTi-2.otf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        float fontSize = 20; // 设置字体大小
        float watermarkAngle = 10; // 设置水印旋转角度
        PdfContentByte watermark;
        // 添加水印到每一页
        for (int i = 1; i <= n; i++) {
            watermark = stamper.getOverContent(i);
            this.setWaterMar(watermark, "凡夫编程", baseFont, fontSize, watermarkAngle);
        }
        // 关闭PdfStamper和PdfReader对象
        stamper.close();
        reader.close();
        System.out.println("水印已添加到PDF文档中。");
    } catch (DocumentException | IOException e) {
        e.printStackTrace();
    }
}
private void setWaterMar(PdfContentByte watermark, String waterContent, BaseFont baseFont, float fontSize, float watermarkAngle) {
    watermark.setColorFill(BaseColor.LIGHT_GRAY);
    watermark.beginText();
    watermark.setFontAndSize(baseFont, fontSize);
    for (int m = 0; m < 10; m++) {
        for (int n = 0; n < 10; n++) {
            watermark.showTextAligned(Element.ALIGN_LEFT, "凡夫编程", 10 + m * 150, 10 + n * 100, watermarkAngle);
        }
    }
    watermark.endText();
}

效果如下:
在这里插入图片描述

写入与读取元数据

写入元数据:

1.创建一个空白的PDF文档对象。
2.创建PdfWriter对象,用于将文档内容写入到PDF文件中,并指定输出文件路径。
3.打开文档。
4.向文档中添加一段文字内容。
5.使用addCreator方法设置文档的创建者信息。
6.使用addTitle方法设置文档的标题信息。
7.使用addAuthor方法设置文档的作者信息。
8.关闭文档。

@Test
public void test6() {
    Document document = new Document();
    try {
        // 设置加密算法和用户/所有者密码
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("e:/pdf-test/test-v6.pdf"));
        document.open();
        // 添加一些内容到文档中
        document.add(new Paragraph("This is pdf document."));
        document.addCreator("fanfu");
        document.addTitle("test-pdf");
        document.addAuthor("gaoxing");
        document.close();
    } catch (DocumentException | IOException e) {
        e.printStackTrace();
    }
}

读取元数据:

1.创建一个PdfReader对象,用于读取指定PDF文件("e:/pdf-test/test-v6.pdf")的内容。
2.调用getInfo方法获取PDF文档的元数据信息,并将其存储在一个HashMap对象中。
3.使用for循环遍历HashMap中的键值对,打印每个键对应的值。
@Test
public void test7() {
    try {
        // 设置加密算法和用户/所有者密码
        PdfReader pdfReader = new PdfReader(new FileInputStream("e:/pdf-test/test-v6.pdf"));
        HashMap<String, String> info = pdfReader.getInfo();
        for (String key : info.keySet()) {
            System.out.println(info.get(key));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/240154.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

并发编程-线程等待唤醒机制

目录 前言 ​编辑 线程等待和唤醒的方法 wait() 方法&#xff1a; notify() 方法&#xff1a; 注意事项和建议&#xff1a; 我的其他博客 前言 程等待唤醒机制是多线程编程中用于线程之间协调和通信的一种机制。在多线程环境中&#xff0c;有时候一个线程需要等待某个条件…

【大数据】Doris 架构

Doris 架构 Doris 的架构很简洁&#xff0c;只设 FE&#xff08;Frontend&#xff09;、BE&#xff08;Backend&#xff09;两种角色、两个进程&#xff0c;不依赖于外部组件&#xff0c;方便部署和运维&#xff0c;FE、BE 都可线性扩展。 ✅ Frontend&#xff08;FE&#xff0…

C++_类的定义和使用

目录 1、类的引用 1.1 类的成员函数 1.2 类成员函数的声明和定义 2、类的定义 2.1 类的访问限定&#xff08;封装&#xff09; 3、类重名问题 4、类的实例化 4.1 类的大小 5、隐含的this指针 5.1 空指针问题 结语&#xff1a; 前言&#xff1a; C的类跟c语言中的结…

Standoff 12 网络演习

在 11 月 21 日至 24 日于莫斯科举行的 "Standoff 12 "网络演习中&#xff0c;Positive Technologies 公司再现了其真实基础设施的一部分&#xff0c;包括软件开发、组装和交付的所有流程。安全研究人员能够在安全的环境中测试系统的安全性&#xff0c;并尝试将第三方…

GO闭包实现原理(汇编级讲解)

go语言闭包实现原理(汇编层解析) 1.起因 今天开始学习go语言,在学到go闭包时候,原本以为go闭包的实现方式就是类似于如下cpp lambda value通过值传递,mutable修饰可以让value可以修改,但是地址不可能一样value通过引用传递,但是在其他地方调用时,这个value局部变量早就释放,…

低多边形植物模型法线贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时&#xff0c;有几种不同的风格&#xf…

深度学习在人体动作识别领域的应用:开源工具、数据集资源及趋动云GPU算力不可或缺

人体动作识别检测是一种通过使用计算机视觉和深度学习技术&#xff0c;对人体姿态和动作进行实时监测和分析的技术。该技术旨在从图像或视频中提取有关人体姿态、动作和行为的信息&#xff0c;以便更深入地识别和理解人的活动。 人体动作识别检测的基本步骤包括&#xff1a; 数…

web279(s2-001)

目前java小白一个&#xff0c;主要是学学别人的思路 进入题目&#xff0c;登录框一个 抓包也没发现什么东西 网上说是struts2框架 Struts2是用Java语言编写的一个基于MVC设计模式的Web应用框架 判断是不是基于struts2的一些方法&#xff1a; 1.通过页面回显的错误消息来判断…

MySQL一行记录是怎么存储的?

文章目录 MySQL 一行记录是怎么存储的&#xff1f;MySQL 的数据存放在哪个文件&#xff1f;表空间文件结构 InnoDB行格式有哪些Compact行格式varchar(n) 中 n 最大取值为多少&#xff1f;行溢出后&#xff0c;MySQL是怎么处理的&#xff1f; MySQL 一行记录是怎么存储的&#x…

IDEA 出现问题:git提交commit时Perform code analysis卡住解决方案

问题 git提交commit时Perform code analysis卡住很久 解决方案一 1、打开 IntelliJ IDEA&#xff0c;进入 File -> Settings&#xff08;或者使用快捷键 CtrlAltS&#xff09;。 2、在弹出的 Settings 窗口中&#xff0c;找到 Version Control -> Commit Dialog 选项…

Flink 有状态流式处理

传统批次处理方法 【1】持续收取数据&#xff08;kafka等&#xff09;&#xff0c;以window时间作为划分&#xff0c;划分一个一个的批次档案&#xff08;按照时间或者大小等&#xff09;&#xff1b; 【2】周期性执行批次运算&#xff08;Spark/Stom等&#xff09;&#xff1b…

机器学习---Adaboost算法

1. Adaboost算法介绍 Adaboost是一种迭代算法&#xff0c;其核心思想是针对同一个训练集训练不同的分类器&#xff08;弱分类器&#xff09;&#xff0c;然 后把这些弱分类器集合起来&#xff0c;构成一个更强的最终分类器&#xff08;强分类器&#xff09;。Adaboost算法本身…

CSS学习

CSS学习 1. 什么是css?2.css引入方式2.1 内嵌式2.2 外联式2.3 行内式2.4 引入方式特点 3. 基础选择器3.1 标签选择器3.2 类选择器3.3 id选择器3.4 通配符选择器 1. 什么是css? 2.css引入方式 2.1 内嵌式 2.2 外联式 提示: 需要在html文件中link目标样式表; 2.3 行内式 注意:…

【EventBus】EventBus源码浅析

二、EventBus源码解析 目录 1、EventBus的构造方法2、订阅者注册 2.1 订阅者方法的查找过程2.2 订阅者的注册过程1. subscriptionsByEventType 映射&#xff1a;2. typesBySubscriber 映射&#xff1a;2.3 总结订阅者的注册过程 3、事件的发送 3.1 使用Post提交事件3.2 使用p…

【STM32】DMA直接存储器存取

1 DMA简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 可以直接访问STM32的存储器的&#xff0c;包括运行SRAM、程序存储器Flash和寄存器等等 DMA可以提供外设寄存器和存储器或者存储器和存储器之间的高速数据传输&#xff0c;无须CPU干预&#xff0c;节…

【lombok】从easyExcel read不到值到cglib @Accessors(chain = true)隐藏的大坑

背景: 在一次使用easyExcel.read 读取excel时&#xff0c;发现实体类字段没有值&#xff0c;在反复测试后&#xff0c;发现去掉Accessors(chain true)就正常了&#xff0c;为了验证原因&#xff0c;进行了一次代码跟踪 由于调用链路特别长&#xff0c;只列举出部分代码&#x…

二蛋赠书十一期:《TypeScript入门与区块链项目实战》

前言 大家好&#xff01;我是二蛋&#xff0c;一个热爱技术、乐于分享的工程师。在过去的几年里&#xff0c;我一直通过各种渠道与大家分享技术知识和经验。我深知&#xff0c;每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此&#xff0c;我非常感激大家一直…

【C 剑指offer】有序整型矩阵元素查找 {杨氏矩阵}

目录 题目内容&#xff1a; 思路&#xff1a; 图形演示&#xff1a; 复杂度分析 C源码&#xff1a; /** *************************************************************************** ******************** ********************* ******…

DWA(dynamic window approach)算法学习

系列文章目录 A*算法学习-CSDN博客 弗洛伊德算法&#xff08;Floyd&#xff09;和路径平滑弗洛伊德算法&#xff08;Smooth Floyd&#xff09;学习-CSDN博客 D*算法学习-CSDN博客 目录 系列文章目录 前言 搜索空间 —减小速度搜索空间 优化过程 —最大化目标函数 算法实…

《洛谷深入浅出》斯特林数

斯特林数被分为三种&#xff0c;但我们这只介绍两种。即第一类斯特林数&#xff0c;和第二类斯特拉数。 第一类斯特林数指的是&#xff1a; 将n个不同元素&#xff0c;变成m个圆排列的方案数量。第一类斯特林数&#xff0c;分为有符号和无符号。通常我们只研究无符号斯特林数&…