白日依山尽,黄河入海流。欲穷千里目,更上一层楼。 -- 唐·王之涣

Python实现图片添加水印(支持中文、英文和图片)

阅读大纲

  • 图片水印忽大忽小问题研究
  • 中文水印乱码问题
  • 水印的动态展示

背景

在上次CSDN中发表技术文章的时候,文章中涉及到图片,CSDN会自动上传然后添加水印,突然注意到上传之后的图片的水印超级小,就在右下角一丢丢点,不注意还以为没有添加呢,然后对比这里之前文章的水印发现显示挺正常合适的。

为啥有时候显示的很适合,有时候显示的特别小呢?

然后去微信公账号的平台测试下了,同样的图片,微信公众号显示合适(比例、位置等看来正常,不是忽大忽小)

研究问题所在

之前用Python写过给图片添加水印的小工具,然后用该工具经常测试、验证问题所在。

经过使用不同尺寸和大小的图片测试和验证发现问题所在。出现在两个点上

1、水印举例图片边距是固定的,比如都是10px
2、文字水印没有设置字体或者设置了固定大小

针对第一个点,比如图片A尺寸 300px * 200px,如果默认边距是10px。

下面这个是测试使用的Demo程序

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/12/18 5:51 下午
# @Author : Colin
# @Email : colin@colinspace.com
# @File : testImageWatermark.py
# @Software : PyCharm
#

from PIL import Image
from PIL import ImageDraw

# 定义一个水印
watermark = "Hello Python!"
# 定义边距,水印举例原始图片的边距
border = 10
# 先画一个尺寸为200*300背景色为灰色的图片;然后通过设置不同的尺寸来观察水印的位置和大小
# img = Image.new('RGBA', (300, 200), 'gray')
# img = Image.new('RGBA', (900, 600), 'gray')
img = Image.new('RGBA', (3000, 2000), 'gray')
text_layer = ImageDraw.Draw(img)
# 计算水印文字的大小,为了更精确的存放水印位置
text_xy = text_layer.textsize(watermark)
# 注意计算位置,添加水印一般都是 左上角、右上角、右下角、左下角或者中心位置等特殊点;最常见的就是在右下角
# 计算水印在右下角的位置
watermark_xy = (img.size[0] - text_xy[0] - 10, img.size[1] - text_xy[1] - 10)
# print("原始图片的大小: ", img.size)
# print("水印文字的大小: ", text_xy)
# print("水印文字的位置: ", watermark_xy)
text_layer.text(watermark_xy, watermark, fill='orange')
img.show()

通过调整原始图片的大小,然后展示最终的结果很容易发现问题,为了节约篇幅,把三次测试结果调整到一个截图中缩放到相同的尺寸,可以看到图片越大,水印(水印本身的大小没有发生变化)越来越小
在这里插入图片描述
同样的,如果设置了水印的字体,但是字体大小固定,即使边距随之动态变化,那么情况也和上面类似,只是水印的位置不固定了而已。

因为设置字体设计到 中文水印乱码 的问题,我们放到第二趴介绍。

同时这里思考一个问题,如何实现水印边距随之动态变化 ?


中文水印乱码

中文水印乱码或者更正确的说是中文水印导致的报错问题。

报错信息如下
中文水印报错

原因就是未配置字体导致的,至于为什么,可以查看pillow的源码中ImageFont.py ImageFont 类中getmask方法中提示

1
2
If the font uses antialiasing, the bitmap should have mode ``L`` 
and use a maximum value of 255. Otherwise, it should have mode ``1``.

我们修改最开始的Demo,添加如下代码

1
2
3
4
5
6
7
# 定义字体
font_path = "/Users/colinspace/Library/Fonts/LXGWWenKai-Regular.ttf"
font = ImageFont.truetype(font_path, 20)

# 修改添加font
text_xy = text_layer.textsize(watermark, font=font)
text_layer.text((100, 50), watermark, fill='orange', font=font)

最终的完整Demo代码详见 testImageWatermark.py


水印的动态展示

水印的动态上面提到需要解决两个问题

1、水印距离原始图片的动态边距
2、水印字体大小的动态设定

为了解决动态设定 使之随图片尺寸而变化。最简单的就是通过百分比 来实现,取长或者宽的百分比。代码如下

1
2
3
4
5
6
7
8
9
10
11
# 左右间距,采用图片比例的扩展,可以有效解决不同大小图片,水印位置相对一致
border = 0
if im.size[0] > im.size[1]:
border = int(im.size[1]/100*3)
else:
border = int(im.size[0]/100*3)

# 设置字体
font_path = "/Users/colinspace/Library/Fonts/LXGWWenKai-Regular.ttf"
# 字体大小设置为上面定义的border,这样可以修复遇到超大图片时因为设定固定字体导致文字水印过小的问题
font = ImageFont.truetype(font_path, border)

最终完善工具脚本支持

1、中文、英文 文字水印
2、图片水印
3、修复因为图片过大导致 文字水印超小的问题
4、解决中文水印乱码问题
5、支持添加到不同的位置,左上角、右上角、左下角、右下角、中心位置
6、支持设置水印颜色

最终完整脚本详见: python添加水印工具

或者 CSDN的资源下载


可以关注公众号,第一时间获取最新分享哦~
在这里插入图片描述


References

[1] testImageWatermark.py: https://gitee.com/colin5063/cws-tools/blob/master/python/testImageWatermark.py
[2] python添加水印工具: https://gitee.com/colin5063/cws-tools/blob/master/python/cws_image.py

作者

Colin

发布于

2021-12-23

许可协议