为什么要批量裁剪图片?

做电商要统一主图尺寸、社交媒体头像要裁成正方形、证件照需要固定比例……手动一张张裁,几十张就够你喝两杯咖啡了。

用Python + Pillow,几行代码就能批量搞定。这篇博客覆盖最常用的3个场景,每个都给可运行代码。


场景一:固定尺寸裁剪(左上角裁剪)

最简单粗暴的方式:把所有图片裁成统一的宽×高。

from PIL import Image
import os

def crop_fixed_size(input_dir, output_dir, width, height):
    os.makedirs(output_dir, exist_ok=True)
    
    for filename in os.listdir(input_dir):
        if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.webp')):
            continue
        
        img_path = os.path.join(input_dir, filename)
        img = Image.open(img_path)
        
        # 左上角裁剪
        cropped = img.crop((0, 0, width, height))
        cropped.save(os.path.join(output_dir, filename))
        print(f"{filename}{width}x{height}")

# 使用:裁成 800x600
crop_fixed_size(r'D:\原图', r'D:\裁剪后', 800, 600)

⚠️ 如果原图比目标尺寸小,会报错。下面的"居中裁剪"可以解决这个问题。


场景二:居中裁剪成正方形(最常用)

社交媒体头像、商品主图,基本都要正方形。这个方法会自动居中裁剪,不会拉伸变形。

from PIL import Image
import os

def crop_center_square(input_dir, output_dir, size):
    os.makedirs(output_dir, exist_ok=True)
    
    for filename in os.listdir(input_dir):
        if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.webp')):
            continue
        
        img_path = os.path.join(input_dir, filename)
        img = Image.open(img_path)
        
        # 取最小边作为裁剪尺寸,保证不会切掉内容
        min_side = min(img.width, img.height)
        left = (img.width - min_side) // 2
        top = (img.height - min_side) // 2
        right = left + min_side
        bottom = top + min_side
        
        cropped = img.crop((left, top, right, bottom))
        
        # 再缩放到目标尺寸(可选)
        cropped = cropped.resize((size, size), Image.LANCZOS)
        
        cropped.save(os.path.join(output_dir, filename))
        print(f"{filename}{size}x{size}")

# 使用:裁成 500x500 正方形
crop_center_square(r'D:\照片', r'D:\头像', 500)

效果对比

原图 居中裁剪 左上角裁剪
1200×800 横图 ✅ 保留中间主体 ❌ 只保留左上角
800×1200 竖图 ✅ 保留中间主体 ❌ 只保留左上角

场景三:按坐标批量裁剪(精确控制)

有些场景需要精确裁剪某个区域,比如证件照只取头部、截图只取特定区域。

from PIL import Image
import os

def crop_by_coordinates(input_dir, output_dir, coords):
    """
    coords: (left, top, right, bottom)
    例如:(100, 50, 400, 400) 表示从(100,50)到(400,400)的矩形区域
    """
    os.makedirs(output_dir, exist_ok=True)
    
    left, top, right, bottom = coords
    crop_width = right - left
    crop_height = bottom - top
    
    for filename in os.listdir(input_dir):
        if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.webp')):
            continue
        
        img_path = os.path.join(input_dir, filename)
        img = Image.open(img_path)
        
        # 判断原图是否够大
        if img.width < right or img.height < bottom:
            print(f"⚠️ {filename} 尺寸不足,跳过")
            continue
        
        cropped = img.crop((left, top, right, bottom))
        cropped.save(os.path.join(output_dir, filename))
        print(f"{filename} → 裁剪区域 {coords}")

# 使用:裁剪左上角 (100, 50) 到 (600, 550) 的区域
crop_by_coordinates(r'D:\截图', r'D:\裁剪后', (100, 50, 600, 550))

进阶:批量裁剪 + 加水印(一气呵成)

裁剪完直接加上水印,电商场景特别实用。

from PIL import Image, ImageDraw, ImageFont
import os

def crop_and_watermark(input_dir, output_dir, size, watermark_text):
    os.makedirs(output_dir, exist_ok=True)
    
    for filename in os.listdir(input_dir):
        if not filename.lower().endswith(('.jpg', '.jpeg', '.png')):
            continue
        
        img_path = os.path.join(input_dir, filename)
        img = Image.open(img_path)
        
        # 居中裁剪
        min_side = min(img.width, img.height)
        left = (img.width - min_side) // 2
        top = (img.height - min_side) // 2
        cropped = img.crop((left, top, left + min_side, top + min_side))
        cropped = cropped.resize((size, size), Image.LANCZOS)
        
        # 加水印
        draw = ImageDraw.Draw(cropped)
        font = ImageFont.truetype("simhei.ttf", int(size * 0.08))  # Windows自带黑体
        
        text_bbox = draw.textbbox((0, 0), watermark_text, font=font)
        text_width = text_bbox[2] - text_bbox[0]
        x = (size - text_width) // 2
        y = size - int(size * 0.1)
        
        draw.text((x, y), watermark_text, fill=(255, 255, 255, 128), font=font)
        
        cropped.save(os.path.join(output_dir, filename), quality=95)
        print(f"{filename} → 裁剪+水印完成")

# 使用
crop_and_watermark(r'D:\商品图', r'D:\成品', 800, '店铺名称')

💡 如果是Mac/Linux,字体路径改成 /System/Library/Fonts/Supplemental/Arial Unicode.ttf 或安装中文字体。


常见问题速查

问题 解决方案
图片有透明通道,保存后变黑底 cropped.convert('RGB') 转成RGB再保存
裁剪后图片模糊 resize()Image.LANCZOS 而不是默认的 Image.BILINEAR
批量处理速度慢 考虑用 concurrent.futures.ThreadPoolExecutor 多线程处理
需要保留EXIF信息 piexif 库,或 pillow-heif 处理HEIC格式

总结

批量裁剪图片的核心就三步:

  1. 打开图片Image.open()
  2. 裁剪区域img.crop((左, 上, 右, 下))
  3. 保存结果img.save()

上面的代码覆盖了固定尺寸、居中正方形、精确坐标三种最常见需求,复制过去改一下路径就能跑。

如果你需要更复杂的操作(比如按人脸自动裁剪、批量加圆角),评论区说,我接着写。

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐