使用 Python 和 wxPython 在图片上添加水印

创建一个基于wxPython的简单水印生成器应用程序。该应用程序具有一个窗口,用户可以选择要添加水印的图片文件,并在输入框中输入要显示在图片底部的文字。点击"印章"按钮后,应用程序将在选择的图片上添加水印,并将生成的带有水印的图片保存在当前目录下的"_copy.jpg"文件中。
C:\pythoncode\new\waterprintonphoto.py
在这里插入图片描述

让我们逐行解释代码的不同部分:

import wx
from PIL import Image, ImageDraw, ImageFont

首先,我们导入所需的模块。wx模块是用于创建GUI应用程序的wxPython库,PIL模块是Python Imaging Library,用于处理图像。

import wx
from PIL import Image, ImageDraw, ImageFont
import os

class WatermarkFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="水印生成器", size=(400, 300))

        self.panel = wx.Panel(self)

        # 创建控件
        self.file_picker = wx.FilePickerCtrl(self.panel, message="选择图片文件",
                                             wildcard="Image files (*.jpg;*.png)|*.jpg;*.png")
        self.text_ctrl = wx.TextCtrl(self.panel, value="Winfredzhang")
        self.button = wx.Button(self.panel, label="印章")

        # 设置布局
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.file_picker, proportion=0, flag=wx.EXPAND | wx.ALL, border=10)
        sizer.Add(self.text_ctrl, proportion=0, flag=wx.EXPAND | wx.ALL, border=10)
        sizer.Add(self.button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10)

        self.panel.SetSizer(sizer)

        # 绑定事件处理函数
        self.button.Bind(wx.EVT_BUTTON, self.on_generate_watermark)

    def on_generate_watermark(self, event):
        filepath = self.file_picker.GetPath()
        text = self.text_ctrl.GetValue()

        if filepath and text:
            image = Image.open(filepath)

            # 创建一个绘图对象
            draw = ImageDraw.Draw(image)

            # 加载字体,指定字体大小
            font = ImageFont.truetype("C://Windows//Fonts//arial.ttf", 40)

            # 指定文字的位置,底部居中
            text_width, text_height = draw.textsize(text, font=font)
            image_width, image_height = image.size
            text_x = (image_width - text_width) // 2
            text_y = image_height - text_height - 20  # 20为底部边距

            # 指定文字的颜色,RGB格式
            color = (255, 0, 0)

            # 在图片上绘制文字
            draw.text((text_x, text_y), text, font=font, fill=color)

            # 保存图片
            output_path = "watermarked_image.jpg"
            image.save(output_path)
            # 另存为带有水印的图片
            save_dir, save_filename = os.path.split(filepath)
            save_name, save_ext = os.path.splitext(save_filename)
            save_path = os.path.join(save_dir, save_name + "_copy" + save_ext)
            # watermarked_image.save(save_path)
            # output_path = "watermarked_image.jpg"
            image.save(save_path)




            # 显示成功提示
            wx.MessageBox("水印已添加并另存为watermarked_image.jpg。", "成功", wx.OK | wx.ICON_INFORMATION)

        event.Skip()


if __name__ == '__main__':
    app = wx.App()
    frame = WatermarkFrame()
    frame.Show()
    app.MainLoop()

在这部分代码中,我们定义了一个名为WatermarkFrame的类,该类继承自wx.Frame,用于创建水印生成器的主窗口。__init__方法是该类的构造函数,用于初始化窗口和控件。

在构造函数中,我们首先调用super()来调用父类的构造函数。然后,我们创建一个wx.Panel作为窗口的子面板,并将其设置为窗口的主面板。

接下来,我们创建了三个控件:wx.FilePickerCtrl用于选择图片文件,wx.TextCtrl用于输入要显示在水印中的文字,以及一个"印章"按钮。

随后,我们使用sizer来设置控件的布局,将控件添加到sizer中,并将sizer应用于主面板。

最后,我们将"印章"按钮绑定到on_generate_watermark事件处理函数,以便在点击按钮时执行水印生成的操作。

def on_generate_watermark(self, event):
    filepath = self.file_picker.GetPath()
    text = self.text_ctrl.GetValue()

    if filepath and text:
        image = Image.open(filepath)
        
        # 创建一个绘图对象
        draw = ImageDraw.Draw(image)

        # 加载字体,指定字体大小
        font = ImageFont.truetype("C://Windows//Fonts//arial.ttf", 40)

        # 指定文字的位置,底部居中
        text_width, text_height = draw.textsize(text, font=font)
        image_width, image_height = image.size
        text_x = (image_width - text_width) // 2
        text_y = image_height - text_height - 20  # 20为底部边距

        # 指定文字的颜色,RGB格式
        color = (255, 0, 0)

        # 在图片上绘制文字
        draw.text((text_x, text_y), text, font=font, fill=color)

        # 保存图片
        output_path = "watermarked_image.jpg"
        image.save(output_path)

        # 显示成功提示
        wx.MessageBox("水印已添加并另存为watermarked_image.jpg。", "成功", wx.OK | wx.ICON_INFORMATION)

    event.Skip()

这是on_generate_watermark事件处理函数。当"印章"按钮被点击时,该函数将被调用。

首先,我们从文件选择控件(file_picker)获取选择的图片文件路径(filepath),并从文本输入控件(text_ctrl)获取输入的文字(text)。

接下来,我们使用Image.open(filepath)打开选择的图片,并创建一个ImageDraw对象(draw)来绘制水印。

然后,我们加载所需的字体文件(arial.ttf)并指定字体大小为40。

接着,我们计算要绘制的文字的位置,将其放置在图片的底部中心位置。我们使用draw.textsize(text, font=font)来获取绘制文字所需的宽度和高度,然后使用图片的宽度和高度计算出文字的x和y坐标。

在绘制文字之前,我们指定文字的颜色为红色(RGB格式)。

最后,我们使用draw.text(...)在图片上绘制文字,将水印添加到图片中。

完成绘制水印后,我们将保存带有水印的图片为"watermarked_image.jpg"文件。

最后,我们显示一个成功的提示消息框,告知用户水印已添加并保存成功。

if __name__ == '__main__':
    app = wx.App()
    frame = WatermarkFrame()
    frame.Show()
    app.MainLoop()

这是应用程序的入口点。我们创建一个wx.App实例,并实例化WatermarkFrame类作为主窗口。

然后,我们显示主窗口,并启动应用程序的主事件循环(app.MainLoop()),以便处理GUI事件和保持应用程序运行。
在这里插入图片描述

以上是该水印生成器应用程序的详细介绍。当您运行该代码时,将显示一个窗口,您可以选择要添加水印的图片文件,并在输入框中输入要显示在水印中的文字。点击"印章"按钮后,应用程序将在选择的图片上添加水印,并将生成的带有水印的图片保存在当前目录下的"_copy.jpg"文件中。

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

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

相关文章

K9、希喂、SC哪款主食冻干适合全体质猫咪?深入对比,真实测评报告

随着越来越多的人开始重视科学养猫的方法,铲屎官们对猫咪主食的营养和健康要求也越来越高。主食冻干作为一种模拟猫咪原始猎物模型配比的食品,因其低温加工工艺而受到广大猫奴的喜爱。这种食品更符合猫咪的饮食天性,相比起高淀粉、碳水化合物…

【高效视频处理】BMF 项目安装与老视频修复体验全流程及总结

一、BMF简介 BMF(Babit Multimedia Framework)是字节跳动开发的跨平台、多语言、可定制的多媒体处理框架。经过 4 年多的测试和改进,BMF 已经过量身定制,能够熟练地应对我们现实生产环境中的挑战。目前广泛应用于字节跳动的视频串…

C# windows服务程序开机自启动exe程序

我们使用传统的Process.Start(".exe")启动进程会遇到无法打开UI界面的问题,尤其是我们需要进行开启自启动程序设置时出现诸多问题,于是我们就想到采用windows服务开机自启动来创建启动一个新的exe程序,并且是显式运行。 首先是打开…

对接第三方接口鉴权(Spring Boot+Aop+注解实现Api接口签名验证)

前言 一个web系统,从接口的使用范围也可以分为对内和对外两种,对内的接口主要限于一些我们内部系统的调用,多是通过内网进行调用,往往不用考虑太复杂的鉴权操作。但是,对于对外的接口,我们就不得不重视这个…

Java字符串对象池的作用是什么?

Java字符串对象池的作用是什么? 在 Java 中,字符串池(String Pool)是字符串常量的存储区域,它位于堆区域中。字符串池的作用是提高字符串的重用性,减少内存消耗。 字符串池的位置: 在堆中&…

Qt6入门教程 3:创建Hello World项目

一.新建一个项目 程序员的职业生涯都是从一声问候开始的,我们的第一个Qt项目也是HelloWorld 首先要说明的是,IDE不一定要用Qt Creator,用Visual Studio、VSCode、CLion也可以搭建Qt开发环境,它们都相应的插件来支持Qt开发。当然这…

气动凝结水回收机组 浮球机械泵回收机组工作原理动画讲解介绍

​ 1:气动凝结水回收浮球机械泵介绍 气动凝结水回收是一种利用气动力转换产生负压的装置,可以将废气中的水分分离出来并回收利用。这种装置主要包含两个关键部件:气水分离器和气动运动控制阀。 气水分离器负责将进入回收装置的废气中的水分…

transforms图像增强(二)

一、图像变换 1、transforms.Pad transforms.Pad是一个用于对图像边缘进行填充的数据转换操作。 参数: padding:设置填充大小。可以是单个整数,表示在上下左右四个方向上均填充相同数量的像素;也可以是一个包含两个整数的元组…

粉丝投稿:从写下第1个脚本到年薪20W,我的自动化测试心路历程

我希望我的故事能够激励现在的软件测试人,尤其是还坚持在做“点点点”的测试人。 你可能会有疑问:“我也能做到这一点的可能性有多大?”因此,我会尽量把自己做决定和思考的过程讲得更具体一些,并尽量体现更多细节。 每…

印象笔记02: 笔记本管理系统和空间使用

印象笔记02: 笔记本管理系统和空间使用 印象笔记新建笔记是一件非常容易的事情。笔记多了,就是归纳到笔记本里。 印象笔记一共有三层的笔记结构:最高层级是笔记本组,其次是笔记本,最后是一个个的笔记。合理的分类能够…

SpringCloud系列篇:核心组件之注册中心组件

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于SpringCloud的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一.注册中心组件是什么 二.注册中心…

一键转换,创新无限:将HTML轻松转化为PDF!

在数字时代,HTML与PDF已成为信息传递的两大主流格式。然而,在这两者之间转换常常让人感到困扰。现在,有了我们的创新工具,您只需轻点一下,即可一键将HTML转化为PDF! 首先,我们要进入首助编辑高…

(Python + Selenium4)Web自动化测试自学Day2之动手尝试

目录 文章声明⭐⭐⭐让我们开始今天的学习吧!小试牛刀关于select标签关于弹窗只有一个点击按钮的弹窗需要确认的弹窗用户可以输入的弹窗 文章声明⭐⭐⭐ 该文章为我(有编程语言基础,非编程小白)的 Python Selenium4 Web自动化测试…

HttpRunner自动化测试工具之获取响应数据extract提取值到变量

获取响应数据 extract: 提取 注:extract 应与request保持同一层级 1、响应行,响应头;通过 extract 提取响应的数据并存储到变量中,如下图: 注:变量名的前面要有 - # 获取响应数据: 响应行(…

【年终总结系列 2023】成长与收获:回顾过去、展望未来,加油2024!

转眼间加入CSDN已经六年多了,初加入CSDN时,我兴致勃勃地投入到写作中,分享了一些CTF的解题思路和方法,取得了不错的反响。但随着工作忙碌和生活压力的增加,我在CTF方面的写作频率逐渐减少,也很长时间没有更…

Linux离线安装MySQL(rpm)

目录 下载安装包安装MySQL检测安装结果服务启停MySQL用户设置 下载安装包 下载地址:https://downloads.mysql.com/archives/community/ 下载全量包如:(mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar) 解压:tar -xzvf mysql-8.1.0-1.el7.x86_64.…

国家高等教育智慧教育平台

文章目录 1. 网站地址2. 网站简介3. 网站集合的资源与依托平台彩蛋环节a. 考试酷b. 公益学术平台 足不出户,就能免费学习2.7万门大学课程。包含国家精品课程,部分课程由国家级名师 / 院士 授课。 1. 网站地址 国家高等教育智慧教育平台网址:…

架构的本质是什么?

最近总是有小伙伴问我,如何成长为一名优秀的架构师,我也不知道该如何去回答,但是我想聊一下架构的本质。 架构不是互联网行业独有的 架构及对应的架构师职位并不是互联网行业独有的,只要存在组织的地方就存在架构。 比如一个木…

【C++】vector

文章目录 1. vector 的介绍2. vector 的使用2.1 vector 的定义2.2 vector iterator 的使用2.3 vector 的空间增长问题2.3 vector 增删查改 1. vector 的介绍 vector的文档介绍 vector是表示可变大小数组的序列容器。就像数组一样,vector也采用连续的存储空间来存储…

程序员必知!责任链模式的实战应用与案例分析

责任链模式让多个对象依次处理请求,降低发送者和接收者的耦合度,以在线购物为例,用户提交订单需经多步验证,通过责任链模式,验证器按顺序处理请求,先用户身份,再支付方式,最后配送地…