Python图像处理:批量添加水印的优雅实现与进阶技巧

2023-12-19

1. 简介

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

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

2. PIL库概述

先前的文章已经详细介绍过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 import

 Image, ImageDraw, ImageFont, ImageEnhance
import os

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位小数):'))

        # 设置字体
        self.font = ImageFont.truetype("cambriab.ttf", size=35)

    # 文字水印
    def add_text_watermark(self, img):
        global location
        image = 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 argparse

class 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 logging

logging.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':
            break
    except 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() 方法注册其他格式的图片打开器。
---------------------------END---------------------------

题外话

感谢你能看到最后,给大家准备了一些福利!

感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。


???? CSDN大礼包????: 全网最全《Python学习资料》免费赠送????! (安全链接,放心点击)

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img

二、Python兼职渠道推荐 *

学的同时助你创收,每天花1-2小时兼职,轻松稿定生活费.
在这里插入图片描述

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

???? CSDN大礼包????: 全网最全《Python学习资料》免费赠送????! (安全链接,放心点击)

若有侵权,请联系删除

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python图像处理:批量添加水印的优雅实现与进阶技巧 的相关文章

随机推荐

  • 华为认证 | 专科考HCIE有用吗?

    当然可以 HCIE认证 对考生的学历 专业等没有任何要求 考生可以直接进行考试的报名 考试报名可以通过Pearson VUE官网 或者是直接前往考试中心所在地 向工作人员直接申请考试报名 01 专科考HCIE真的很有用吗 华为认证被越来越多
  • JAVA四大权限修饰符

    1 四大权限修饰符 public private default protected是java的四大修饰符 下面分别主要介绍四者之间的区别 1 1 public 公共的 public是权限最大的修饰符 他可以修饰类 成员变量 成员方法 构造
  • 通过全流量分析Web业务性能好坏

    随着全球商业环境的不断发展和变化 业务性能的重要性愈发凸显 无论是传统实体企业还是纯线上企业 业务性能都是其核心竞争力和稳定运营的关键要素 良好的业务性能不仅可以提升客户满意度 增加市场份额 还可以降低成本 提高效率 本文章目的为探讨基于B
  • 不做数据采集,不碰行业应用,专注数字孪生PaaS平台,飞渡科技三轮融资成功秘诀

    12月15日 飞渡科技在北京举行2023年度投资人媒体见面会 全面分享其产品技术理念与融资之路 北京大兴经开区党委书记 管委会主任常学智 大兴经开区副总经理梁萌 北京和聚百川投资管理有限公司 以下简称 和聚百川 投资总监严玉婷 北京天穆私募
  • 【Proteus仿真】【Arduino单片机】定时智能插座开关

    文章目录 一 功能简介 二 软件设计 三 实验现象 联系作者 一 功能简介 本项目使用Proteus8仿真Arduino单片机控制器 使LCD1602液晶 DS18B20温度传感器 按键 蜂鸣器 继电器开关 HC05蓝牙模块等 主要功能 系
  • 【精选】ATK&CK红队评估实战靶场三(超详细思路过程)

    博主介绍 博主介绍 大家好 我是 hacker routing 很高兴认识大家 主攻领域 渗透领域 应急响应 ATK CK红队评估实战靶场 VulnHub靶场复现 面试分析 点赞 评论 收藏 养成习惯 一键三连 欢迎关注 一起学习 一起讨论
  • 探索反思写作中Prompt的益处

    探索反思写作是一种有益于个人成长和思考的活动 它可以帮助我们深入思考自己的经历 情感和想法 并从中获得新的见解和启示 在探索反思写作中 Prompt 提示语 起着重要的作用 本文将介绍探索反思写作中Prompt的概念 作用以及如何利用它来提
  • 堡垒机是什么?有什么作用?

    随着互联网的快速发展 网络安全问题日益凸显 为了保护网络和数据的安全 堡垒机作为一种先进的安全防护技术应运而生 堡垒机提供多云主机资产的运维审计功能 覆盖SSH RDP VNC Telnet FTP SFTP等多种协议 同时支持通过浏览器W
  • 1796. 字符串中第二大的数字

    1796 字符串中第二大的数字 java class Solution public int secondHighest String s int max 1 for char ch s toCharArray if Character i
  • 几个Python小案例,爱上Python编程!

    Python是一种面向对象的解释型编程语言 源代码与解释器CPython遵守GPL协议 Python语法简洁清晰 语法简洁清晰 那么我们用少量的Python代码能做哪些有趣的东西 一 画爱心表白 1 图形都是由一系列的点 X Y 构成的曲线
  • yolo网络整理-网络结构原理与anchor

    YOLOv5 是Glenn Jocher等人操刀研发 Ultralytics公司的开源项目 项目地址可点击 2020年6月发布以来 Ultralytics公司一直在对项目进行维护与更新 目前repo的star数目突破44k YOLOv5的功
  • 软件测试/测试开发/人工智能丨ROC 与 AUC 的含义

    ROC Receiver Operating Characteristic 曲线和AUC Area Under the Curve 是用于评估二分类模型性能的常用工具 特别在处理不平衡数据集时非常有用 ROC 曲线 Receiver Ope
  • Qt 信号槽相关

    简单连接和关闭 connect 操作对象 操作对象属性 操作 this 响应对象 响应函数 连接 disconnect 操作对象 操作对象属性 操作 this 响应对象 响应函数 关闭 Lambda表达式 信号 connect 对象 对象类
  • 什么软件可以识别图片上的文字?快收藏好这些识别工具

    我真是要受不了自己的脑子了 它怎么总是能自动执行 清空 指令 让我把要做的事情忘得精光呢 就算是刚刚才在心中暗暗提醒过自己的事情 过个把小时就能忘到 九霄云外 去了 真是没少耽误正事 还好我学会了用便利贴来提醒自己 其它重要的事情也会记到小
  • 计算机组成原理——数制与编码

    1 在以下编码中 零的表示唯一的是 C A 反码 B 原码 C 补码 D 原码和移码 2 假设某数的真值为 100 1010B 在计算机内部表示为1011 0110B 该数采用的编码为 D A 移码 B 原码 C 反码 D 补码 3 考虑以
  • 大气污染扩散模型Calpuff丨Calmet气象模块、Calpost后处理模块、Post Tools后处理工具及绘图工具等

    目录 第一章 Calpuff基础知识 第二章 数据预处理 第三章 Calmet气象模块 第四章 Calpuff模块 第五章 Calpost后处理模块 第六章 Post Tools后处理工具及绘图工具 更多应用 Calpuff模型是一种三维非
  • 哪个图片翻译软件好用?推荐这三款帮你轻松翻译

    表弟在这两天正躲在家里 头悬梁锥刺股 呢 原因无它 距离他英语考试的时间只剩两三天了 可他这几个月都在偷懒 不仅上课不好好听 作业也没有好好写 可不得临时抱佛脚嘛 看着他对着英语卷子疯狂挠头 看不懂单词还得现翻词典的样子 真是狼狈极了 好歹
  • 为什么俄罗斯盛产黑客?

    自第一任总统上任以来 弗拉基米尔 普京始终将说服西方 特别是美国认真对待莫斯科 视作国家的首要任务 俄罗斯的这一目标 很大程度上源于过去十年更为自信且倾向于军事化的外交政策 长时间以来 俄罗斯似乎难以打破美国人深植的不可侵犯感 2014年
  • 为什么企业有了银企直联还需要智能网银?

    银企直联 又称银企互联 是指企业通过在内部建立自己的资金管理系统 与银行进行数据与信息的交互 方便企业实时查询账户信息 交易明细 以及办理结算 贷款 票据管理等业务 由于银企直联为企业财资管理带来了更多的便利 同时也能为银行提供更多的客户资
  • Python图像处理:批量添加水印的优雅实现与进阶技巧

    1 简介 在日常图像处理中 为图片添加水印是一项常见任务 有多种方法和工具可供选择 而今天我们将专注于使用Python语言结合PIL库批量添加水印 需要注意的是 所选用的图片格式不应为JPG或JPEG 因为这两种格式的图片不支持透明度设置