广告位联系
返回顶部
分享到

Python实现图像添加水印的方法

Golang 来源:互联网 作者:佚名 发布时间:2024-07-14 08:59:17 人浏览
摘要

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

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

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

2. PIL库概述

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

1

pip install Pillow

3. PIL库中涉及的类

模块或类 说明
image模块 用于图像处理
ImageDraw 2D图像对象
ImageFont 字体存储
ImageEnhance 图像增强

4. 实现原理

本文的主要目标是批量为某个文件夹下的图片添加水印,实现原理如下:

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

5. 实现过程

5.1 原始图片

设定原始图片的存储目录,例如:

1

F:\python_study\image\image01

5.2 导入相关模块

导入所需的PIL模块或类:

1

2

from PIL imort Image, ImageDraw, ImageFont, ImageEnhance

import os

5.3 初始化数据

通过用户手动输入相关信息,如图片存储路径、水印文字、水印位置、水印透明度等:

1

2

3

4

5

6

7

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 水印字体设置

选择系统字体库中的字体:

1

self.font = ImageFont.truetype("cambriab.ttf", size=35)

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

打开原始图片并转换为RGBA:

1

image = Image.open(img).convert('RGBA')

创建绘制对象:

1

2

new_img = Image.new('RGBA', image.size, (255, 255, 255, 0))

image_draw = ImageDraw.Draw(new_img)

5.6 计算图片和水印的大小

计算图片大小:

1

w, h = image.size

计算文字大小:

1

2

w1 = self.font.getsize(self.watermark_text)[0]

h1 = self.font.getsize(self.watermark_text)[1]

5.7 选择性设置水印文字

通过if语句实现:

1

2

3

4

5

6

7

8

9

10

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 绘制文字并设置透明度

绘制文字:

1

image_draw.text(location, self.watermark_text, font=self.font, fill="blue")

设置透明度:

1

2

3

4

5

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 遍历获取图片文件并调用绘制方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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. 完整源码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

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库来解析命令行参数。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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 异常处理改进

在处理异常的部分,我们可以更具体地捕获异常类型,并提供更友好的提示信息。

1

2

3

4

5

6

7

8

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 代码结构优化

可以考虑将一些功能模块化,提高代码的可读性和维护性。例如,将文字水印的添加功能独立成一个方法。

1

2

3

4

5

class WatermarkText():

    # existing code...

 

    def add_text_watermark(self, img):

        # existing code...

8.4 日志记录

考虑在程序中添加日志记录,记录关键步骤和出错信息,以便于排查问题。

1

2

3

4

5

6

7

8

9

10

11

12

13

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得到的文件扩展名可能包含大写字母,为了确保匹配,可以将文件扩展名转换为小写。

1

2

3

4

if filetype.lower() == '.png':

    watermark_text.add_text_watermark(filepath)

else:

    print("Error: Image format is not supported. Please use PNG format.")

10. 增加用户交互性

可以考虑在程序中增加更多用户交互性,比如在成功添加水印后询问用户是否继续添加水印。

1

2

3

4

5

6

7

8

9

10

11

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模块实现。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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()方法注册其他格式的图片打开器。
  • 如果水印文字较长,可以考虑自动调整文字大小,以适应图片。

版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 :
相关文章
  • Go中gin框架的*gin.Context参数常见实用方法
    梗概: *gin.Context是处理HTTP请求的核心。ctx代表context(上下文),它包含了处理请求所需的所有信息和方法,例如请求数据、响应构建器、
  • Python实现图像添加水印的方法
    在日常图像处理中,为图片添加水印是一项常见任务。有多种方法和工具可供选择,而今天我们将专注于使用Python语言结合PIL库批量添加水
  • go的defer和return的执行顺序介绍
    go的defer和return的执行顺序 go的defer和return是golang中的两个关键字,return用于返回函数的返回值,也可以参与一定的流程控制,比如下面代码
  • 使用go语言实现Redis持久化的代码
    redis是一个内存数据库,如果你把进程杀掉,那么里面存储的数据都会消失,那么这篇文章就是来解决redis持久化的问题 我们在redis.conf文件
  • Go中的Timer和Ticker介绍
    一:简介 在日常开发中,我们可能会遇到需要延迟执行或周期性地执行一些任务。这个时候就需要用到Go语言中的定时器。 在Go语言中,定
  • Golang在gin框架中使用JWT鉴权
    什么是JWT JWT,全称 JSON Web Token,是一种开放标准(RFC 7519),用于安全地在双方之间传递信息。尤其适用于身份验证和授权场景。JWT 的设计
  • Golang使用Redis与连接池方式
    Golang使用Redis与连接池 使用下载go的redis包go get github.com/gomodule/redigo/redis 如果网不好的话就很费劲了 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2
  • Golang使用embed引入静态文件的代码
    Go 语言从 1.16 版本开始引入了一个新的标准库embed,可以在二进制文件中引入静态文件 指令:/go:embed 通过一个简单的小实例,来演示将静态
  • Golang发送Get和Post请求的实现
    最近在研究钉钉机器人,发现钉钉的第三方接口有时需要用Get或者Post请求访问,虽然说可以通过Apifox直接模拟发送请求,但是我还是想研究
  • Go实现数据脱敏的方案设计
    在一些常见的业务场景中可能涉及到用户的手机号,银行卡号等敏感数据,对于这部分的数据经常需要进行数据脱敏处理,就是将此部分数
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计