利用pythonstudio写的PDF、图片批量水印生成器,可同时为不同读者生成多组水印

现在很多场合需要将PDF或图片加水印,本程序利用pythonstudio编写。

第一步 界面

在这里插入图片描述
其中:

LstMask:列表框

  • PopupMenu:PmnMark

LstFiles:列表框

  • PopupMenu:PmnFiles

OdFiles:文件选择器

  • Filter:PDF文件(.PDF)|.PDF|图像文件(.JPG)|.JPG|图像文件(.png)|.png
  • Option-OfAllowMultiSelection:True

其余一眼都能看出来

代码:

模块1:m_water 用来打水印


import os
import iofrom PyPDF2 import PdfWriter, PdfReader
from reportlab.lib import pagesizes  # 页面样式
from reportlab.lib.units import cm
from reportlab.pdfbase import pdfmetrics  # 注册字体
from reportlab.pdfbase.ttfonts import TTFont  # 字体类
from reportlab.pdfgen import canvasfrom watermarker.marker import add_mark
from PIL import Imagepdfmetrics.registerFont(TTFont('SimHei', os.path.join(os.path.dirname(os.path.abspath(__file__)), "bird.ttf")))# 生成水印文件
def create_water_mark(text):packet = io.BytesIO()# 创建一个带有水印的新PDF页my_canvas = canvas.Canvas(packet, pagesizes.A0)# 设置水印字体my_canvas.setFont("SimHei", 40)# 填充色my_canvas.setFillColorRGB(0, 0, 0)# 透明度my_canvas.setFillAlpha(0.1)# 设置字体旋转度数my_canvas.rotate(15)# x轴的3cm处,到24结束,步长是10for i in range(3, 24, 10):# y轴的for j in range(-5, 30, 5):my_canvas.drawString(i * cm, j * cm, text)my_canvas.save()packet.seek(0)return PdfReader(packet)def add_watermark(input_pdf_path, output_pdf_path, watermark_text):# 创建水印watermark = create_water_mark(watermark_text)# 读取输入 PDFpdf_reader = PdfReader(input_pdf_path)pdf_writer = PdfWriter()# 遍历每一页,将水印添加到每一页for page in pdf_reader.pages:page.merge_page(watermark.pages[0])  # 将水印添加到当前页面pdf_writer.add_page(page)# 写入到输出 PDF 文件with open(output_pdf_path, "wb") as output_pdf:pdf_writer.write(output_pdf)def add_pic_watermark(input_jpg_path,out_jpg_path, watermark_text):# 加水印add_mark(file=input_jpg_path,out=out_jpg_path,mark=watermark_text,opacity=0.3,angle=30,space=80)
##    add_mark(file=f"{cwd}\page_{i + 1}.jpg" , out=cwd, mark=EPdf.stamp,opacity=EPdf.tran,angle=30,space=80)def main():passif __name__ == '__main__':main()

模块2:m_zip 用来打包文件

import zipfile
import osdef compress_folder(folder_path, output_path):with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zipf:for root, dirs, files in os.walk(folder_path):for file in files:file_path = os.path.join(root, file)arc_name = os.path.relpath(file_path, folder_path)zipf.write(file_path, arc_name)def main():passcompress_folder("111","111.zip")if __name__ == '__main__':main()

Unit1.py 主界面代码

import os
from glcl import *
from m_water import *
from m_zip import *
import shutilclass Form1(Form):def __init__(self, owner):self.PgbFiles = ProgressBar(self)self.LblStat = Label(self)self.PmnFiles = PopupMenu(self)self.PmnMark = PopupMenu(self)self.OdFiles = OpenDialog(self)self.BtnAddFiles = Button(self)self.Label3 = Label(self)self.Label2 = Label(self)self.BtnClose = Button(self)self.BtnMark = Button(self)self.Label1 = Label(self)self.EdtMark = Edit(self)self.LstFiles = ListBox(self)self.LstMark = ListBox(self)self.BtnBeginMark = Button(self)self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "Unit1.pydfm"))self.BtnClose.OnClick = self.BtnCloseClickself.BtnBeginMark.OnClick = self.BtnBeginMarkClickself.LstFiles.OnClick = self.LstFilesClickself.MniFiles.OnClick = self.MniFilesClickself.PmnFiles.OnPopup = self.PmnFilesPopupself.BtnAddFiles.OnClick = self.BtnAddFilesClickself.MniDel.OnClick = self.MniDelClickself.PmnMark.OnPopup = self.PmnMarkPopupself.BtnMark.OnClick = self.BtnMarkClick# 把水印名加入到列表def BtnMarkClick(self, Sender):# 如果 EDT不为空,则加至列表if self.EdtMark.Text.strip()!="":# 没有重复if self.LstMark.Items.IndexOf(self.EdtMark.Text.strip())>-1:ShowMessage("当前水印已存在,请检查后重新输入。")returnself.LstMark.Items.Add(self.EdtMark.Text.strip())# 清除EDTself.EdtMark.Text=""else:ShowMessage("请先填写需要添加的水印内容。")# 如果水印名有值,就显示删除def PmnMarkPopup(self, Sender):self.MniDel.Enabled=True if self.LstMark.ItemIndex>-1 else False# 如果文件有值,就显示删除def PmnFilesPopup(self, Sender):self.MniDel.Enabled=True if self.LstFiles.ItemIndex>-1 else False# 确认是否要删除水印,然后删除def MniDelClick(self, Sender):if Application.MessageBox("是否要删除"+ self.LstMark.Items[self.LstMark.ItemIndex]+"?","请确认", MB_YESNO)==IDYES:self.LstMark.DeleteSelected()# 确认是否要删除文件,然后删除def MniFilesClick(self, Sender):if Application.MessageBox("是否要删除"+ self.LstFiles.Items[self.LstFiles.ItemIndex]+"?","请确认", MB_YESNO)==IDYES:self.LstFiles.DeleteSelected()# 选择文件并添加到列表中def BtnAddFilesClick(self, Sender):if self.OdFiles.Execute():for item in self.OdFiles.Files:# 如果不重复就添加if self.LstFiles.Items.IndexOf(item)==-1:self.LstFiles.Items.Add(item)# 显示选中项的提示def LstFilesClick(self, Sender):self.LstFiles.Hint=self.LstFiles.Items[self.LstFiles.ItemIndex]# 循环打水印def BtnBeginMarkClick(self, Sender):# 如果没有文件或水印,退出if self.LstFiles.Count==0 or self.LstMark.Count==0:ShowMessage("请确认添加好水印和文件后再进行操作。")return# 将所有按钮都禁用self.BtnAddFiles.Enabled=Falseself.BtnBeginMark.Enabled=Falseself.BtnMark.Enabled=Falseself.BtnClose.Enabled=False# 提示需要较长时间ShowMessage("共有"+str(self.LstFiles.Count * self.LstMark.Count)+"个文件要打水印并打包,所需时间较长,请确认后开始操作。")# 进度条最大值self.PgbFiles.max=self.LstFiles.Count * self.LstMark.Countself.PgbFiles.Position=0self.LblStat.Caption="正在建立文件夹"# 建立以水印名为名字的文件夹try:for folder in self.LstMark.Items:if os.path.exists(folder)==False:os.mkdir(folder)except:ShowMessage("建立文件夹失败")returnself.LblStat.Caption="开始打水印"# 循环水印for mark in self.LstMark.Items:# 循环文件for markfile in self.LstFiles.Items:# 如果是pdf,打PDF水印,存在水印文件夹if markfile[-4:].upper()==".PDF":try:outfilename=os.path.join( mark, markfile[markfile.rfind("\\")+1:])add_watermark(markfile,outfilename,mark)except:ShowMessage(markfile[markfile.rfind("\\")+1:]+"文件建立失败")else:# 如果是图片,打图片水印,存在水印文件夹下try:add_pic_watermark(markfile,mark,mark)except:ShowMessage(markfile[markfile.rfind("\\")+1:]+"文件建立失败")self.PgbFiles.Position+=1# 打包进度self.PgbFiles.Max=self.LstMark.Countself.PgbFiles.Position=0# 所有水印打完后,每个水印文件夹打包if os.path.exists("output")==False:os.mkdir("output")self.LblStat.Caption="开始文件打包"for folder in self.LstMark.Items:compress_folder(folder,"output\\"+folder+".zip")self.PgbFiles.Position+=1# 删除临时文件for folder in self.LstMark.Items:shutil.rmtree(folder)# 恢复所有按钮self.BtnAddFiles.Enabled=Trueself.BtnBeginMark.Enabled=Trueself.BtnMark.Enabled=Trueself.BtnClose.Enabled=Trueself.LblStat.Caption="打水印完成"ShowMessage("打水印、打包完成,请在当前文件夹下检查ZIP文件。")self.LblStat.Caption=""self.LstMark.Clear()self.LstFiles.Clear()def BtnCloseClick(self, Sender):self.Close()

伸手党可直接下载可执行文件
https://download.csdn.net/download/gxchai/89956703

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试:TCP、UDP如何解决丢包问题

文章目录 一、TCP丢包原因、解决办法1.1 TCP为什么会丢包1.2 TCP传输协议如何解决丢包问题1.3 其他丢包情况(拓展)1.4 补充1.4.1 TCP端口号1.4.2 多个TCP请求的逻辑1.4.3 处理大量TCP连接请求的方法1.4.4 总结 二、UDP丢包2.1 UDP协议2.1.1 UDP简介2.1.2…

Python的函数(补充浅拷贝和深拷贝)

一、定义 函数的定义:实现【特定功能】的代码块。 形参:函数定义时的参数,没有实际意义 实参:函数调用/使用时的参数,有实际意义 函数的作用: 简化代码提高代码重用性便于维护和修改提高代码的可扩展性…

Spring Boot框架的知识分类技术解析

2 开发技术 2.1 VUE框架 Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。 Vue 只关注视图层, 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 2.2 Mysql数据库 …

Hive详解

1 Hive基本概念 Hive是一个构建在Hadoop上的数据仓库框架。最初,Hive是由Facebook开发,后来移交由Apache软件基金会开发,并作为一个Apache开源项目。 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据…

llamaIndex和langchain对比及优劣对比

一. LangChain vs LlamaIndex: 基本描述 LlamaIndex在搜索和检索任务方面表现出色。它是一个强大的数据索引和查询工具,非常适合需要高级搜索的项目。LlamaIndex能够处理大型数据集,从而实现快速准确的信息检索。 LangChain是一个模块化和灵活的工具集框…

《重学Java设计模式》之 工厂方法模式

《重学Java设计模式》之 建造者模式 《重学Java设计模式》之 原型模式 《重学Java设计模式》之 单例模式 模拟发奖多种商品 工程结构 奖品发放接口 package com.yys.mes.design.factory.store;public interface ICommodity {/*** Author Sherry* Date 14:20 2024/11/6**/voi…

【C++笔记】string类的模拟实现

前言 各位读者朋友们大家好!上期我们讲解了string类的基础用法,这期我们来模拟实现一下string类。 目录 前言一. string类的构造函数1. 1 无参构造2.2 带参构造1.3 无参和带参构造结合1.4 拷贝构造1.5 c_str 二. string类的析构函数三. 字符串的遍历3.…

java中ArrayList的使用存储对象的易错点

ArrayList存储对象的易错点 上面这种写法是有逻辑问题的,因为只创建了一个Student对象,因此最后打印出来的结果是三个最后赋值的结果。 下面我们来形象看下存储关系 集合中存储的始终是第一个对象的地址,而每次输入新的名字和年龄&#xf…

栈和队列(Java)

一.栈(Stack) 1.定义 栈是限定仅在表尾进行插入或删除操作的线性表 一般的表尾称为栈顶 表头称为栈底 栈具有“后进先出”的特点 2.对栈的模拟 栈主要具有以下功能: push(Object item):将元素item压入栈顶。 pop()&am…

Angular 和 Vue2.0 对比

前言 :“业精于勤,荒于嬉;行成于思,毁于随” 很久没写博客了,大多记录少进一步探查。 Angular 和 Vue2.0 对比: 一.概念 1.1 Angular 框架: 是一款由谷歌开发的开源web前端框架(核…

基于Multisim数字电子秒表0-60S电路(含仿真和报告)

【全套资料.zip】数字电子秒表电路Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.秒表最大计时值为60秒; 2. 2位数码管显示,分辨率为1秒; 3.具有清零…

安卓智能指针sp、wp、RefBase浅析

目录 前言一、RefBase1.1 引用计数机制1.2 设计目的1.3 主要方法1.4 如何使用1.5 小结 二、sp和wp2.1 引用计数机制2.2 设计目的2.3 主要方法2.3.1 sp2.3.2 wp 2.4 如何使用2.5 小结 四、参考链接 前言 安卓底层binder中,为什么 IInterface要继承自RefBase &#x…

【论文笔记】Prefix-Tuning: Optimizing Continuous Prompts for Generation

🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Prefix-Tuning: Optimizin…

【Web前端】从回调到现代Promise与Async/Await

异步编程是一种让程序能够在等待某些操作完成的同时继续执行其他任务的关键技术,打破了传统编程中顺序执行代码的束缚。这种编程范式允许开发者构建出能够即时响应用户操作、高效处理网络请求和资源加载的应用程序。通过异步编程,JavaScript 能够在执行耗…

【CSS】“flex: 1“有什么用?

flex 属性的组成 flex 属性是一个复合属性,包含以下三个子属性: flex-grow:决定元素在容器中剩余空间的分配比例。默认值为 0,表示元素不会扩展。当设置为正数时,元素会按照设定比例扩展。flex-shrink:决…

计算机课程管理:Spring Boot与工程认证的协同创新

3系统分析 3.1可行性分析 通过对本基于工程教育认证的计算机课程管理平台实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于工程教育认证的计算机课程管理平…

【SpringBoot】18 上传文件到数据库(Thymeleaf + MySQL)

Git仓库 https://gitee.com/Lin_DH/system 介绍 使用 Thymeleaf 写的页面&#xff0c;将&#xff08;txt、jpg、png&#xff09;格式文件上传到 MySQL 数据库中。 依赖 pom.xml <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j --><depende…

Sharding运行模式、元数据、持久化详解

运行模式 单机模式 能够将数据源和规则等元数据信息持久化&#xff0c;但无法将元数据同步至多个Sharding实例&#xff0c;无法在集群环境中相互感知。 通过某一实例更新元数据之后&#xff0c;会导致其他实例由于获取不到最新的元数据而产生不一致的错误。 适用于工程师在本…

挖掘web程序中的OAuth漏洞:利用redirect_uri和state参数接管账户

本文探讨了攻击者如何利用OAuth漏洞&#xff0c;重点是滥用redirect_uri和state参数以接管用户账户。如果redirect_uri参数验证不严&#xff0c;可能会导致未经授权的重定向到恶意服务器&#xff0c;从而使攻击者能够捕获敏感信息。同样&#xff0c;state参数的错误实现可能使O…

Python世界:力扣题解1712,将数组分成三个子数组的方案数,中等

Python世界&#xff1a;力扣题解1712&#xff1a;将数组分成三个子数组的方案数&#xff0c;中等 任务背景思路分析代码实现测试套件本文小结 任务背景 问题来自力扣题目1712. Ways to Split Array Into Three Subarrays&#xff0c;大意如下&#xff1a; A split of an intege…