Python图像处理实战:使用PIL库批量添加水印的完整指南【第27篇—python:Seaborn】

文章目录

    • 1. 简介
    • 2. PIL库概述
    • 3. PIL库中涉及的类
    • 4. 实现原理
    • 5. 实现过程
      • 5.1 原始图片
      • 5.2 导入相关模块
      • 5.3 初始化数据
      • 5.4 水印字体设置
      • 5.5 打开原始图片并创建存储对象
      • 5.6 计算图片和水印的大小
      • 5.7 选择性设置水印文字
      • 5.8 绘制文字并设置透明度
      • 5.9 遍历获取图片文件并调用绘制方法
    • 6. 完整源码
    • 7. 效果展示
    • 8. 改进与建议
      • 8.1 参数输入方式优化
      • 8.2 异常处理改进
      • 8.3 代码结构优化
      • 8.4 日志记录
      • 8.5 扩展功能
    • 9. 优化图片格式检查
    • 10. 增加用户交互性
    • 11. 多线程处理
    • 12. 其他优化建议

1. 简介

在日常图像处理中,为图片添加水印是一项常见任务。有多种方法和工具可供选择,而今天我们将专注于使用Python语言结合PIL库批量添加水印。

需要注意的是,所选用的图片格式不应为JPG或JPEG,因为这两种格式的图片不支持透明度设置。

2. PIL库概述

先前的文章已经详细介绍过PIL库,这里不再赘述。

  • PIL是Python的图像处理库,支持多种文件格式。
  • PIL提供强大的图像和图形处理功能,包括缩放、裁剪、叠加以及添加线条、文字等操作。
  • 安装PIL库可使用以下命令:
pip install Pillow

在这里插入图片描述

3. PIL库中涉及的类

模块或类说明
image模块用于图像处理
ImageDraw2D图像对象
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
水印透明度(01之间的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()方法注册其他格式的图片打开器。
  • 如果水印文字较长,可以考虑自动调整文字大小,以适应图片。

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

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

相关文章

解决PS“暂存盘已满”错误

问题:PS“暂存盘已满”错误 原因: PS在运行时会将文件的相关数据参数保存到暂存区。当提醒暂存盘满时,说明你当前PS运行的使用盘符空间不足,所以在运行时一定要保留有足够的盘符空间来运行PS。 效果图 解决方案 注意: 我们在使用P…

vue 组件 import make sure to provide the “name“ option.

百度了好多结果,都过时了,例如: 模块引入是否加{} 再比如: 对于递归组件,请确保提供“name”选项。 出现该错误情况之一: 错误由未正确引入组件或子组件引起,如element-ui中form表单组件未引…

css 怎么绘制一个带圆角的渐变色的边框

1&#xff0c;可以写两个样式最外面的div设置一个渐变的背景色。里面的元素使用纯色。但是宽高要比外面元素的小。可以利用里面的元素设置padding这样挡住部分渐变色。漏出来的渐变色就像边框一样。 <div class"cover-wrapper"> <div class"item-cover…

AI Agent:大模型的下一个高地

科技云报道原创。 当所有人都沉浸在与ChatGPT对话的乐趣中&#xff0c;一场静水流深的变革已然启动。 2023年11月&#xff0c;比尔盖茨发表了一篇文章&#xff0c;他表示&#xff0c;AI Agent将是大模型之后的下一个平台&#xff0c;不仅改变每个人与计算机互动的方式&#x…

Linux 常用进阶指令

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 其他…

如何使用CFImagehost结合内网穿透搭建私人图床并无公网ip远程访问

[TOC] 推荐一个人工智能学习网站点击跳转 1.前言 图片服务器也称作图床&#xff0c;可以说是互联网存储中最重要的应用之一&#xff0c;不仅网站需要图床提供的外链调取图片&#xff0c;个人或企业也用图床存储各种图片&#xff0c;方便随时访问查看。不过由于图床很不挣钱&a…

NLP论文阅读记录 - 2021 | 使用深度强化模型耦合上下文单词表示和注意机制的自动文本摘要

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作2.1 单词表示2.2 文本摘要方法 三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 Automatic text summarization us…

【IEEE会议征稿通知】第五届计算机视觉、图像与深度学习国际学术会议(CVIDL 2024)

第五届计算机视觉、图像与深度学习国际学术会议&#xff08;CVIDL 2024&#xff09; 2024 5th International Conference on Computer Vision, Image and Deep Learning 第五届计算机视觉、图像与深度学习国际学术会议&#xff08;CVIDL 2024&#xff09;定于2024年4月19-21日…

【深基9.例4】求第 k 小的数#洛谷(MLE)

题目描述 输入 n n n&#xff08; 1 ≤ n < 5000000 1 \le n < 5000000 1≤n<5000000 且 n n n 为奇数&#xff09;个数字 a i a_i ai​&#xff08; 1 ≤ a i < 10 9 1 \le a_i < {10}^9 1≤ai​<109&#xff09;&#xff0c;输出这些数字的第 k k k 小…

友思特分享丨高精度彩色3D相机:开启崭新的彩色3D成像时代

来源&#xff1a;友思特 机器视觉与光电 友思特分享丨高精度彩色3D相机&#xff1a;开启崭新的彩色3D成像时代 原文链接&#xff1a;https://mp.weixin.qq.com/s/vPkfA5NizmiZmLiy_jv3Jg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 3D成像的新时代 近年来&#…

pycharm Terminal命令行设置默认是Windows Powershell运行报错怎么修改?

目录 1. 真实案例 2. 如何做 3. 流程 3.1. 打开 settings 3.2. 在 最上方搜索 terminal 3.3. 在 shell path 里选择 cmd&#xff0c;并点击 OK 3.4. 重新打开 terminal 就成功了 1. 真实案例 使用 Windows Powershell 运行部分命令会不显示 2. 如何做 需要修改底部默认…

Android Studio安卓读写NFC Ntag标签源码

本示例使用的发卡器&#xff1a; https://item.taobao.com/item.htm?spma1z10.5-c-s.w4002-21818769070.11.3513789erHXVGx&id615391857885 <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout x…

“语言服务40人论坛2023年年会”在北京举行

为充分发挥区域合作优势&#xff0c;深度推进翻译专业学位研究生培养模式和路径建设&#xff0c;提升翻译人才培养质量&#xff0c;推动京津冀地区教育协同发展&#xff0c;为中国高质量发展提供语言服务智慧和方案&#xff0c;1月13日至14日&#xff0c;“语言服务40人论坛202…

嵌入式学习-网络编程-Day1

Day1 思维导图 作业 实现一下套接字通信 代码 #include<myhead.h>int main(int argc, const char *argv[]) {//1、创建套接字int sfd socket(AF_INET, SOCK_STREAM, 0);//参数1&#xff1a;通信域&#xff1a;使用的是ipv4通信//参数2&#xff1a;表示使用tcp通信//参…

继承、修饰符、工具类、jar包

目录 1.继承 2.修饰符 3.工具类 4.jar包的制作与使用 1.继承 是什么 1.面向对象的三大特征之一&#xff08;封装、继承、多态&#xff09; 2.可以使得子类具有父类的属性和方法&#xff0c;还可以在子类中重新定义&#xff0c;追加属性和方法。 继承的格式 public class F…

并发编程(一)线程基础知识与线程控制

进程与线程 进程&#xff1a;如任务管理器中各种程序叫做正在运行的进程。对于操作系统来说&#xff0c;仅仅是一个数据结构&#xff0c;并不真实的执行代码 线程&#xff1a;真实执行代码的 每个进程启动的是时候会同步启动一个主线程即main函数&#xff0c;当main函数结束…

智慧公厕:引领城市卫生管理新时代

在智慧城市建设中&#xff0c;智慧公厕作为城市环境卫生信息化的重要组成部分&#xff0c;扮演着关键角色。它不仅可以提升城市管理水平&#xff0c;满足人民群众的需求&#xff0c;还能提高公厕使用体验和城市环境卫生水平。如广州中期科技有限公司自主研发的智慧公厕管理系统…

第10章 通信业务

文章目录 10.1.1 通信行业1、通信行业的界定2、通信行业的特点 10.1.2 通信企业10.1.3 通信终端1、通信终端的分类2、终端发展趋势 10.2.1 通信业务的定义及分类10.2.2 基础电信业务1、第一类基础电信业务A11 固定通信业务A12 蜂窝移动通信业务A13 第一类卫星通信业务A14 第一类…

代码随想录 Leetcode1. 两数之和

题目&#xff1a; 代码&#xff08;首刷看解析 2024年1月15日&#xff09;&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int another 0;unordered_map<int,int> hash;for(int i 0; i < nums.size();…

为什么有人说PMP是水证,它的含金量到底怎么样?

在我国大陆&#xff0c;有好多证书被商业化得太重了&#xff0c;甚至演变成了个人或一些公司摇钱的工具。所以有些证书受人吹捧它崛起的快&#xff0c;但是活不长&#xff0c;甚至“夭折”&#xff0c;比如以前微软系列的证书&#xff1b; 而PMP认证从国外引进大陆这么多年了&…