用 pil.image.paste() 叠加透明 png 水印最稳妥,因 imagedraw.text() 存在字体路径不一致、中文报错、缩放失真三大硬伤;水印图须背景全透明、尺寸适中、带 alpha 保存、命名规范;批量处理需转 rgba、按比例缩放、指定 mask 叠加,并注意内存优化。

直接用 PIL.Image.paste() 叠加透明水印图最稳妥,别用 ImageDraw.text() 手动画文字——抗锯齿差、缩放失真、中文字体路径容易出错。
为什么不用 ImageDraw.text() 加文字水印?
实际批量处理时,ImageDraw.text() 会暴露三个硬伤:字体文件路径在不同机器上不一致(尤其 Windows/macOS/Linux 差异大);中文字符常因未指定 font 参数直接报 OSError: cannot open resource;文字缩放后边缘发虚、倾斜角度稍大就糊成一片。而 PNG 水印图是预渲染好的,透明通道可控,叠加位置和缩放比例稳定。
如何准备一张可用的水印 PNG 图?
水印图不是随便截个带字的图就行,必须满足:
• 背景完全透明(Alpha 通道值为 0),不能是白底+半透明字;
• 尺寸适中(建议 400×100 像素以内),太大导致批量处理内存暴涨;
• 保存为带 Alpha 的 PNG(用 Photoshop 或 GIMP 导出时勾选 “Transparency”);
• 文件名不含中文或空格,例如 watermark_alpha.png。
批量叠加水印的核心代码怎么写?
关键在四步:打开原图 → 转为 RGBA 模式(确保有 Alpha 通道)→ 调整水印尺寸(按原图宽高比例缩放)→ 用 paste() 带 mask 叠加。示例片段:
from PIL import Image
import os
<p>watermark = Image.open("watermark_alpha.png").convert("RGBA")
for img_path in ["a.jpg", "b.png", "c.webp"]:
with Image.open(img_path) as base:
base = base.convert("RGBA") # 强制转 RGBA,避免 paste 报错</p><h1>按 base 宽高 15% 缩放 watermark</h1><pre class="brush:python;toolbar:false;"> w, h = base.size
wm_resized = watermark.resize((int(w * 0.15), int(h * 0.15)), Image.LANCZOS)
# 计算右下角位置(留 20px 边距)
pos = (w - wm_resized.width - 20, h - wm_resized.height - 20)
base.paste(wm_resized, pos, mask=wm_resized) # 第三个参数 mask 必须传!
base.convert("RGB").save(f"out_{os.path.basename(img_path)}", quality=95)
注意:paste() 的第三个参数 mask 不能省略,否则透明区域变成黑块;WebP 图需先 convert("RGB") 再保存,否则可能丢 Alpha 或报错。
批量处理时容易卡死或爆内存?
常见于一次性 load 几十张高清图。解决方法:
• 用 with Image.open() 确保句柄及时释放;
• 避免把所有结果图存成 list,边处理边 save;
• 对超大图(>5000px 边长),先 thumbnail() 缩略再加水印;
• 不要用 Image.open().copy(),改用 convert() 或 crop() 这类惰性操作。
水印的透明度、角度、重复平铺这些进阶需求,得靠 ImageEnhance.Brightness() 调 alpha 通道,或用 rotate() + paste() 多次叠加——但第一次跑通单水印逻辑前,别碰这些。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











