【Python】图片加水印 - 无损高清 - 性能强劲版
一、引言
- 在技术课程、文案处理创作中,本着分享的初心,但经常遇到辛苦创作的内容被拿去售卖的情况,因此为图片添加水印是保护版权和增加抄袭成本的有效手段。
- 本文基于Python的Pillow库,提供【无损高清水印】的添加方案,支持透明度调节与批量处理,确保输出画质不受损。
二、技术方案与优势
1.无损处理原理
- 通过RGBA模式保留原始图像的Alpha通道,避免JPEG压缩导致的画质损失,最终可保存为PNG或JPEG等格式图片。
- 双模式水印支持
- 文字水印:自定义字体、颜色、位置,适用于轻量化标识
- 图片水印:适配个人Logo,支持透明度调整,完美融入背景
2.优势功能
- 字体加载三重验证
- 垂直分布参数优化
- 进度条实时监控
- 内存性能优化
3.成功效果展示
三、代码实现过程
3.1 前期准备
# Python version :3.12
# System : macpro m1
import os
import math
from PIL import Image, ImageDraw, ImageFont, ImageOps # 图片处理
# 申明
Image => 基础图像操作
ImageDraw => 矢量绘图
ImageFont => 字体控制
ImageOps => 图像增强
3.2 实现过程
3.2.1 主函数和异常处理
try:
# 使用管理器打开图片
with Image.open(input_path).convert("RGBA") as base_img: # 转换RGBA保留透明度通道
# 创建透明水印层和绘图对象
watermark = Image.new("RGBA", base_img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)
3.2.2 字体的验证:3重验证确保无误
font_size = 60
# 排查系统字号,避免字体安装报错
font_paths = [
"/System/Library/Fonts/PingFang.ttc", # 苹果系统字体
"/System/Library/Fonts/STHeiti Medium.ttc", # 华文黑体
"/Library/Fonts/Arial.ttf" # Windows/Mac通用字体
]
font = None
for path in font_paths:
if os.path.exists(path):
try:
font = ImageFont.truetype(path, font_size, encoding="utf-8") # 指定编码避免中文乱码保险点
break
except Exception as e:
print(f"⚠️ 字体加载失败:{path} → {str(e)}")
continue
if not font:
raise FileNotFoundError("⚠️所有字体路径无效!终端执行:\nls /System/Library/Fonts/PingFang.ttc 验证路径")
3.2.3 水印动态计算 - 计算垂直分布参数
# 间距建议改为动态计算
img_width, img_height = base_img.size
vertical_spacing = 600
total_height = (3-1)*vertical_spacing # 总占位高度 = (组数-1)*间距
# 垂直居中算法
start_y = (img_height - total_height) // 2
3.2.4 循环添加旋转水印
# 添加水印 循环遍历 + 位置处理
for i in range(3):
current_y = start_y + i * vertical_spacing # 当前水印Y坐标
# 创建独立文本层,避免污染主绘图对象
text_bbox = draw.textbbox((0,0), text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_layer = Image.new("RGBA", (text_width, font_size), (0,0,0,0))
text_draw = ImageDraw.Draw(text_layer)
text_draw.text((0,0), text, font=font, fill=(255,255,255,100))
# 45度旋转,好看些,也可以不做这部分
rotated = text_layer.rotate(45, expand=True, resample=Image.BICUBIC) # 双三次插值
rotated_width = rotated.width
x = (img_width - rotated_width) // 2
# 叠加水印层
watermark.paste(rotated, (x, current_y), rotated)
3.2.5 合成与保存
# 合成最终图像
combined = Image.alpha_composite(base_img, watermark) # 阿尔法通道混合 关键步骤
output_path = os.path.join(output_folder, os.path.basename(input_path))
combined.save(output_path, "PNG", quality=95)
print(f"✅报告四叔,成功添加3组水印:{os.path.basename(input_path)}")
四、完整代码演示
# 图片水印叠加
# -*- coding: utf-8 -*-
"""
功能:图片无损水印添加
特点:字体加载三重验证 + 垂直分布参数优化 + 进度条实时监控 + 内存性能优化
作者:看海的四叔
最后更新:2025-03-26
"""
import os
import math
from PIL import Image, ImageDraw, ImageFont, ImageOps # 图片处理
def add_repeated_watermarks(input_path, output_folder, text):
"""添加5组垂直重复水印: 居中+等距分布
Args:
input_path (str): 输入图片路径
output_folder (str): 输出目录路径
text (str): 水印文字内容
"""
try:
with Image.open(input_path).convert("RGBA") as base_img:
watermark = Image.new("RGBA", base_img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)
# ===== 1.字体加载三重验证 =====
font_size = 60
font_paths = [
"/System/Library/Fonts/PingFang.ttc",
"/System/Library/Fonts/STHeiti Medium.ttc",
"/Library/Fonts/Arial.ttf"
]
font = None
for path in font_paths:
if os.path.exists(path):
try:
font = ImageFont.truetype(path, font_size, encoding="utf-8")
break
except Exception as e:
print(f"⚠️ 字体加载失败:{path} → {str(e)}")
continue
if not font:
raise FileNotFoundError("⚠️ 所有字体路径无效!终端执行:\nls /System/Library/Fonts/PingFang.ttc 验证路径")
# ===== 2. 计算垂直分布参数 =====
img_width, img_height = base_img.size
vertical_spacing = 600 # 水印垂直间距,根据图片高度动态计算更佳
total_height = (4-1)*vertical_spacing
# 计算起始Y坐标 垂直居中算法
start_y = (img_height - total_height) // 2
# ===== 3. 循环添加3组水印 =====
for i in range(3):
current_y = start_y + i * vertical_spacing # 当前水印Y坐标
# 创建旋转水印文本层(分离图层避免污染主绘图对象)
text_bbox = draw.textbbox((0,0), text, font=font) # 获取文本包围盒
text_width = text_bbox[2] - text_bbox[0]
text_layer = Image.new("RGBA", (text_width, font_size), (0,0,0,0))
text_draw = ImageDraw.Draw(text_layer)
text_draw.text((0,0), text, font=font, fill=(255,255,255,100))
# 45度旋转并计算水平居中
rotated = text_layer.rotate(45, expand=True, resample=Image.BICUBIC)
rotated_width = rotated.width
x = (img_width - rotated_width) // 2
# 叠加水印层
watermark.paste(rotated, (x, current_y), rotated)
# ===== 4. 合成最终图像 =====
combined = Image.alpha_composite(base_img, watermark)
output_path = os.path.join(output_folder, os.path.basename(input_path))
combined.save(output_path, "PNG")
print(f"✅报告四叔,成功添加3组水印:{os.path.basename(input_path)}")
except Exception as e:
print(f"❌四叔,处理失败 → 错误详情:{str(e)}")
if __name__ == "__main__":
input_folder = "/Users/admin/xxxx 你的path"
output_folder = "/Users/admin/xxxxx 你的path"
watermark_text = "看海的四叔 看海的四叔"
os.makedirs(output_folder, exist_ok=True)
# 遍历输入目录所有图片文件(支持JPG/PNG)
for filename in os.listdir(input_folder):
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
add_repeated_watermarks(
os.path.join(input_folder, filename),
output_folder,
watermark_text
)