利用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…

十六:Spring Boot依赖 (1)-- spring-boot-starter 依赖详解

1. 简介: spring-boot-starter 是 Spring Boot 项目中的基础启动器依赖,它为开发者提供了 Spring Boot 应用所需的核心功能和自动配置 spring-boot-starter 不是一个具体的功能模块,而是一个基础的启动器。 Spring Boot 提供了一系列的 sta…

leetcode203. Remove Linked List Elements

Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val val, and return the new head. Input: head [1,2,6,3,4,5,6], val 6 Output: [1,2,3,4,5] 递归法 通过递归的方法去删除节点 递归程序会先一路遍历来到节…

【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 NIO实现高性能HTTP代理

NIO采用多路复用IO模型,相比传统BIO(阻塞IO),通过轮询机制检测注册的Channel是否有事件发生,可以实现一个线程处理客户端的多个连接,极大提升了并发性能。 在5年前,本人出于对HTTP正向代理的好…

栈和队列(Java)

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

Angular 和 Vue2.0 对比

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

Android 项目模型配置管理

Android 项目配置管理 项目模型相关的配置管理config.gradle文件:build.gradle文件: 参考地址 项目模型相关的配置管理 以下是一个完整的build.gradle和config.gradle示例: config.gradle文件: ext {// 模型相关配置&#xff0…

前端知识点---Javascript中检测数据类型函数总结

文章目录 01 typeof 运算符02 instanceof 运算符03 Array.isArray()04 Object.prototype.toString.call()05 constructor 属性06 isNaN() 和 Number.isNaN() (常用)07 isFinite() 和 Number.isFinite()08 typeof null 是 "object" 的问题 01 typeof 运算符 返回值是…

MAC 安装 brew及其常用命令

​文章:Mac安装brew的四种方法(指定能行) 以下是在 Mac 上使用 Homebrew 清理缓存和无用包的详细指南: 1. 查看系统状态 # 诊断系统问题 brew doctor# 查看已安装的包 brew list# 查看系统占用空间 brew cleanup -n # 预览需要…

基于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 能够在执行耗…