【DuodooBMS】给PDF附件加“受控”水印的完整Python实现
给PDF附件加“受控”水印的完整Python实现
功能需求
在实际工作中,许多文件需要添加水印以标识其状态,例如“受控”“机密”等。对于PDF文件,添加水印不仅可以增强文件的可识别性,还可以防止未经授权的使用。本代码的功能需求是:
-
修复PDF文件:在添加水印之前,确保PDF文件是完整且可读的,避免因文件损坏导致操作失败。
-
添加水印:在PDF的每一页上添加指定的水印图像或文字,水印可以设置位置、角度和透明度。
-
保存输出:将添加水印后的PDF文件保存到指定路径,并返回其二进制数据以便后续处理。

实现过程
-
修复PDF文件
-
使用
PyMuPDF库打开PDF文件,并尝试修复。如果文件损坏,PyMuPDF可以尝试修复并保存为一个新的二进制流。 -
如果修复失败,则直接返回原始的PDF二进制数据。
Python复制
def repair_pdf(self, input_pdf_binary):try:# 使用 PyMuPDF 打开并修复 PDFdoc = fitz.open(stream=input_pdf_binary, filetype="pdf")repaired_pdf_binary = BytesIO()doc.save(repaired_pdf_binary)doc.close()repaired_pdf_binary.seek(0)return repaired_pdf_binary.read()except Exception as e:print(f"Error repairing PDF: {e}")return input_pdf_binary -
-
添加水印
-
使用
reportlab库创建一个临时的PDF文件作为水印。水印可以是图像或文字,支持设置位置、角度和透明度。 -
使用
PyPDF2库将水印PDF与原始PDF合并。通过merge_page方法,将水印添加到每一页。
Python复制
def add_watermark(self, input_pdf_binary, output_pdf, watermark_image, x_position=30, y_position=50, opacity=1):# 尝试修复 PDFrepaired_pdf_binary = self.repair_pdf(input_pdf_binary)input_pdf_obj = PdfReader(BytesIO(repaired_pdf_binary)) # 从二进制数据中读取 PDFoutput_pdf_obj = PdfWriter()output_buffer = BytesIO()# 创建一个临时的 PDF 作为水印page_width, page_height = A4[1], A4[0]c = canvas.Canvas(output_buffer, pagesize=(page_width, page_height))try:c.setFillColor(colors.white) # 将背景设置为白色c.setFillColor(colors.red) # 设置字体颜色为红色c.setFont("Helvetica", 12) # 设置字体和字体大小c.setFillAlpha(opacity) # 设置透明度c.setStrokeColor(colors.transparent) # 设置笔触颜色为透明img = ImageReader(watermark_image)if x_position is not None and y_position is not None:c.saveState()c.translate(x_position, y_position)c.rotate(20)c.drawImage(img, 0, 0, width=60, height=25)c.restoreState()else:x = (page_width - 60) / 2y = (page_height - 25) / 2c.saveState()c.translate(x, y)c.rotate(20)c.drawImage(img, 0, 0, width=60, height=25)c.restoreState()except Exception as e:raise ValueError(f"Error drawing image: {e}")c.showPage()c.save()# 将水印 PDF 与原始 PDF 合并watermark_pdf = PdfReader(output_buffer)for page in input_pdf_obj.pages:page.merge_page(watermark_pdf.pages[0])output_pdf_obj.add_page(page)# 保存输出 PDFfinal_output_buffer = BytesIO()output_pdf_obj.write(final_output_buffer)binary_data = final_output_buffer.getvalue()with open(output_pdf, 'wb') as f:output_pdf_obj.write(f)return binary_data -
-
调用示例
-
准备一个PDF文件和一个水印图像文件。
-
调用
add_watermark方法,指定输入PDF、输出路径、水印图像路径等参数。
Python复制
if __name__ == "__main__":from io import BytesIOfrom PyPDF2 import PdfReader, PdfWriterfrom reportlab.pdfgen import canvasfrom reportlab.lib.pagesizes import A4from reportlab.lib import colorsfrom reportlab.lib.utils import ImageReaderimport fitzclass WatermarkPDF:def repair_pdf(self, input_pdf_binary):try:doc = fitz.open(stream=input_pdf_binary, filetype="pdf")repaired_pdf_binary = BytesIO()doc.save(repaired_pdf_binary)doc.close()repaired_pdf_binary.seek(0)return repaired_pdf_binary.read()except Exception as e:print(f"Error repairing PDF: {e}")return input_pdf_binarydef add_watermark(self, input_pdf_binary, output_pdf, watermark_image, x_position=30, y_position=50, opacity=1):repaired_pdf_binary = self.repair_pdf(input_pdf_binary)input_pdf_obj = PdfReader(BytesIO(repaired_pdf_binary))output_pdf_obj = PdfWriter()output_buffer = BytesIO()page_width, page_height = A4[1], A4[0]c = canvas.Canvas(output_buffer, pagesize=(page_width, page_height))try:c.setFillColor(colors.white)c.setFillColor(colors.red)c.setFont("Helvetica", 12)c.setFillAlpha(opacity)c.setStrokeColor(colors.transparent)img = ImageReader(watermark_image)if x_position is not None and y_position is not None:c.saveState()c.translate(x_position, y_position)c.rotate(20)c.drawImage(img, 0, 0, width=60, height=25)c.restoreState()else:x = (page_width - 60) / 2y = (page_height - 25) / 2c.saveState()c.translate(x, y)c.rotate(20)c.drawImage(img, 0, 0, width=60, height=25)c.restoreState()except Exception as e:raise ValueError(f"Error drawing image: {e}")c.showPage()c.save()watermark_pdf = PdfReader(output_buffer)for page in input_pdf_obj.pages:page.merge_page(watermark_pdf.pages[0])output_pdf_obj.add_page(page)final_output_buffer = BytesIO()output_pdf_obj.write(final_output_buffer)binary_data = final_output_buffer.getvalue()with open(output_pdf, 'wb') as f:output_pdf_obj.write(f)return binary_data# 示例调用watermark_pdf = WatermarkPDF()with open("example.pdf", "rb") as f:input_pdf_binary = f.read()watermark_image = "watermark.png"output_pdf = "output_with_watermark.pdf"watermark_pdf.add_watermark(input_pdf_binary, output_pdf, watermark_image) -
实现总结
本代码通过PyMuPDF修复PDF文件,使用reportlab创建水印PDF,并通过PyPDF2将水印合并到原始PDF中。整个过程支持自定义水印的位置、角度和透明度,能够灵活地满足不同场景的需求。代码结构清晰,易于扩展和维护,适合在实际项目中使用。
让转型不迷航——邹工转型手札
相关文章:
【DuodooBMS】给PDF附件加“受控”水印的完整Python实现
给PDF附件加“受控”水印的完整Python实现 功能需求 在实际工作中,许多文件需要添加水印以标识其状态,例如“受控”“机密”等。对于PDF文件,添加水印不仅可以增强文件的可识别性,还可以防止未经授权的使用。本代码的功能需求是…...
GitCode 助力 Dora SSR:开启游戏开发新征程
项目仓库(点击阅读原文链接可直达) https://gitcode.com/ippclub/Dora-SSR 跨越技术藩篱,构建游戏开发乐园 Dora SSR 是一款致力于打破游戏开发技术壁垒的开源游戏引擎。其诞生源于开发者对简化跨平台游戏开发环境搭建的强烈渴望࿰…...
Mediamtx+Python读取webrtc流
一、功能思路: 1、我采用ffmpeg -re -stream_loop -1 -i xcc.mp4 -c:v libx264 -profile:v baseline -x264opts "bframes0:repeat_headers1" -b:v 1500k -preset fast -f flv rtmp://127.0.0.1:1835/stream/111推流到mediamtx的rtmp上 2、通过mediamtx自…...
每日一题——矩阵最长递增路径
矩阵最长递增路径问题 题目描述数据范围:进阶要求:示例示例 1示例 2 题解思路算法步骤:代码实现代码解释复杂度分析总结 题目描述 给定一个 n 行 m 列的矩阵 matrix,矩阵内所有数均为非负整数。你需要在矩阵中找到一条最长路径&a…...
【CLIP系列】4:目标检测(ViLD、GLIP)
目录 1 ViLD2 GLIP2.1 前言2.2 损失计算2.3 模型框架 1 ViLD OPEN-VOCABULARY OBJECT DETECTION VIA VISION AND LANGUAGE KNOWLEDGE DISTILLATION 从标题就能看出来,作者是把CLIP模型当成一个Teacher,去蒸馏他自己的网络,从而能Zero Shot去…...
Cesium for Unity Linux版本
Cesium for Unity 直装不支持Linux 参照官方开发流程一些操作命令issues 宝藏最后运行图 参照官方开发流程 https://github.com/CesiumGS/cesium-unity/blob/main/Documentation~/developer-setup.md 系统已经安装过dotnet和cmake xuefeixuefei:~$ dotnet --version 9.0.102 …...
Spring Boot过滤器链:从入门到精通
文章目录 一、过滤器链是什么?二、为什么需要过滤器链?三、Spring Boot中的过滤器链是如何工作的?(一)过滤器的生命周期(二)过滤器链的执行流程 四、如何在Spring Boot中定义自己的过滤器&#…...
关于 IoT DC3 中驱动(Driver)的理解
在开源IoT DC3物联网系统中,驱动(Driver)扮演着至关重要的角色,它充当了软件系统与物理设备之间的桥梁。驱动的主要功能是依据特定的通信协议连接到设备,并根据设备模板中配置的位号信息进行数据采集和指令控制。不同的…...
微信小程序地图标记点,安卓手机一次性渲染不出来的问题
问题描述: 如果微信小程序端,渲染的标记物太多,安卓手机存在标记物不显示的问题,原因初步判断是地图还没有渲染完,标记物数据已经加载完了,导致没有在地图上显示。 解决办法: 使用map组件的b…...
一维差分与二维差分
差分(Difference)是一种与前缀和密切相关的技术,主要用于高效处理区间更新操作。差分数组的核心思想是通过记录相邻元素的差值来表示原数组的变化,从而将区间更新操作的时间复杂度从 O(n) 优化到 O(1)。下面详细讲解一维差分和二维…...
EasyRTC嵌入式WebRTC视频通话SDK支持Web浏览器、Linux、ARM、Android、iOS
随着互联网技术的飞速发展,实时通信(RTC)已经成为现代应用中不可或缺的一部分。无论是视频会议、在线教育、远程医疗,还是社交娱乐,实时通信技术都在其中扮演着重要角色。 然而,WebRTC技术在PC和移动端的支…...
数据库脚本MySQL8转MySQL5
由于生产服务器版本上部署的是MySQL5,而开发手里的脚本代码是MySQL8。所以只能降版本了… 升级版本与降级版本脚本转换逻辑一样 MySQL5与MySQL8版本SQL脚本区别 大多数无需调整、主要是字符集与排序规则 MySQL5与MySQL8版本SQL字符集与排序规则 主要操作&…...
【PGCCC】commit_delay 对性能的提升:PostgreSQL 基准测试
通过禁用参数可以来调整事务工作负载synchronous_commit。该措施有惊人效果。但在操作系统崩溃期间丢失已提交事务的可能性使其成为许多应用程序无法启动的因素。因此我决定写下来。 WAL 刷新是事务数据库工作负载的瓶颈 为了确保已提交的事务不会丢失,PostgreSQL…...
AI大模型随机初始化权重并打印网络结构方法(以Deepseekv3为例,单机可跑)
背景 当前大模型的权重加载和调用,主要是通过在HuggingFace官网下载并使用transformer的库来加以实现;其中大模型的权重文件较大(部分>100GB),若只是快速研究网络结构和数据流变化,则无需下载权重。本文…...
字符串解码——巧妙使用递归解题
题目描述 给定一个经过编码的字符串,返回它解码后的字符串。编码规则为 k[encoded_string],表示方括号内部的 encoded_string 重复 k 次。其中 k 是正整数,输入字符串确保符合格式要求且无额外空格。 示例: 复制 示例 1&#…...
Flask Web开发的重要概念和示例
一口气列举Flask Web应用的所有概念和示例 Flask Web 应用基本框架 路由(Routing) 模版(Template) request 对象 JSON 数据处理 redirect 示例 文件上传示例 文件下载示例 Session 示例 Cookie操作 Flask Web 应用基本框架 这是一个 最基础的 Flask Web 应用,…...
51-ArrayList
51-ArrayList Collection 类型介绍 仓颉中常用的几种基础 Collection 类型,包含 Array、ArrayList、HashSet、HashMap。 可以在不同的场景中选择适合对应业务的类型: Array:如果不需要增加和删除元素,但需要修改元素ÿ…...
Ollama+WebUI+DeepSeek部署自己的本地大模型
前言 使用AI几乎成为互联网工作者必备技能了,DeepSeek的出现把AI再次推向高潮,在本文中,我们将带领大家借助 Ollama、WebUI 和 deepseek 这三个工具,成功搭建属于自己的本地大模型环境。Ollama 作为一款轻量级的大模型运行工具&a…...
(篇六)基于PyDracula搭建一个深度学习的软件之新版本ultralytics-8.3.28调试
ultralytics-8.3.28版本debug记录 1传入文件 代码太多不粘贴在这里了,完整代码写在了篇三 def open_src_file(self):config_file config/fold.jsonconfig json.load(open(config_file, r, encodingutf-8))open_fold config[open_fold]if not os.path.exists(op…...
NLP Word Embeddings
Word representation One-hot形式 在上一周介绍RNN类模型时,使用了One-hot向量来表示单词的方式。它的缺点是将每个单词视为独立的,算法很难学习到单词之间的关系。 比如下面的例子,即使语言模型已经知道orange juice是常用组合词…...
基于 FPGA 的嵌入式系统硬件逻辑优化技术探究
在数字化浪潮席卷全球的当下,嵌入式系统已然成为众多领域不可或缺的核心力量。从我们日常使用的智能手机、智能穿戴设备等消费电子产品,到关乎工业生产效率与精度的工业控制系统,再到汽车电子领域的自动驾驶辅助系统以及航空航天领域的飞行器…...
使用HX搭建UNI-APP云开发项目(适合新手小白与想学云开发的宝子)
什么是uni-app云开发 uni-app云开发是uni-app提供的一套后端服务,它可以帮助开发者快速搭建起一个完整的后端服务,包括数据库、云函数、存储等。开发者只需要关注前端页面的开发,后端服务由uni-app云开发提供。 uni-app云开发的优势: 快速搭建后端服务:uni-app云开发提供了…...
sql:时间盲注和boolen盲注
关于时间盲注,boolen盲注的后面几个获取表、列、具体数据的函数补全 时间盲注方法 import time import requests# 获取数据库名 def inject_database(url):dataname for i in range(1, 20):low 32high 128mid (low high) // 2while low < high:payload &q…...
【STM32】ADC|多通道ADC采集
本次实现的是ADC实现数字信号与模拟信号的转化,数字信号时不连续的,模拟信号是连续的。 1.ADC转化的原理 模拟-数字转换技术使用的是逐次逼近法,使用二分比较的方法来确定电压值 当单片机对应的参考电压为3.3v时,0~ 3.3v(模拟信…...
arcgis for js实现层叠立体效果
在 Web 开发中,利用 ArcGIS for JS 实现一些炫酷的地图效果能够极大地提升用户体验。本文将详细介绍如何使用 ArcGIS for JS 实现层叠立体效果,并展示最终的效果图。 效果图 实现思路 要实现层叠立体效果,关键在于获取边界图形的坐标…...
多模态本地部署和ollama部署Llama-Vision实现视觉问答
文章目录 一、模型介绍二、预期用途1. 视觉问答(VQA)与视觉推理2. 文档视觉问答(DocVQA)3. 图像字幕4. 图像-文本检索5. 视觉接地 三、本地部署1. 下载模型2. 模型大小3. 运行代码 四、ollama部署1. 安装ollama2. 安装 Llama 3.2 Vision 模型3. 运行 Llama 3.2-Vision 五、效果…...
【DeepSeek】deepseek可视化部署
目录 1 -> 前文 2 -> 部署可视化界面 1 -> 前文 【DeepSeek】DeepSeek概述 | 本地部署deepseek 通过前文可以将deepseek部署到本地使用,可是每次都需要winR输入cmd调出命令行进入到命令模式,输入命令ollama run deepseek-r1:latest。体验很…...
【Git版本控制器】:第一弹——Git初识,Git安装,创建本地仓库,初始化本地仓库,配置config用户名,邮箱信息
🎁个人主页:我们的五年 🔍系列专栏:Linux网络编程 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 相关笔记: https://blog.csdn.net/dj…...
Fabric.js、leaferjs、pixi.js 库的对比分析
文章目录 一、引言二、参与对比的 canvas 库简介三、性能对比四、易用性对比五、功能特性对比六、综合评价与使用建议七、总结 在前端开发中,canvas 库为实现丰富的图形效果和交互功能提供了强大的支持。本文将对 Fabric.js、leaferjs 和 pixi.js 这三个常见的 canv…...
JVM——堆的回收:引用计数发和可达性分析法、五种对象引用
目录 引用计数法和可达性分析法 引用计数法: 可达性分析算法: 五种对象引用 软引用: 弱引用: 引用计数法和可达性分析法 引用计数法: 引用计数法会为每个对象维护一个引用计数器,当对象被引用时加1&…...
