Python实现图像添加水印的方法
1. 简介
在日常图像处理中,为图片添加水印是一项常见任务。有多种方法和工具可供选择,而今天我们将专注于使用Python语言结合PIL库批量添加水印。
需要注意的是,所选用的图片格式不应为JPG或JPEG,因为这两种格式的图片不支持透明度设置。
2. PIL库概述
- PIL是Python的图像处理库,支持多种文件格式。
- PIL提供强大的图像和图形处理功能,包括缩放、裁剪、叠加以及添加线条、文字等操作。
- 安装PIL库可使用以下命令:
pip install Pillow
3. PIL库中涉及的类
| 模块或类 | 说明 |
|---|---|
| image模块 | 用于图像处理 |
| ImageDraw | 2D图像对象 |
| ImageFont | 字体存储 |
| ImageEnhance | 图像增强 |
4. 实现原理
本文的主要目标是批量为某个文件夹下的图片添加水印,实现原理如下:
- 设置水印内容;
- 使用Image对象的open()方法打开原始图片;
- 使用Image对象的new()方法创建存储水印图片的对象;
- 使用ImageDraw.Draw对象的text()方法绘制水印文字;
- 使用ImageEnhance中Brightness的enhance()方法设置水印透明度。
5. 实现过程
5.1 原始图片
设定原始图片的存储目录,例如:
F:\python_study\image\image01
5.2 导入相关模块
导入所需的PIL模块或类:
from PIL imort Image, ImageDraw, ImageFont, ImageEnhance
import os
5.3 初始化数据
通过用户手动输入相关信息,如图片存储路径、水印文字、水印位置、水印透明度等:
class WatermarkText():def __init__(self):super(WatermarkText, self).__init__()self.image_path = input('图片路径:')self.watermark_text = input('水印文字:')self.position_flag = int(input('水印位置(1:左上角,2:左下角,3:右上角,4:右下角,5:居中):'))self.opacity = float(input('水印透明度(0—1之间的1位小数):'))
5.4 水印字体设置
选择系统字体库中的字体:
self.font = ImageFont.truetype("cambriab.ttf", size=35)
5.5 打开原始图片并创建存储对象
打开原始图片并转换为RGBA:
image = Image.open(img).convert('RGBA')
创建绘制对象:
new_img = Image.new('RGBA', image.size, (255, 255, 255, 0))
image_draw = ImageDraw.Draw(new_img)
5.6 计算图片和水印的大小
计算图片大小:
w, h = image.size
计算文字大小:
w1 = self.font.getsize(self.watermark_text)[0]
h1 = self.font.getsize(self.watermark_text)[1]
5.7 选择性设置水印文字
通过if语句实现:
if self.position_flag == 1: # 左上角location = (0, 0)
elif self.position_flag == 2: # 左下角location = (0, h - h1)
elif self.position_flag == 3: # 右上角location = (w - w1, 0)
elif self.position_flag == 4: # 右下角location = (w - w1, h - h1)
elif self.position_flag == 5: # 居中location = (h/2, h/2)
5.8 绘制文字并设置透明度
绘制文字:
image_draw.text(location, self.watermark_text, font=self.font, fill="blue")
设置透明度:
transparent = new_img.split()[3]
transparent = ImageEnhance.Brightness(transparent).enhance(self.opacity)
new_img.putalpha(transparent)Image.alpha_composite(image, new_img).save(img)
5.9 遍历获取图片文件并调用绘制方法
watermark_text = WatermarkText()
try:file_list = os.listdir(watermark_text.image_path)for i in range(0, len(file_list)):filepath = os.path.join(watermark_text.image_path, file_list[i])if os.path.isfile(filepath):filetype = os.path.splitext(filepath)[1]if filetype == '.png':watermark_text.add_text_watermark(filepath)else:print("图片格式有误,请使用png格式图片")print('批量添加水印完成')
except:print('输入的文件路径有误,请检查~~')
6. 完整源码
from PIL importImage, ImageDraw, ImageFont, ImageEnhance
import osclass WatermarkText():def __init__(self):super(WatermarkText, self).__init__()self.image_path = input('图片路径:')self.watermark_text = input('水印文字:')self.position_flag = int(input('水印位置(1:左上角,2:左下角,3:右上角,4:右下角,5:居中):'))self.opacity = float(input('水印透明度(0—1之间的1位小数):'))# 设置字体self.font = ImageFont.truetype("cambriab.ttf", size=35)# 文字水印def add_text_watermark(self, img):global locationimage = Image.open(img).convert('RGBA') new_img = Image.new('RGBA', image.size, (255, 255, 255, 0)) image_draw = ImageDraw.Draw(new_img) w, h = image.size # 图片大小w1 = self.font.getsize(self.watermark_text)[0] # 字体宽度h1 = self.font.getsize(self.watermark_text)[1] # 字体高度# 设置水印文字位置if self.position_flag == 1: # 左上角location = (0, 0)elif self.position_flag == 2: # 左下角location = (0, h - h1)elif self.position_flag == 3: # 右上角location = (w - w1, 0)elif self.position_flag == 4: # 右下角location = (w - w1, h - h1)elif self.position_flag == 5: # 居中location = (h/2, h/2)# 绘制文字image_draw.text(location, self.watermark_text, font=self.font, fill="blue")# 设置透明度transparent = new_img.split()[3]transparent = ImageEnhance.Brightness(transparent).enhance(self.opacity)new_img.putalpha(transparent)Image.alpha_composite(image, new_img).save(img)if __name__ == "__main__":watermark_text = WatermarkText()try:file_list = os.listdir(watermark_text.image_path) for i in range(0, len(file_list)): filepath = os.path.join(watermark_text.image_path, file_list[i])if os.path.isfile(filepath): filetype = os.path.splitext(filepath)[1] if filetype == '.png': watermark_text.add_text_watermark(filepath) else:print("图片格式有误,请使用png格式图片")print('批量添加水印完成')except:print('输入的文件路径有误,请检查~~')
7. 效果展示
运行过程:
D:\Python37\python.exe F:/python_study/python_project/watermark_text.py
图片路径:F:\python_study\image\image01
水印文字:
水印位置(1:左上角,2:左下角,3:右上角,4:右下角,5:居中):1
水印透明度(0—1之间的1位小数):0.5
F:/python_study/python_project/watermark_text.py:32: DeprecationWarning: getsize is deprecated and will be removed in Pillow 10 (2023-07-01). Use getbbox or getlength instead.w1 = self.font.getsize(self.watermark_text)[0] # 获取字体宽度
F:/python_study/python_project/watermark_text.py:33: DeprecationWarning: getsize is deprecated and will be removed in Pillow 10 (2023-07-01). Use getbbox or getlength instead.h1 = self.font.getsize(self.watermark_text)[1] # 获取字体高度
批量添加水印完成
8. 改进与建议
8.1 参数输入方式优化
在初始化数据的部分,我们可以考虑通过命令行参数或配置文件的方式输入相关信息,以提高用户体验。例如使用argparse库来解析命令行参数。
import argparseclass WatermarkText():def __init__(self):parser = argparse.ArgumentParser(description='Add watermark to images.')parser.add_argument('--image_path', type=str, help='Path to the image directory.')parser.add_argument('--watermark_text', type=str, help='Text for watermark.')parser.add_argument('--position_flag', type=int, help='Position flag for watermark (1: top-left, 2: bottom-left, 3: top-right, 4: bottom-right, 5: center).')parser.add_argument('--opacity', type=float, help='Opacity for watermark (0-1 with 1 decimal place).')args = parser.parse_args()self.image_path = args.image_path or input('Image path: ')self.watermark_text = args.watermark_text or input('Watermark text: ')self.position_flag = args.position_flag or int(input('Watermark position (1: top-left, 2: bottom-left, 3: top-right, 4: bottom-right, 5: center): '))self.opacity = args.opacity or float(input('Watermark opacity (0-1 with 1 decimal place): '))
8.2 异常处理改进
在处理异常的部分,我们可以更具体地捕获异常类型,并提供更友好的提示信息。
try:# existing code...
except FileNotFoundError:print('Error: The specified image directory does not exist.')
except PermissionError:print('Error: Permission denied to access the specified image directory.')
except Exception as e:print(f'An unexpected error occurred: {e}')
8.3 代码结构优化
可以考虑将一些功能模块化,提高代码的可读性和维护性。例如,将文字水印的添加功能独立成一个方法。
class WatermarkText():# existing code...def add_text_watermark(self, img):# existing code...
8.4 日志记录
考虑在程序中添加日志记录,记录关键步骤和出错信息,以便于排查问题。
import logginglogging.basicConfig(level=logging.INFO)class WatermarkText():# existing code...def add_text_watermark(self, img):try:# existing code...logging.info(f'Successfully added watermark to {img}')except Exception as e:logging.error(f'Error adding watermark to {img}: {e}')
8.5 扩展功能
在程序中可以考虑添加更多功能,比如支持不同的水印颜色、字体大小等选项,以使程序更加灵活。
这些改进和建议将有助于提高程序的稳定性、易用性和可维护性。
当然,我们将继续改进和完善你的代码。在这一部分,我们会考虑一些进一步的优化和改进。
9. 优化图片格式检查
在处理图片文件时,可以优化检查图片格式的方式。使用os.path.splitext得到的文件扩展名可能包含大写字母,为了确保匹配,可以将文件扩展名转换为小写。
if filetype.lower() == '.png':watermark_text.add_text_watermark(filepath)
else:print("Error: Image format is not supported. Please use PNG format.")
10. 增加用户交互性
可以考虑在程序中增加更多用户交互性,比如在成功添加水印后询问用户是否继续添加水印。
while True:try:# existing code...print('Watermark added successfully.')another = input('Do you want to add watermark to another image? (yes/no): ').lower()if another != 'yes':breakexcept Exception as e:logging.error(f'Error: {e}')
这样,用户可以选择是否继续添加水印,提高程序的交互性。
11. 多线程处理
如果你需要处理大量图片,可以考虑使用多线程来加速处理过程。这可以通过concurrent.futures模块实现。
from concurrent.futures import ThreadPoolExecutor# existing code...if __name__ == "__main__":watermark_text = WatermarkText()try:file_list = os.listdir(watermark_text.image_path) with ThreadPoolExecutor() as executor:executor.map(watermark_text.add_text_watermark, [os.path.join(watermark_text.image_path, file) for file in file_list])print('Batch watermarking completed.')except Exception as e:logging.error(f'Error: {e}')
这将允许同时处理多个图片,提高处理速度。
12. 其他优化建议
- 考虑支持更多图片格式,而不仅限于PNG。你可以使用Pillow库中的
Image.register_open()方法注册其他格式的图片打开器。 - 如果水印文字较长,可以考虑自动调整文字大小,以适应图片。
相关文章:
Python实现图像添加水印的方法
1. 简介 在日常图像处理中,为图片添加水印是一项常见任务。有多种方法和工具可供选择,而今天我们将专注于使用Python语言结合PIL库批量添加水印。 需要注意的是,所选用的图片格式不应为JPG或JPEG,因为这两种格式的图片不支持透明…...
MemFire Cloud: 一种全新定义后端即服务的解决方案
在这个快节奏的互联网时代,开发者们最希望的就是能够省时省力地完成项目,快速上线。然而,搭建服务、开发接口API、处理各种后端问题,往往让人头疼不已。别担心,现在有了MemFire Cloud,一款为懒人开发者量身…...
职业教育软件测试实验实训室建设应用案例
在信息化高速发展的今天,软件测试作为保障软件质量的关键环节,其重要性日益凸显。为满足职业教育对软件测试人才的培养需求,提高学生的实践能力和职业素养,唯众倾力打造了一款先进的软件测试实验实训室,并成功应用于多…...
如何判断一个js对象为数组类型
如何判断一个js对象为数组类型? 能想到的最常见的intanceof是吗?开始是这么认为,但是不是哈,看下面的解释,也没有太明白,暂且记住吧 综上,判断js对象为数组的两种方式 Array.isArray([]) // trueObject.prototype.toString.call([]) ‘[object Array]’ //true...
Nacos2.X 配置中心源码分析:客户端如何拉取配置、服务端配置发布客户端监听机制
文章目录 Nacos配置中心源码总流程图NacosClient源码分析获取配置注册监听器 NacosServer源码分析配置dump配置发布 Nacos配置中心源码 总流程图 Nacos2.1.0源码分析在线流程图 源码的版本为2.1.0 ,并在配置了下面两个启动参数,一个表示单机启动&#…...
phpstudy框架,window平台,如何开端口给局域网访问?
Windows平台上使用phpstudy框架开端口给同事访问,主要涉及到几个步骤:查看并确认本机IP地址、配置phpstudy及网站项目、开放防火墙端口以及确保同事能够通过局域网访问。以下是详细的步骤说明: 1. 查看并确认本机IP地址 首先,需…...
高性能Python网络框架实现网络应用详解
概要 Python作为一种广泛使用的编程语言,其简洁易读的语法和强大的生态系统,使得它在Web开发领域占据重要位置。高性能的网络框架是构建高效网络应用的关键因素之一。本文将介绍几个高性能的Python网络框架,详细描述它们的特点、使用场景及具体示例代码,帮助高效实现网络应…...
万字学习——DCU编程实战
参考资料 2.1 DCU软件栈(DCU ToolKit, DTK) DCU 开发与使用文档 (hpccube.com) DCU软件栈 DCU的软件栈—DCU Toolkit(DTK) HIP(Heterogeneous-Compute Interface for Portability)是AMD公司在2016年提出…...
Neo4j 图数据库 高级操作
Neo4j 图数据库 高级操作 文章目录 Neo4j 图数据库 高级操作1 批量添加节点、关系1.1 直接使用 UNWIND 批量创建关系1.2 使用 CSV 文件批量创建关系1.3 选择方法 2 索引2.1 创建单一属性索引2.2 创建组合属性索引2.3 创建全文索引2.4 列出所有索引2.5 删除索引2.6 注意事项 3 清…...
《RWKV》论文笔记
原文出处 [2305.13048] RWKV: Reinventing RNNs for the Transformer Era (arxiv.org) 原文笔记 What RWKV(RawKuv):Reinventing RNNs for the Transformer Era 本文贡献如下: 提出了 RWKV 网络架构,结合了RNNS 和Transformer 的优点,同…...
相机光学(二十九)——显色指数(Ra)
显指Ra是衡量光源显色性的数值,表示光源对物体颜色的还原能力。显色性是指光源对物体颜色的呈现能力,即光源照射在同一颜色的物体上时,所呈现的颜色特性。通常用显色指数(CRI)来表示光源的显色性,而显指Ra是…...
【Swoole 的生命周期,文件描述符,协程数量,以及默认值】
目录 Swoole 的生命周期 Swoole 文件描述符(FD)缓存 Swoole设置协程的数量 Swoole 默认值 Swoole 是一个基于 PHP 的高性能网络通信引擎,它采用 C 编写,提供了协程和高性能的网络编程支持。Swoole 支持多种网络服务器和客户端…...
“不要卷模型,要卷应用”之高考志愿填报智能体
摘要:李总的发言深刻洞察了当前人工智能领域的发展趋势与核心价值所在,具有高度的前瞻性和实践性。“大家不要卷模型,要卷应用”这一观点强调了在当前人工智能领域,应该更加注重技术的实际应用而非单纯的技术竞赛或模型优化。个性…...
k8s离线部署芋道源码后端
目录 概述实践Dockerfilek8s部署脚本 概述 本篇将对 k8s离线部署芋道源码后端 进行详细的说明,对如何构建 Dockerfile,如何整合 Nginx,如何整合 ingress 进行实践。 相关文章:[nacos在k8s上的集群安装实践] k8s离线部署芋道源码前…...
图论·Day01
P3371 P4779 P3371 【模板】单源最短路径(弱化版) 注意的点: 边有重复,选择最小边!对于SPFA算法容易出现重大BUG,没有负权值的边时不要使用!!! 70分代码 朴素板dijsk…...
hutool ExcelUtil 导出导入excel
引入依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.15</version></dependency>文件导入 public void savelist(String filepath,String keyname){ExcelReader reader Exce…...
打卡第7天-----哈希表
继续坚持✊,我现在看到leetcode上的题不再没有思路了,真的是思路决定出路,在做题之前一定要把思路梳理清楚。 一、四数相加 leetcode题目编号:第454题.四数相加II 题目描述: 给定四个包含整数的数组列表 A , B , C , …...
【Linux】WEB网站网络防火墙(WAF软件)Fail2ban:保护服务器免受恶意攻击的必备工具
随着互联网的迅速发展,服务器的安全性日益成为用户和管理员关注的焦点。恶意攻击者不断寻找机会侵入服务器,窃取敏感信息、破坏数据或者滥用系统资源。为了抵御这些威胁,许多安全工具应运而生,其中一款备受推崇的工具就是 Fail2ba…...
妙笔生词智能写歌词软件:创新助力还是艺术之殇?
在音乐创作日益普及和多样化的当下,各种辅助工具层出不穷,妙笔生词智能写歌词软件便是其中之一。那么,它到底表现如何呢? 妙笔生词智能写歌词软件(veve522)的突出优点在于其便捷性和高效性。对于那些灵感稍…...
力扣hot100-普通数组
文章目录 题目:最大子数组和方法1 动态规划方法2 题目:合并区间题解 题目:轮转数组方法1-使用额外的数组方法2-三次反转数组 题目:除自身以外数组的乘积方法1-用到了除法方法2-前后缀乘积法 题目:最大子数组和 原题链…...
Logisim实战:8位可控加减法电路设计与溢出检测
1. 从零开始理解8位可控加减法电路 第一次接触数字电路设计的朋友可能会觉得"8位可控加减法电路"听起来很高深,其实它的核心原理就像我们小时候用的算盘。想象一下,你有一个8档的算盘,每档只能表示0或1(对应算珠的上或下…...
听说读写画样样精通!美团开源LongCat-Next,给物理世界AI统一了语言
美团刚刚开源了最强原生多模态模型LongCat-Next,将物理世界AI的语言统一了。LongCat-Next模型能听,能说。比如语音问答,或者让它用指定音色说话,能读能写(视觉理解和推理),还能画画和设计&#…...
别再只盯着大模型了!手把手教你用Python+卫星数据做农业产量预测(附代码)
用Python和卫星数据构建农业产量预测模型:从数据获取到结果可视化全流程指南 当我们在谈论智慧农业时,往往容易陷入对大模型的盲目崇拜。但实际上,一套简单实用的数据科学流程,配合公开免费的卫星遥感数据,就能为中小农…...
SRS (Simple Realtime Server) 实战:从SFU到大规模互动直播架构
1. SRS与SFU:互动直播的基石架构 第一次接触SRS时,我被它简洁的配置方式惊艳到了。这个看似轻量级的服务器,竟然能支撑起我们平台日均百万级的直播流量。作为选择性转发单元(SFU),SRS的核心价值在于它解决了…...
如何构建Min浏览器插件:从零开始的可扩展架构指南
如何构建Min浏览器插件:从零开始的可扩展架构指南 【免费下载链接】min A fast, minimal browser that protects your privacy 项目地址: https://gitcode.com/gh_mirrors/mi/min Min浏览器作为一款注重隐私保护的轻量级浏览器,其插件系统为开发者…...
H5扫码功能实战:如何在微信和原生浏览器中实现二维码解析(附完整代码)
H5扫码功能实战:如何在微信和原生浏览器中实现二维码解析 移动互联网时代,二维码已成为连接线上线下最重要的入口之一。作为前端开发者,我们经常需要在H5页面中实现扫码功能,但不同环境下的兼容性问题往往让人头疼。本文将深入探讨…...
C#桌面开发选型指南:OpenTK vs SharpGL,在.NET Framework 4.7/Winform中谁更香?
C#桌面开发选型指南:OpenTK vs SharpGL在WinForm中的深度对决 当我们需要在.NET WinForm项目中集成3D图形功能时,OpenTK和SharpGL这两个库常常成为开发者纠结的选择。作为在.NET生态中封装OpenGL的两种主流方案,它们各有特色,适用…...
云手机 流畅稳定 操作简单
云手机依托云端服务器集群,配备企业级 GPU和高性能 CPU,通过资源池化技术,将物理算力切割成多个独立安卓实例,每个云手机实例可独占或动态共享强大资源,算力远超本地旗舰手机,能轻松运行大型 3D 游戏等高性…...
Win11下用VMware16安装UOS服务器版全流程(附镜像+序列号)
Win11环境下VMware 16安装UOS服务器版实战指南 在数字化转型浪潮中,国产操作系统正逐步成为企业IT基础设施的新选择。统信UOS作为国内领先的服务器操作系统,凭借其稳定性与安全性,正在金融、政务等领域获得广泛应用。本文将手把手指导Windows…...
UE后期处理材质实战:从黑白蒙版到卡通渲染的进阶应用
1. 黑白蒙版遮罩的底层原理与应用 在UE4后期处理材质中,黑白蒙版遮罩是最基础也最实用的功能之一。我第一次接触这个功能时,被它强大的选择性处理能力惊艳到了——它能像手术刀一样精准地分离出场景中的特定物体。 核心原理其实很简单:通过Sc…...
