PIL如何批量给图片添加文字水印?

news2024/10/5 15:35:03

PIL如何批量给图片添加文字水印?

  • 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 显示效果

1 简单引入

  • 平常我们想给某些图片添加文字水印,方法有很多,也有很多的工具可以方便的进行;
  • 今天主要是对PIL库的应用,结合Python语言批量对图片添加水印;
  • 这里需要注意的是图片的格式,不能为JPG或JPEG,因为这两种格式的图片不支持透明度设置。

2 关于PIL

之前有的文章已经详细介绍过,这里不再赘述了。

  • PILPython的一个图像处理库,支持多种文件格式;
  • PIL提供强大的图像处理和图形处理能力;
  • 可完成对图像的缩放、裁剪、叠加以及图像添加线条、图像和文字等操作。
  • 安装的话,使用以下命令:
pip install Pillow

在这里插入图片描述

3 本文涉及的PIL的几个类

模块或类说明
image模块用于对图像就行处理
ImageDraw2D图像对象
ImageFont存储字体
ImageEnhance图像增强

4 实现原理

本文主要目的是批量对某个文件夹下的图片进行添加水印,原理如下:

  • 对水印内容设置;
  • 使用Image对象的open()方法打开原始图片;
  • 使用Image对象的new()方法新建存储水印图片对象;
  • 使用Image.Draw.Draw对象的text()绘制水印文字;
  • 使用ImageEnhance中的Brightness中的enhance()设置水印透明度。

5 实现过程

5.1 原始图片

  • 我们设置一个原始图片的存储目录,比如:
F:\python_study\image\image01
  • 这个文件夹中存放了多个png格式的图片:
    在这里插入图片描述
  • 这里的一个原始图片为:
    在这里插入图片描述

5.2 导入相关模块

  • 导入需要的几个PIL中的模块或类:
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
import os

5.3 初始化数据

  • 我们这里预想的是,通过用户自己手动输入相关信息,比如图片的存储路径,需要设置的水印文字,通过输入的方式设置水印的位置,设置水印的透明度等;
class TestText():
    def __init__(self):
        super(TestText, self).__init__()
        self.pic_path = input('图片路径:')
        self.pic_text = input('水印文字:')
        self.p_flag = int(input('水印位置(1:左上角,2:左下角,3:右上角,4:右下角,5:居中):'))
        self.a = float(input('水印透明度(0—1之间的1位小数):'))

5.4 水印字体设置

  • 这里我们先看下ImageFont.truetype源码:
def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
    """
    Load a TrueType or OpenType font from a file or file-like object,
    and create a font object.
    This function loads a font object from the given file or file-like
    object, and creates a font object for a font of the given size.

    Pillow uses FreeType to open font files. On Windows, be aware that FreeType
    will keep the file open as long as the FreeTypeFont object exists. Windows
    limits the number of files that can be open in C at once to 512, so if many
    fonts are opened simultaneously and that limit is approached, an
    ``OSError`` may be thrown, reporting that FreeType "cannot open resource".
    A workaround would be to copy the file(s) into memory, and open that instead.

    This function requires the _imagingft service.

    :param font: A filename or file-like object containing a TrueType font.
                 If the file is not found in this filename, the loader may also
                 search in other directories, such as the :file:`fonts/`
                 directory on Windows or :file:`/Library/Fonts/`,
                 :file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/` on
                 macOS.

    :param size: The requested size, in pixels.
    :param index: Which font face to load (default is first available face).
    :param encoding: Which font encoding to use (default is Unicode). Possible
                     encodings include (see the FreeType documentation for more
                     information):
  • 它的大意就是从系统中的字体库中读取字体;
  • 那我们的系统字体在哪里呢?
  • 系统字体在
C:\Windows\Fonts
  • 如下:
    在这里插入图片描述
  • 我们随便选一个自己喜欢的字体,复制下名字即可:
self.font = ImageFont.truetype("cambriab.ttf", size=35)

5.5 打开原始图片并新建存储对象

  • 打开原始图片,并转换为RGB
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.pic_text)[0]  # 获取字体宽度
h1 = self.font.getsize(self.pic_text)[1]  # 获取字体高度

5.7 选择性设置水印文字

  • 通过if语句来实现:
 if self.p_flag == 1:  # 左上角
      location = (0, 0)
 elif self.p_flag == 2:  # 左下角
      location = (0, h - h1)
 elif self.p_flag == 3:  # 右上角
      location = (w - w1, 0)
 elif self.p_flag == 4:  # 右下角
      location = (w - w1, h - h1)
 elif self.p_flag == 5:  # 居中
      location = (h/2, h/2)

5.8 绘制文字并设置透明度

  • 绘制文字:
image_draw.text(location, self.pic_text, font=self.font, fill="blue")
  • 设置透明度
 transparent = new_img.split()[3]
 transparent = ImageEnhance.Brightness(transparent).enhance(self.a)
 new_img.putalpha(transparent)

 Image.alpha_composite(image, new_img).save(img)

5.9 遍历获取图片文件并调用绘制方法

 text_pic = TestText()
    try:
        file_list = os.listdir(text_pic.pic_path)
        for i in range(0, len(file_list)):
            filepath = os.path.join(text_pic.pic_path, file_list[i])  
            if os.path.isfile(filepath): 
                filetype = os.path.splitext(filepath)[1] 
                if filetype == '.png': 
                    text_pic.test_text(filepath) 
                else:
                    print("图片格式有误,无法添加水印,请使用png格式图片")
        print('批量添加水印完成')
    except:
        print('输入的文件路径有误,请检查~~')

6 完整源码

# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2023/11/21 
# 文件名称:test_text_pic.py
# 作用:批量给图片添加文字水印和图片水印
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelson


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


class TestText():
    def __init__(self):
        super(TestText, self).__init__()
        self.pic_path = input('图片路径:')
        self.pic_text = input('水印文字:')
        self.p_flag = int(input('水印位置(1:左上角,2:左下角,3:右上角,4:右下角,5:居中):'))
        self.a = float(input('水印透明度(0—1之间的1位小数):'))

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

    # 文字水印
    def test_text(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.pic_text)[0]  # 字体宽度
        h1 = self.font.getsize(self.pic_text)[1]  # 字体高度

        # 设置水印文字位置
        if self.p_flag == 1:  # 左上角
            location = (0, 0)
        elif self.p_flag == 2:  # 左下角
            location = (0, h - h1)
        elif self.p_flag == 3:  # 右上角
            location = (w - w1, 0)
        elif self.p_flag == 4:  # 右下角
            location = (w - w1, h - h1)
        elif self.p_flag == 5:  # 居中
            location = (h/2, h/2)
        # 绘制文字
        image_draw.text(location, self.pic_text, font=self.font, fill="blue")

        # 设置透明度
        transparent = new_img.split()[3]
        transparent = ImageEnhance.Brightness(transparent).enhance(self.a)
        new_img.putalpha(transparent)

        Image.alpha_composite(image, new_img).save(img)


if __name__ == "__main__":
    text_pic = TestText()
    try:
        file_list = os.listdir(text_pic.pic_path) 
        for i in range(0, len(file_list)): 
            filepath = os.path.join(text_pic.pic_path, file_list[i])
            if os.path.isfile(filepath): 
                filetype = os.path.splitext(filepath)[1] 
                if filetype == '.png': 
                    text_pic.test_text(filepath) 
        print('批量添加水印完成')
    except:
        print('输入的文件路径有误,请检查~~')

7 显示效果

  • 运行过程:
D:\Python37\python.exe F:/python_study/python_project/test_text_pic.py
图片路径:F:\python_study\image\image01
水印文字:@虫无涯
水印位置(1:左上角,2:左下角,3:右上角,4:右下角,5:居中):1
水印透明度(01之间的1位小数):0.5
F:/python_study/python_project/test_text_pic.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.pic_text)[0]  # 获取字体宽度
F:/python_study/python_project/test_text_pic.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.pic_text)[1]  # 获取字体高度
批量添加水印完成
  • 不同位置的水印效果:
    在这里插入图片描述
  • 居中效果:
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vite - 配置 - 自动修改 index.html 中的title

需求描述 在Vue3项目的开发过程中,我们为了能区分正式环境和测试环境, 通常会进行环境配置文件的区分, 例如,开发环境一个配置文件、生产环境一个配置文件。因此,我们就希望 在项目的index.html 的 title 标签中&…

普冉PY32系列(十) 基于PY32F002A的6+1通道遥控小车I - 综述篇

目录 普冉PY32系列(一) PY32F0系列32位Cortex M0 MCU简介普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单普冉PY32系列(四) PY32F002A/003/030的时钟设置普冉PY32系列(五) 使用JLink RTT代替串口输出日志普冉PY32…

Redis从入门到精通(三)-高阶篇

文章目录 0. 前言[【高阶篇】3.1 Redis协议(RESP )详解](https://blog.csdn.net/wangshuai6707/article/details/132742584)[【高阶篇】3.3 Redis之底层数据结构简单动态字符串(SDS)详解](https://blog.csdn.net/wangshuai6707/article/details/131101404)[【高阶篇】3.4 Redis…

GNSS技术在农业领域的创新应用

全球导航卫星系统(GNSS)技术在农业领域的广泛应用为现代农业带来了革命性的变革。从精准农业到农业机械自动化,GNSS技术为提高农业生产效率、减少资源浪费、实现可持续发展提供了关键支持。本文将深入探讨GNSS技术在农业领域的应用&#xff0…

【理解ARM架构】不同方式点灯 | ARM架构简介 | 常见汇编指令 | C与汇编

🐱作者:一只大喵咪1201 🐱专栏:《理解ARM架构》 🔥格言:你只管努力,剩下的交给时间! 目录 🏀直接操作寄存器点亮LED灯🏀地址空间🏀ARM内部的寄存…

深度学习入门:自建数据集完成花鸟二分类任务

自建数据集完成二分类任务(参考文章) 1 图片预处理 1 .1 统一图片格式 找到的图片需要首先做相同尺寸的裁剪,归一化,否则会因为图片大小不同报错 RuntimeError: stack expects each tensor to be equal size, but got [3, 667…

5.基于飞蛾扑火算法(MFO)优化的VMD参数(MFO-VMD)

代码的使用说明 基于飞蛾扑火算法优化的VMD参数 优化算法代码原理 飞蛾扑火优化算法(Moth-Flame Optimization,MFO)是一种新型元启发式优化算法,该算法是受飞蛾围绕火焰飞行启发而提出的,具有搜索速度快、寻优能力强的…

git常常用命令

这篇文章中,一些简单的,大家都知道的git 命令我就不再赘述,我只写出来最近在项目中常用到的一些命令。这些命令可以帮助我更好的开发。 git stash 请大家设想下面的场景,你的本地有两个分支,develop,fix分支&#xf…

万界星空科技QMS质量管理系统功能

QMS质量管理系统结合质量决策、综合质量管理、过程质量控制三个层次要素,帮助企业实现产品全寿命周期质量数据的及时、灵活、准确和全面采集。 通过质量管理软件能够实现质量数据科学处理和应用,包括数据的系统化组织、结构化存贮、便捷式查询、定制化统…

使用USB转JTAG芯片CH347在Vivado下调试

简介 高速USB转接芯片CH347是一款集成480Mbps高速USB接口、JTAG接口、SPI接口、I2C接口、异步UART串口、GPIO接口等多种硬件接口的转换芯片。 通过XVC协议,将CH347应用于Vivado下,简单尝试可以成功,源码如下,希望可以一起共建&a…

全链路压测的步骤及重要性

全链路压测是一种系统性的性能测试方法,旨在模拟真实用户场景下的完整操作流程,全面评估软件系统在不同压力下的性能表现。这种测试方法对于保证应用程序的高可用性、稳定性和可扩展性至关重要。 1. 全链路压测概述 全链路压测是在模拟实际用户使用场景的…

OpenAI 董事会宫斗始作俑者?一窥伊尔亚·苏茨克维内心世界

OpenAI 董事会闹剧应该是暂告一个段落了,Sam Altman和Greg Brockman等一众高管均已加入微软,还有员工写联名信逼宫董事会的戏码,关注度已经降下来了。 但是,这场宫斗闹剧的中心人物Ilya Sutskever大家关注度不算太高。他本人是纯粹的技术男,极少抛头露面透露其内心世界。…

TransmittableThreadLocal - 线程池中也可以传递参数了

一、InheritableThreadLocal的不足 InheritableThreadLocal可以用于主子线程之间传递参数,但是它必须要求在主线程中手动创建的子线程才可以获取到主线程设置的参数,不能够通过线程池的方式调用。 但是现在我们实际的项目开发中,一般都是采…

深度学习之三(卷积神经网络--Convolutional Neural Networks,CNNs)

概念 卷积神经网络(Convolutional Neural Networks,CNNs)是一种特殊的神经网络结构,专门用于处理具有网格状结构(如图像、音频)的数据。CNN 在计算机视觉领域取得了巨大成功,广泛应用于图像识别、物体检测、图像生成等任务。以下是 CNN 的主要理论概念: 在数学中,卷…

短视频配音软件有哪些?这些常用的短视频配音软件

短视频行业近年来发展得很快,几乎闯入了我们每个现代人的生活,它以其独有的特点和乐趣,也收获了大批短视频爱好者,配音是短视频创作过程中不可或缺的环节,今天,我们就来聊聊短视频配音及好用的配音软件。 短…

京东大数据(京东数据采集):2023年Q3线上投影仪品类销售数据分析报告

11月初,某知名投影仪企业发布了2023年三季度财报。数据显示,今年第三季度,公司营收依然不客观,连续第五个季度业绩持续下滑。 从鲸参谋数据也可以看出,今年Q3,京东平台上该品牌的销量环比下滑约35%&#x…

审计dvwa高难度命令执行漏洞的代码,编写实例说明如下函数的用法

审计dvwa高难度命令执行漏洞的代码 &#xff0c;编写实例说明如下函数的用法 代码&#xff1a; <?phpif( isset( $_POST[ Submit ] ) ) {// Get input$target trim($_REQUEST[ ip ]);// Set blacklist$substitutions array(& > ,; > ,| > ,- > ,$ …

第一次参加算法比赛是什么感受?

大家好&#xff0c;我是怒码少年小码。 冬日暖阳&#xff0c;好日常在。今天中午在食堂干饭的时候&#xff0c;我的手机&#x1f4f1;收到了一条收货信息。 阿&#xff1f;什么玩意儿&#xff1f;我又买啥了&#xff1f; 个败家玩意&#xff0c;我都准备好叨叨我自己&#x…

SpringCloud原理-OpenFeign篇(二、OpenFeign包扫描和FeignClient的注册原理)

文章目录 前言正文一、从启动类开始二、EnableFeignClients 的源码分析三、Import FeignClientsRegistrar 的作用四、FeignClientsRegistrar#registerFeignClients(...)五、饥饿注册&懒注册 FeignClientsRegistrar#registerFeignClient(...)六、通过Holder真正注册beanDefi…

一文概括AxureRP的优缺点和替代软件

AxureRP是目前流行的设计精美的用户界面和交互软件。AxureRP根据其应用领域提供了一组丰富的UI控制。 Axure是什么软件&#xff1f; Axure是目前流行的设计精美的用户界面和交互软件。Axure已经存在了近十年&#xff0c;让UX设计师轻松了解创建软件原型的细节。作为一种原型设…