pin_drop当前位置:知识文库 ❯ 图文

Pillow图片水印添加详解 - 文字水印半透明平铺水印教程

一、图片水印概述

图片水印是在图像上叠加文字或图案以标识版权、来源或状态的技术。Pillow通过 ImageDraw 绘制文字水印、通过 paste() 方法粘贴图片水印、通过 alpha_composite() 合成透明通道来实现各种水印效果。

水印可以分为可见水印(明显标注,如摄影网站上的版权信息)和半透明水印(低透明度,不易察觉但保留版权标识),是图像版权保护的重要手段。平铺水印由于覆盖整张图片,比单点水印更难被裁剪去除,保护效果更好。

二、语法与参数说明

基本语法

代码示例

from PIL import Image, ImageDraw, ImageFont

# 文字水印绘制
draw = ImageDraw.Draw(img)
draw.text(position, text, fill=color, font=font)

# 图片水印(带透明度合成)
img.paste(watermark, position, mask=watermark)

文字水印参数

参数 类型 必填 说明
position tuple 水印位置 (x, y)
text str 水印文字内容
fill str/tuple 文字颜色
font ImageFont对象 字体对象

paste() 图片水印参数

参数 类型 必填 说明
im Image对象 要粘贴的水印图像
box tuple 粘贴位置 (x, y)
mask Image对象 透明度蒙版

返回值

draw.text()img.paste()无返回值,直接在原图上绘制或粘贴修改。

三、文字水印详解

简单文字水印:直接在图像上绘制文字,适合简单场景。通过 ImageFont.truetype() 加载字体文件,使用 font.getbbox() 计算文字尺寸以便精确控制位置。

半透明文字水印:需要创建独立的RGBA图层,在该图层上绘制半透明文字(通过四元组颜色 (R, G, B, Alpha) 控制透明度),然后使用 Image.alpha_composite() 将水印层与主图合成。

平铺水印:通过循环在多个位置绘制相同文字,使水印铺满整张图片。平铺水印比单点水印更难被裁剪去除,是版权保护推荐的方式。可以结合旋转角度实现倾斜铺满效果。

四、代码示例

示例1:简单文字水印(右下角)

代码示例

from PIL import Image, ImageDraw, ImageFont

# 创建测试图像
img = Image.new('RGB', (400, 300), color='white')
draw = ImageDraw.Draw(img)

# 加载字体(尝试系统字体,失败则使用默认字体)
try:
    font = ImageFont.truetype("arial.ttf", 36)
except OSError:
    font = ImageFont.load_default()

# 计算水印文字尺寸
text = "Copyright 2024"
bbox = font.getbbox(text)
text_w = bbox[2] - bbox[0]
text_h = bbox[3] - bbox[1]

# 计算右下角位置(留出10像素边距)
x = img.width - text_w - 10
y = img.height - text_h - 10

# 绘制文字水印
draw.text((x, y), text, fill='gray', font=font)
print(f"文字水印位置: ({x}, {y})")
img.save('text_watermark.png')

输出:

代码示例

文字水印位置: (195, 248)

示例2:半透明文字水印

代码示例

from PIL import Image, ImageDraw, ImageFont

# 创建主图像
img = Image.new('RGB', (400, 300), color='skyblue')

# 创建半透明水印层(RGBA模式,初始完全透明)
watermark_layer = Image.new('RGBA', img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark_layer)

try:
    font = ImageFont.truetype("arial.ttf", 30)
except OSError:
    font = ImageFont.load_default()

# 绘制半透明文字(RGBA四元组,第四个值为透明度0-255)
draw.text((50, 100), "SAMPLE", fill=(255, 255, 255, 80), font=font)
draw.text((50, 150), "DRAFT", fill=(255, 0, 0, 100), font=font)

# 将主图转为RGBA模式,然后与水印层合成
img_rgba = img.convert('RGBA')
composite = Image.alpha_composite(img_rgba, watermark_layer)
result = composite.convert('RGB')

result.save('transparent_watermark.png')
print("半透明水印已添加")

输出:

代码示例

半透明水印已添加

示例3:平铺水印

代码示例

from PIL import Image, ImageDraw, ImageFont

# 创建主图像
img = Image.new('RGB', (400, 300), color='lightyellow')

try:
    font = ImageFont.truetype("arial.ttf", 20)
except OSError:
    font = ImageFont.load_default()

text = "WATERMARK"
bbox = font.getbbox(text)
tw = bbox[2] - bbox[0]
th = bbox[3] - bbox[1]

# 创建透明水印层
watermark_layer = Image.new('RGBA', img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark_layer)

# 循环平铺水印文字(每60像素一行,每150像素一列)
for y in range(0, img.height, 60):
    for x in range(0, img.width, 150):
        draw.text((x, y), text, fill=(200, 200, 200, 60), font=font)

# 合成水印层与主图
img_rgba = img.convert('RGBA')
composite = Image.alpha_composite(img_rgba, watermark_layer)
result = composite.convert('RGB')

result.save('tiled_watermark.png')
print("平铺水印已添加")

输出:

代码示例

平铺水印已添加

五、水印方式对比表格

水印类型 实现方式 透明度支持 防去除能力 适用格式
文字水印 draw.text() 有限 PNG/JPEG
半透明文字 RGBA合成 支持 PNG
图片水印 paste+mask 支持 PNG
平铺水印 循环绘制 支持 PNG

六、实际应用场景

  • 摄影作品版权保护:摄影师在发布作品前添加半透明版权水印,既不影响观赏效果,又能标识作品归属,防止未经授权的盗用。

  • 内部文档状态标识

  • 电商平台防盗图:电商平台商品图添加店铺Logo水印,使用平铺方式铺满图片,防止竞争对手直接盗用商品图片。

小贴士

计算文字位置时,推荐使用 font.getbbox(text) 方法获取文字边界框,然后计算文字宽高:text_w = bbox[2] - bbox[0]text_h = bbox[3] - bbox[1]。这是Pillow 9.2.0+推荐的方法,替代了已过时的 textsize()

七、注意事项

注意1:半透明水印需要使用 RGBA模式,最终保存为 PNG格式 才能保留透明度效果。JPEG格式不支持透明度。

注意2:JPEG格式不支持透明度,保存为JPEG时水印的透明效果会丢失,半透明区域会与白色背景混合。如果必须使用JPEG,建议直接调整水印颜色而不使用Alpha通道。

注意3:水印位置应避免遮挡图像的重要内容区域。一般推荐右下角、左下角或平铺方式。

注意4平铺水印比单点水印更难被裁剪去除,保护效果更好。可以结合45度旋转实现倾斜铺满,进一步增加去除难度。

八、常见问题FAQ

常见问题

为什么加载字体时会出现OSError错误?

因为指定的字体文件路径不存在。建议使用try/except包裹 ImageFont.truetype(),失败时回退到 ImageFont.load_default()。Windows系统字体通常在 C:\Windows\Fonts\ 目录下。

如何实现旋转45度的平铺水印?

可以先在一张更大的画布上绘制水平文字,然后使用 watermark_layer.rotate(45, expand=True) 旋转,最后裁剪到与原图相同尺寸并合成。

水印会影响图片的文件大小吗?

会有一定影响。平铺水印会增加图像的信息复杂度,导致JPEG压缩效率降低,文件略微增大。PNG格式由于是无损压缩,增加更明显。但对于大多数场景,这种增加可以忽略不计。

alpha_composite和paste有什么区别?

alpha_composite() 要求两个图像都必须是RGBA模式,按Alpha通道精确合成。paste(im, box, mask) 的mask参数也可以用作透明度蒙版,但更灵活——mask可以是'L'模式(灰度)或'1'模式(二值)。

如何批量为多张图片添加相同水印?

可以编写一个函数封装水印添加逻辑,然后用 globos.listdir() 遍历目录中的所有图片,逐一调用该函数处理并保存。

九、练习题

练习1

编写函数 add_watermark(image_path, text, position='center'),支持在图片中心(center)、左上角(top-left)、右下角(bottom-right)三个位置添加文字水印,保存为新图片。

练习2

编写程序,创建一个带旋转角度的平铺水印效果:水印文字以45度倾斜角度铺满整张图片,文字内容为"CONFIDENTIAL",透明度设为50。


标签: Pillow 图片水印 ImageDraw 半透明水印 平铺水印 版权保护 Python图像处理

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Pillow GIF动画处理详解 - 读取创建编辑GIF帧完整教程 下一篇: Python Selenium库入门教程 - 安装使用指南

poll相关推荐