场景引入
公司有 5000 张产品图片需要加上公司 logo 水印,或 2000 张员工工牌照片需要加盖"仅限内部使用"的文字水印。用 photoshop 一张一张处理,一个人都要干半天。
本节教你用 python 的 pillow 库,批量为图片添加文字水印或图片水印,每秒处理几十张。
技术原理
使用 pillow(pil fork)库操作图片:
| 水印类型 | 实现方式 |
|---|---|
| 文字水印 | imagedraw.text() |
| 图片水印(logo) | image.paste() 或 image.alpha_composite() |
| 半透明水印 | 创建透明图层 + image.blend() |
| 倾斜水印 | image.rotate() |
原图 → 创建透明图层 → 绘制水印 → 叠加到原图 → 保存
环境准备
pip install pillow
完整代码
from pil import image, imagedraw, imagefont, imageenhance
import os
from pathlib import path
# ==================== 方案 1:文字水印 ====================
def add_text_watermark(input_image, output_image, text="内部资料",
position="center", font_size=40, color=(255, 255, 255, 128),
angle=0):
"""
为图片添加文字水印
参数:
input_image: 输入图片路径
output_image: 输出图片路径
text: 水印文字
position: 位置 'center'/'bottom-right'/'bottom-left'/'top-right'/'top-left'
font_size: 字体大小
color: 字体颜色 (r, g, b, a)
angle: 旋转角度(0=水平,-30=左倾斜)
"""
# 打开图片
img = image.open(input_image).convert('rgba')
# 创建透明图层
txt_layer = image.new('rgba', img.size, (255, 255, 255, 0))
draw = imagedraw.draw(txt_layer)
# 获取字体
try:
font = imagefont.truetype("c:/windows/fonts/msyh.ttc", font_size) # 微软雅黑
except:
font = imagefont.load_default()
# 计算文字大小和位置
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
img_width, img_height = img.size
positions = {
'center': ((img_width - text_width) // 2, (img_height - text_height) // 2),
'bottom-right': (img_width - text_width - 20, img_height - text_height - 20),
'bottom-left': (20, img_height - text_height - 20),
'top-right': (img_width - text_width - 20, 20),
'top-left': (20, 20),
}
x, y = positions.get(position, positions['center'])
# 如果需要旋转
if angle != 0:
# 创建更大的图层以容纳旋转后的文字
big_layer = image.new('rgba', (img_width * 2, img_height * 2), (255, 255, 255, 0))
big_draw = imagedraw.draw(big_layer)
big_draw.text((img_width // 2, img_height // 2), text, font=font, fill=color)
big_layer = big_layer.rotate(angle, expand=0)
txt_layer = big_layer.crop((img_width // 2, img_height // 2,
img_width // 2 + img_width,
img_height // 2 + img_height))
else:
draw.text((x, y), text, font=font, fill=color)
# 叠加
result = image.alpha_composite(img, txt_layer)
# 保存(转回 rgb 以便保存为 jpeg)
result = result.convert('rgb')
result.save(output_image, quality=95)
print(f"文字水印: {os.path.basename(input_image)}")
# ==================== 方案 2:图片水印(logo) ====================
def add_image_watermark(input_image, output_image, logo_path,
position="bottom-right", opacity=0.5, scale=0.15):
"""
为图片添加 logo 水印
参数:
input_image: 输入图片
output_image: 输出图片
logo_path: logo 图片路径(建议 png 透明背景)
position: 位置
opacity: 透明度(0-1,1=完全不透明)
scale: logo 相对原图大小的比例(0.15=15%)
"""
img = image.open(input_image).convert('rgba')
# 打开 logo
logo = image.open(logo_path).convert('rgba')
# 缩放 logo
new_logo_size = (int(img.width * scale), int(img.height * scale * logo.height / logo.width))
logo = logo.resize(new_logo_size, image.lanczos)
# 设置 logo 透明度
if opacity < 1:
# 调整 alpha 通道
r, g, b, a = logo.split()
a = a.point(lambda x: int(x * opacity))
logo = image.merge('rgba', (r, g, b, a))
# 计算位置
positions = {
'center': ((img.width - logo.width) // 2, (img.height - logo.height) // 2),
'bottom-right': (img.width - logo.width - 20, img.height - logo.height - 20),
'bottom-left': (20, img.height - logo.height - 20),
'top-right': (img.width - logo.width - 20, 20),
'top-left': (20, 20),
}
x, y = positions.get(position, positions['bottom-right'])
# 创建透明图层并粘贴 logo
watermark_layer = image.new('rgba', img.size, (0, 0, 0, 0))
watermark_layer.paste(logo, (x, y))
# 叠加
result = image.alpha_composite(img, watermark_layer)
result = result.convert('rgb')
result.save(output_image, quality=95)
print(f"logo水印: {os.path.basename(input_image)}")
# ==================== 方案 3:平铺水印(全屏重复) ====================
def add_tiled_watermark(input_image, output_image, text="内部资料",
font_size=30, color=(255, 255, 255, 50), angle=-30, spacing=150):
"""
添加平铺水印(全屏重复文字)
"""
img = image.open(input_image).convert('rgba')
txt_layer = image.new('rgba', img.size, (255, 255, 255, 0))
draw = imagedraw.draw(txt_layer)
try:
font = imagefont.truetype("c:/windows/fonts/msyh.ttc", font_size)
except:
font = imagefont.load_default()
# 计算文字大小
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# 平铺
y = 0
while y < img.height:
x = 0
row_offset = (y // spacing) % 2 * (spacing // 2) # 错行排列
while x < img.width:
draw.text((x + row_offset, y), text, font=font, fill=color)
x += text_width + spacing
y += text_height + spacing
result = image.alpha_composite(img, txt_layer)
result = result.convert('rgb')
result.save(output_image, quality=95)
print(f"平铺水印: {os.path.basename(input_image)}")
# ==================== 批量处理 ====================
def batch_add_watermark(input_dir, output_dir, watermark_func, **kwargs):
"""
批量为文件夹中的所有图片添加水印
"""
input_path = path(input_dir)
output_path = path(output_dir)
output_path.mkdir(parents=true, exist_ok=true)
image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tiff'}
count = 0
for file_path in input_path.iterdir():
if file_path.is_file() and file_path.suffix.lower() in image_extensions:
output_file = output_path / file_path.name
watermark_func(str(file_path), str(output_file), **kwargs)
count += 1
print(f"\n批量水印完成: {count} 张图片")
# ==================== 使用示例 ====================
if __name__ == "__main__":
# 单个文件
# add_text_watermark("工牌照片.jpg", "工牌_水印.jpg", text="内部资料", position="center", font_size=50)
# 批量文字水印
batch_add_watermark(
input_dir="原始工牌照片",
output_dir="已加水印",
watermark_func=add_text_watermark,
text="仅限内部使用",
position="center",
font_size=40,
)
# 批量 logo 水印
# batch_add_watermark(
# input_dir="产品图片",
# output_dir="已加logo",
# watermark_func=add_image_watermark,
# logo_path="company_logo.png",
# position="bottom-right",
# opacity=0.7,
# scale=0.1
# )
# 平铺水印(防截图)
# batch_add_watermark(
# input_dir="机密文档截图",
# output_dir="平铺水印",
# watermark_func=add_tiled_watermark,
# text="机密文件",
# font_size=25,
# angle=-30,
# )
常见问题
q1:中文水印显示为方框?
需要指定中文字体路径:
font = imagefont.truetype("c:/windows/fonts/msyh.ttc", font_size) # 微软雅黑
# 或
font = imagefont.truetype("c:/windows/fonts/simsun.ttc", font_size) # 宋体
q2:水印太显眼覆盖了图片内容?
调整 color 的 alpha 值(第四个参数):
color=(255, 255, 255, 50) # alpha=50,更透明
q3:保存 png 后水印不见了?
确保保存时使用 rgba 模式并指定 png 格式:
result.save(output_image, 'png')
总结
| 水印类型 | 函数 | 适用场景 |
|---|---|---|
| 文字水印 | add_text_watermark() | 版权声明 |
| logo 水印 | add_image_watermark() | 品牌标识 |
| 平铺水印 | add_tiled_watermark() | 防泄漏标记 |
本节掌握了为图片批量添加水印的能力。
到此这篇关于python pillow库批量为图片添加文字水印或图片水印的文章就介绍到这了,更多相关python图片添加水印内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论