利用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.rhkb.cn/news/465279.html

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

相关文章

如何区分实例化网格中的每个实例

1)如何区分实例化网格中的每个实例 2)项目在模拟器上切换程序后有概率画面冻结 3)Unity工程导入团结引擎,GUID会变化,导致引用关系丢失 4)Mask在Android平台下渲染异常 这是第407篇UWA技术知识分享的推送&a…

前端前置——ajax

目标:使用axios库,获取省份列表数据,展示到页面上 axios库地址:https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js 省份数据地址:http://hmajax.itheima.net/api/province axios的使用 axios({ url:目标资源地…

oasys系统代码审计

简述: oasys是一个OA办公自动化系统,使用Maven进行项目管理,基于springboot框架开发的项目,mysql底层数据库,前端采用freemarker模板引擎,Bootstrap作为前端UI框架,集成了jpa、mybatis等框架。…

书生大模型第三关Git 基础知识

关卡编号:L0G3000 任务一 破冰行动 fork仓库,注意这里不要勾选Copy branch Only!!!,因为后面课程中会使用到class分支: 克隆仓库: 移动分支: 创建自己的分支: 创建id.md文档,…

在vue3的vite网络请求报错 [vite] http proxy error:

在开发的过程中 代理proxy报错: [vite] http proxy error: /ranking/hostRank?dateType1 Error: connect ETIMEDOUT 43.xxx.xxx.xxx:443 网络请求是http的: // vite.config.ts import { Agent } from node:http;server: {host: 0.0.0.0,port: port,open: true,https: false,…

初识HTML

什么是HTML呢? HTML是超文本标记语言,HTML代码是由“标签”构成的 超文本:文本、声音、图片、视频、表格、链接 标记:由许许多多的标签组成 HTML页面是运行到浏览器上面的 第一个HTML程序 和C语言从hello world开始一样 HTML可…

DevOps-课堂笔记

各种 aaS 类比于计算机网络的 OSI 参考模型,一个软件应用项目需要不同的支撑层,例如从下至上大概需要: 硬件层面的服务器针对硬件做弹性分配的虚拟化机制,例如虚拟机在虚拟化环境内运行的 OS支撑软件应用的中间件,例…

AnatoMask的分层图像编码器-解码器

方法思想 采用多尺度编码器-解码器主干: 在编码器中,把CT图像分解成不同大小的图像块,从这些图像块中提取特征在解码器中,重建被掩盖图像时,考虑图像块的空间关系 输入D(深度Depth)张H&#x…

C++ 之boost/date_time/posix_time高精度计时详细总结

文章目录 概要时间长度类time_duration时间点ptime时间区域time_period时间迭代器实际应用1:(计算加速度)实际应用2:可以支持秒级和微秒/纳秒级计时器 概要 使用date_time库需要在编译时加上"-lboost_date_time"&#x…

小语言模型介绍与LLM的比较

小模型介绍 小语言模型(SLM)与大语言模型(LLM)相比,具有不同的特点和应用场景。大语言模型通常拥有大量的参数(如 GPT-3 拥有 1750 亿个参数),能够处理复杂的自然语言任务&#xff…

Kafka 可观测性最佳实践

Kafka 概述 Kafka 是由 LinkedIn 开发一个分布式的基于发布订阅模式的消息队列,是一个实时数据处理系统,可以横向扩展。与 RabbitMQ、RockerMQ 等中间件一样拥有几大特点: 异步处理服务解耦流量削峰 监控 Kafka 是非常重要的,因…

混合式学习平台:企业培训的新选择

在当前的商业环境中,企业普遍采用在线直播课程进行员工培训。然而,在线学习常常伴随着焦虑、疲劳和效率低下等问题,这些都是企业在进行在线培训时需要面对和解决的挑战。本文将探讨如何通过使用白板协作工具——即时白板,来提高企…

内网项目,maven本地仓库离线打包,解决Cannot access central in offline mode?

背景&#xff1a; 内网项目打包&#xff0c;解决Cannot access central in offline mode? 1、修改maven配置文件&#xff1a; localRepository改为本地仓库位置 <localRepository>D:\WorkSpace\WorkSoft\maven-repository\iwhalecloud-repository\business</loca…

如何用 ChatPaper.ai 打造完美的 AI 课堂笔记系统

作为学生&#xff0c;我们都遇到过这样的困扰&#xff1a;上课时记笔记太投入就听不进讲解&#xff0c;专注听讲又担心错过重要知识点。有了AI助手&#xff0c;这个问题就可以优雅地解决了。今天跟大家分享如何用ChatPaper.ai构建个人的智能课堂笔记系统。 为什么需要AI辅助记笔…

雷池社区版 7.1.0 LTS 发布了

LTS&#xff08;Long Term Support&#xff0c;长期支持版本&#xff09;是软件开发中的一个概念&#xff0c;表示该版本将获得较长时间的支持和更新&#xff0c;通常包含稳定性、性能改进和安全修复&#xff0c;但不包含频繁的新特性更新。 作为最受欢迎的社区waf&#xff0c…

C语言心型代码解析

方法一 心型极坐标方程 爱心代码你真的理解吗 笛卡尔的心型公式&#xff1a; for (y 1.5; y > -1.5; y - 0.1) for (x -1.5; x < 1.5; x 0.05) 代码里面用了二个for循环&#xff0c;第一个代表y轴&#xff0c;第二个代表x轴 二个增加的单位不同&#xff0c;能使得…

【云原生开发】如何通过client-go来操作K8S集群

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

开源协议类型及长安链开源协议介绍

截至目前&#xff0c;我国参与国际开源社区协作的开发者数量排名全球第二并推出了众多社区活跃度较高的高质量开源项目&#xff0c;是全球开源生态的重要贡献力量&#xff0c;但在开源治理方面我国还处于发展初期&#xff0c;大部分开发者对开源的印象还限于开放代码、免费使用…

计算机网络:网络层 —— 边界网关协议 BGP

文章目录 路由选择协议动态路由协议边界网关协议 BGPBGP 的基本概念BGP-4 的四种报文 路由选择协议 因特网是全球最大的互联网&#xff0c;它所采取的路由选择协议具有以下三个主要特点&#xff1a; 自适应&#xff1a;因特网采用动态路由选择&#xff0c;能较好地适应网络状态…

Kubernetes——part9-2 kubernetes集群java项目上云部署

一、部署前准备工作 1.1 部署项目情况 1.1.1 业务部署架构 单体服务架构分布式服务架构微服务架构超微服务架构 1.1.2 项目涉及第三方服务 关系型数据库系统 MySQL缓存服务 Redis memcache协调服务 zookeeper消息中间件服务 kafka rabbitmq服务注册 服务发现 nacos 1.1.3…