Python Pillow批量处理图片:自动调整尺寸、添加水印和压缩的实战脚本
日常开发或办公中,经常需要批量处理图片:统一尺寸、添加水印、格式转换或压缩大小。Python的Pillow库(PIL的升级版)可以高效完成这些重复操作,无需逐张手动处理。本文从基础操作到完整工作流,提供可直接复用的脚本代码,并针对常见报错给出解决方案。一、安装与导入
Pillow可通过pip安装:
pip install Pillow
在脚本中导入核心模块:
from PIL import Image, ImageDraw, ImageFont, ImageFilter
二、基础操作
打开图片后,可通过属性获取格式、尺寸和颜色模式:
img = Image.open("照片.jpg")
print(f"格式: {img.format}")
print(f"尺寸: {img.size}")
print(f"模式: {img.mode}")
调整尺寸有多种方式:
# 等比例缩放(指定宽度,高度自动计算)
def resize_by_width(img, target_width=800):
w, h = img.size
ratio = target_width / w
new_h = int(h * ratio)
return img.resize((target_width, new_h), Image.LANCZOS)
# 裁剪为正方形(从中心切)
def crop_square(img):
w, h = img.size
min_side = min(w, h)
left = (w - min_side) // 2
top = (h - min_side) // 2
right = left + min_side
bottom = top + min_side
return img.crop((left, top, right, bottom))
# 强制缩放到指定尺寸(可能变形)
img_resized = img.resize((1920, 1080), Image.LANCZOS)
# 直接调用thumbnail方法,原图被修改,最长边不超过给定值
img.thumbnail((800, 600))
旋转与翻转:
# rotation (expand=True可防止裁剪)
rotated = img.rotate(90, expand=True)
# horizontal flip
flipped_h = img.transpose(Image.FLIP_LEFT_RIGHT)
# vertical flip
flipped_v = img.transpose(Image.FLIP_TOP_BOTTOM)
三、实战案例:批量处理婚纱照
以下PhotoProcessor类封装了三个常用功能:压缩到微信分享尺寸、添加文字水印、创建拼图。可直接用于影楼或个人的批量处理。
from PIL import Image, ImageDraw, ImageFont
import os
class PhotoProcessor:
def __init__(self, input_dir, output_dir):
self.input_dir = input_dir
self.output_dir = output_dir
os.makedirs(output_dir, exist_ok=True)
def resize_for_wechat(self, max_width=1080):
"""批量压缩至适合微信分享的尺寸(最长边不超过max_width)"""
for f in os.listdir(self.input_dir):
if not f.lower().endswith((".jpg", ".jpeg", ".png")):
continue
img = Image.open(os.path.join(self.input_dir, f))
w, h = img.size
if max(w, h) > max_width:
ratio = max_width / max(w, h)
new_size = (int(w * ratio), int(h * ratio))
img = img.resize(new_size, Image.LANCZOS)
output_path = os.path.join(self.output_dir, f"wechat_{f}")
img.save(output_path, quality=85, optimize=True)
print(f"已处理: {f}")
def add_watermark(self, text="张政 & 爱妻", position="右下角"):
"""批量添加半透明水印,支持位置参数"""
for f in os.listdir(self.input_dir):
if not f.lower().endswith((".jpg", ".jpeg", ".png")):
continue
img = Image.open(os.path.join(self.input_dir, f)).convert("RGBA")
watermark = Image.new("RGBA", img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)
font_size = max(img.size) // 30
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_w, text_h = bbox - bbox, bbox - bbox
margin = 20
if position == "右下角":
x, y = img.width - text_w - margin, img.height - text_h - margin
elif position == "左下角":
x, y = margin, img.height - text_h - margin
elif position == "居中":
x, y = (img.width - text_w) // 2, (img.height - text_h) // 2
draw.text((x, y), text, font=font, fill=(255, 255, 255, 100))
result = Image.alpha_composite(img, watermark).convert("RGB")
output_path = os.path.join(self.output_dir, f"wm_{f}")
result.save(output_path, quality=95)
print(f"已添加水印: {f}")
def create_collage(self, photos_per_row=3):
"""创建照片拼图,适合朋友圈九宫格预览"""
photos = [f for f in os.listdir(self.input_dir)
if f.lower().endswith((".jpg", ".jpeg", ".png"))]
if not photos:
return
thumb_size = 300
rows = (len(photos) + photos_per_row - 1) // photos_per_row
canvas = Image.new("RGB", (photos_per_row * thumb_size, rows * thumb_size), (255, 255, 255))
for i, f in enumerate(photos):
img = Image.open(os.path.join(self.input_dir, f))
img.thumbnail((thumb_size - 10, thumb_size - 10))
x = (i % photos_per_row) * thumb_size + 5
y = (i // photos_per_row) * thumb_size + 5
canvas.paste(img, (x, y))
output_path = os.path.join(self.output_dir, "collage.jpg")
canvas.save(output_path, quality=95)
print(f"拼图已生成")
# 使用示例
processor = PhotoProcessor("原始照片", "输出照片")
processor.resize_for_wechat(max_width=1080)
# processor.add_watermark("张政 & 爱妻")
# processor.create_collage(photos_per_row=3)
四、其他常用场景
批量格式转换:
def batch_convert(input_dir, output_dir, target_format="png"):
os.makedirs(output_dir, exist_ok=True)
for f in os.listdir(input_dir):
name, ext = os.path.splitext(f)
if ext.lower() not in (".jpg", ".jpeg", ".png", ".bmp", ".webp"):
continue
img = Image.open(os.path.join(input_dir, f))
img.save(os.path.join(output_dir, f"{name}.{target_format}"))
print(f"已转换: {f}")
批量压缩(可控制quality参数,减少文件大小):
def compress_images(input_dir, output_dir, quality=60):
os.makedirs(output_dir, exist_ok=True)
for f in os.listdir(input_dir):
if not f.lower().endswith((".jpg", ".jpeg", ".png")):
continue
img = Image.open(os.path.join(input_dir, f))
output_path = os.path.join(output_dir, f"compressed_{f}")
img.save(output_path, quality=quality, optimize=True)
orig_size = os.path.getsize(os.path.join(input_dir, f))
new_size = os.path.getsize(output_path)
ratio = (1 - new_size / orig_size) * 100
print(f"{f}: 压缩 {ratio:.0f}%")
添加滤镜效果和亮度/对比度调整:
from PIL import ImageEnhance
img = Image.open("照片.jpg")
# 滤镜
blur = img.filter(ImageFilter.BLUR)
contour = img.filter(ImageFilter.CONTOUR)
emboss = img.filter(ImageFilter.EMBOSS)
sharpen = img.filter(ImageFilter.SHARPEN)
smooth = img.filter(ImageFilter.SMOOTH)
# 转灰度
gray = img.convert("L")
# 增强亮度
enhancer = ImageEnhance.Brightness(img)
brighter = enhancer.enhance(1.3)# 增加30%
# 增强对比度
enhancer = ImageEnhance.Contrast(img)
higher_contrast = enhancer.enhance(1.2)
批量重命名(可自定义前缀和起始编号):
def batch_rename(directory, prefix="IMG_", start=1):
files = [f for f in os.listdir(directory)
if f.lower().endswith((".jpg", ".jpeg", ".png", ".webp"))]
files.sort()
for i, f in enumerate(files):
ext = os.path.splitext(f)
new_name = f"{prefix}{start + i:03d}{ext}"
os.rename(os.path.join(directory, f), os.path.join(directory, new_name))
print(f"{f} → {new_name}")
五、实际工作流
现实中可将上述函数串联:①从设备导出照片 → ②批量重命名 → ③调整尺寸/压缩 → ④添加水印 → ⑤挑选部分做滤镜/拼图 → ⑥发朋友圈或上传。每个步骤独立成函数,参数可调,不满意只需修改参数重新运行,无需手动逐张操作。
六、常见问题与解决
1. OSError: cannot identify image file
原因:文件扩展名与实际格式不一致或文件损坏。处理时用try包裹并验证:
try:
img = Image.open(file)
img.verify()
except:
print(f"跳过损坏文件: {file}")
2. 中文文字显示为方框
原因:Pillow默认字体不支持中文。需要指定中文字体路径(Windows常见字体):
font = ImageFont.truetype("C:/Windows/Fonts/simhei.ttf", 36)# 黑体
# 也可用 msyh.ttc (微软雅黑), simsun.ttc (宋体)
3. 图片太大导致内存不足
处理超大图片前先缩小尺寸:
img = Image.open("超大图片.jpg")
img.thumbnail((4000, 4000))# 限制最长边4000像素
总结:Pillow几乎覆盖日常所有图片处理需求。将以上代码保存为脚本,下次只需修改文件路径和参数即可批量执行,省去90%的手动操作时间。最常用的三个场景:批量改尺寸(发朋友圈/上传网站)、批量加水印(保护版权)、批量压缩(节省存储空间)。
Re: Python Pillow批量处理图片:自动调整尺寸、添加水印和压缩的实战脚本
楼主的分享非常实用,正好最近在整理婚纱照,这个 `PhotoProcessor` 类直接拿来改改就能用。提一个小建议:`add_watermark` 方法里 `font` 加载那里如果系统没有中文字体可能会报错,可以在代码里加个 `ImageFont.load_default()` 作为 fallback,或者指定一个常见中文字体路径(比如 Windows 下的 `msyh.ttc`),这样更省心。另外裁剪正方形的逻辑很赞,下次需要头像裁剪直接调用了。感谢楼主的辛勤整理!Re: Python Pillow批量处理图片:自动调整尺寸、添加水印和压缩的实战脚本
感谢分享!这个批量处理脚本很实用,代码结构清晰,特别是`PhotoProcessor`类封装得方便复用。想请教一下,在`add_watermark`方法里,如果指定的字体文件不存在(比如系统没装对应中文字体),有什么推荐的兜底处理吗?另外注意到最后的`compress`函数好像没贴完,是打算后续再补充还是漏掉了?期待完整版,先收藏学习!Re: Python Pillow批量处理图片:自动调整尺寸、添加水印和压缩的实战脚本
非常实用的脚本,感谢分享!特别是`PhotoProcessor`类的设计简洁易用,直接就能套用到自己的工作流里。有个小建议:`add_watermark`里字体路径是硬编码的,实际部署时最好加个`font_path`参数或者自动检测系统字体,不然Windows和Mac上容易报FileNotFoundError。另外压缩时如果能保留原图目录结构就更完美了,方便子文件夹批量处理。
页:
[1]