
Python在图像处理领域有强大的能力和灵活性,无论是简单的文字水印还是复杂的透明图层混合,都能轻松实现。第三方库如filestools更是将复杂的水印效果简化为一行代码,大大提高了开发效率。本文将全面介绍如何使用Python实现图片水印的批量自动化添加,涵盖基础的Pillow库操作和高级的filestools工具应用,帮助高效完成图片添加水印工作。
Pillow库是Python图像处理的标准库,能够处理多种图片格式,支持打开、操作和保存各种图像文件。filestools是第三方库,其中的watermarker模块可以用一行代码就实现水印效果。
pip install pillow # 基础图像处理库
pip install filestools -U # 高级水印工具库导入模块:
from PIL import Image, ImageDraw, ImageFont
import os
from watermarker.marker import add_mark from PIL import Image, ImageDraw, ImageFont
import os
from watermarker.marker import add_mark
image = Image.open(r'E:\learn\gzh\image-20250703172759851.png')
# 创建绘图对象
draw = ImageDraw.Draw(image)
# 设置字体(Windows系统可以使用simhei.ttf支持中文)
font = ImageFont.truetype('simhei.ttf', 36) # 或者使用'simhei.ttf'
# 设置水印文字颜色(RGB格式)
text_color = (0, 255, 0)
# 在图片右下角添加水印
width, height = image.size
draw.text((width - 450, height - 150), "Nicholas与Pypi", fill=text_color, font=font)
# 将图像模式从 RGBA 转换为 RGB
image = image.convert('RGB')
# 保存图片
image.save(r'E:\learn\gzh\watermarked_test.jpg')
注意事项:
from PIL import Image, ImageDraw, ImageFont
import os
from watermarker.marker import add_mark
# 打开原始图片并转换为RGBA模式
image = Image.open(r'E:\learn\gzh\watermarked_test.jpg').convert('RGBA')
# 创建透明图层
watermark_layer = Image.new('RGBA', image.size, (0, 0, 0, 0))
# 在透明图层上绘制水印
draw = ImageDraw.Draw(watermark_layer)
# 设置字体(确保字体文件路径正确)
font = ImageFont.truetype('simhei.ttf', 36)
text_color = (255, 255, 255, 128) # 白色,50%透明度
width, height = image.size
text = "Nicholas与Pypi"
# 计算文字尺寸
text_bbox = draw.textbbox((0, 0), text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
# 计算文字位置(正中心)
x = (width - text_width) / 2
y = (height - text_height) / 2
draw.text((x, y), text, fill=text_color, font=font)
# 合并图层
combined_image = Image.alpha_composite(image, watermark_layer)
# 保存图片(转换为RGB模式以兼容JPEG格式)
combined_image.convert('RGB').save(r'E:\learn\gzh\watermarked_test1.jpg')
这种方法可以实现更灵活的水印效果,包括透明度控制、图层混合等高级功能。
单张图片的水印添加后,可以扩展为批量处理,大大提高效率。
from PIL import Image, ImageDraw, ImageFont
import os
def calculate_position(base_size, text_size, position='bottom-right'):
"""计算水印位置"""
positions = {
'top-left': (20, 20),
'top-right': (base_size[0] - text_size[0] - 20, 20),
'center': ((base_size[0] - text_size[0]) // 2,
(base_size[1] - text_size[1]) // 2),
'bottom-left': (20, base_size[1] - text_size[1] - 20),
'bottom-right': (base_size[0] - text_size[0] - 20,
base_size[1] - text_size[1] - 20)
}
return positions.get(position, (0, 0))
def adjust_opacity(color, opacity):
"""调整颜色透明度"""
return (color[0], color[1], color[2], int(255 * opacity))
# 水印参数设置
watermark_text = "Nicholas与Pypi"
base_font_size = 36
text_color = (0, 255, 0) # 绿色
opacity = 0.5 # 50%透明度
position = 'bottom-right' # 水印位置
# 图片文件夹路径
image_folder = 'images'
output_folder = 'watermarked_images'
# 创建输出文件夹
os.makedirs(output_folder, exist_ok=True)
# 遍历文件夹中的所有文件
for filename in os.listdir(image_folder):
# 检查文件扩展名
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
# 打开图片
image_path = os.path.join(image_folder, filename)
image = Image.open(image_path).convert('RGBA')
# 自适应字体大小
font_size = int(min(image.size) * 0.05)
font = ImageFont.truetype('simhei.ttf', font_size)
# 创建透明图层
txt_layer = Image.new('RGBA', image.size, (255, 255, 255, 0))
draw = ImageDraw.Draw(txt_layer)
# 计算水印位置
bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x, y = calculate_position(image.size, (text_width, text_height), position)
# 调整透明度
adjusted_color = adjust_opacity(text_color, opacity)
# 绘制水印
draw.text((x, y), watermark_text, font=font, fill=adjusted_color)
# 合并图层并保存
watermarked = Image.alpha_composite(image, txt_layer)
output_path = os.path.join(output_folder, filename)
watermarked.convert('RGB').save(output_path)
print(f"已处理: {filename}")calculate_position 函数,你可以轻松设置水印的位置,支持 top-left、top-right、center、bottom-left 和 bottom-right。adjust_opacity 函数,你可以调整水印的透明度,范围从 0(完全透明)到 1(完全不透明)。将代码中 image_folder 和 output_folder 变量设置为你的图片文件夹路径和输出文件夹路径。根据需要调整 watermark_text、text_color、opacity 和 position 参数。运行代码后,所有处理后的图片将保存在 output_folder 中。
filestools库提供的watermarker模块可以实现一行代码添加水印的强大功能,可以极大的提升效率和简便性。
from watermarker.marker import add_mark
add_mark(file=r'E:\learn\gzh\image-20250703172759851.png',
out=r'E:\learn\gzh\watermarked_test2.jpg',
mark="Nicholas与Pypi",
opacity=0.3,
angle=30,
space=30,
size=50)参数说明:
file: 原始图片路径;out: 输出图片路径或文件夹;mark: 水印文字内容;opacity: 透明度(0-1);angle: 旋转角度;space: 水印间距;size: 字体大小;
import os
from watermarker.marker import add_mark
input_folder = "images"
output_folder = "watermarked_images"
watermark_text = "Nicholas与Pypi"
# 创建输出文件夹
os.makedirs(output_folder, exist_ok=True)
# 遍历文件夹中的所有文件
for filename in os.listdir(input_folder):
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
# 构造完整的输出文件路径
output_path = os.path.join(output_folder, filename)
add_mark(file=os.path.join(input_folder, filename),
out=output_path,
mark=watermark_text,
opacity=0.3,
angle=30,
space=30,
size=50)output_path = os.path.join(output_folder, filename):构造完整的输出文件路径,确保输出文件保存在 output_folder 中,并且文件名与输入文件相同。add_mark(..., out=output_path, ...):将完整的输出文件路径传递给 add_mark 函数。filestools库的水印功能不仅代码简洁,而且生成的水印效果专业,默认具有旋转和间隔排列的特性,能有效防止简单裁剪去除水印。
使用python的tkinter为水印工具开发图形界面,让非技术人员也能方便使用。
from PIL import Image, ImageDraw, ImageFont
import os
from watermarker.marker import add_mark
import tkinter as tk
from tkinter import filedialog, messagebox
class WatermarkApp:
def __init__(self, root):
self.root = root
self.root.title("批量图片水印工具")
# 输入文件夹
tk.Label(root, text="图片文件夹:").grid(row=0, column=0, sticky="e")
self.input_entry = tk.Entry(root, width=50)
self.input_entry.grid(row=0, column=1)
tk.Button(root, text="浏览", command=self.browse_input).grid(row=0, column=2)
# 水印文字
tk.Label(root, text="水印文字:").grid(row=1, column=0, sticky="e")
self.watermark_entry = tk.Entry(root, width=50)
self.watermark_entry.grid(row=1, column=1)
# 输出文件夹
tk.Label(root, text="输出文件夹:").grid(row=2, column=0, sticky="e")
self.output_entry = tk.Entry(root, width=50)
self.output_entry.grid(row=2, column=1)
tk.Button(root, text="浏览", command=self.browse_output).grid(row=2, column=2)
# 水印位置
tk.Label(root, text="水印位置:").grid(row=3, column=0, sticky="e")
self.position_var = tk.StringVar(value="bottom-right")
positions = ["top-left", "top-right", "center", "bottom-left", "bottom-right"]
for i, pos in enumerate(positions):
tk.Radiobutton(root, text=pos, variable=self.position_var, value=pos).grid(row=3, column=1+i, sticky="w")
# 透明度
tk.Label(root, text="透明度(10-100):").grid(row=4, column=0, sticky="e")
self.opacity_scale = tk.Scale(root, from_=10, to=100, orient=tk.HORIZONTAL)
self.opacity_scale.set(50)
self.opacity_scale.grid(row=4, column=1, columnspan=2, sticky="ew")
# 执行按钮
tk.Button(root, text="开始添加水印", command=self.process_images).grid(row=5, column=1)
def browse_input(self):
folder = filedialog.askdirectory()
if folder:
self.input_entry.delete(0, tk.END)
self.input_entry.insert(0, folder)
def browse_output(self):
folder = filedialog.askdirectory()
if folder:
self.output_entry.delete(0, tk.END)
self.output_entry.insert(0, folder)
def process_images(self):
input_folder = self.input_entry.get()
output_folder = self.output_entry.get()
watermark_text = self.watermark_entry.get()
position = self.position_var.get()
opacity = self.opacity_scale.get() / 100
if not all([input_folder, output_folder, watermark_text]):
messagebox.showerror("错误", "请填写所有必要字段!")
return
os.makedirs(output_folder, exist_ok=True)
for filename in os.listdir(input_folder):
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
try:
image = Image.open(os.path.join(input_folder, filename)).convert('RGBA')
watermark = Image.new('RGBA', image.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)
# 计算字体大小
font_size = int(min(image.size) * 0.05)
font = ImageFont.truetype("simhei.ttf", font_size)
# 计算水印位置
bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x, y = self.calculate_position(image.size, (text_width, text_height), position)
# 绘制水印
draw.text((x, y), watermark_text, font=font, fill=(0, 255, 0, int(255 * opacity)))
# 合并保存
combined = Image.alpha_composite(image, watermark)
combined.convert('RGB').save(os.path.join(output_folder, filename))
except Exception as e:
print(f"处理 {filename} 时出错: {e}")
messagebox.showinfo("完成", "水印添加完成!")
def calculate_position(self, base_size, text_size, position):
if position == "top-left":
return (20, 20)
elif position == "top-right":
return (base_size[0] - text_size[0] - 20, 20)
elif position == "center":
return ((base_size[0] - text_size[0]) // 2, (base_size[1] - text_size[1]) // 2)
elif position == "bottom-left":
return (20, base_size[1] - text_size[1] - 20)
else: # bottom-right
return (base_size[0] - text_size[0] - 20, base_size[1] - text_size[1] - 20)
“无他,惟手熟尔”!有需要的用起来。
如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!