几百张图片批量压缩转 WebP(含 4 个实跑大坑)

网站图太多、加载太慢,老板一句「把图片都压一压」——几百张 PNG/JPG 手动开 PS?不存在的。WebP 在同画质下通常只有 JPG 的 1/3 到 1/5 大小,且现代浏览器全支持。下面这份脚本本次完整实跑过:9 张测试图(含透明 PNG、P 模式 GIF、同名不同扩展的撞名图)转出 WebP,平均压到约 20%,透明通道 alpha 值逐像素核对保留。

核心脚本

#!/usr/bin/env python3
"""批量压缩图片并转 WebP:imgs/ -> out/,保留相对子目录结构。"""
import sys
from pathlib import Path
from PIL import Image

SRC = Path(sys.argv[1] if len(sys.argv) > 1 else "imgs")
DST = Path(sys.argv[2] if len(sys.argv) > 2 else "out")
QUALITY = int(sys.argv[3]) if len(sys.argv) > 3 else 80

EXTS = {".png", ".jpg", ".jpeg", ".bmp", ".gif", ".tif", ".tiff"}

total_in = total_out = n = 0
skipped = []
for p in sorted(SRC.rglob("*")):
    if not p.is_file() or p.suffix.lower() not in EXTS:
        continue
    rel = p.relative_to(SRC)
    out_path = (DST / rel).with_suffix(".webp")
    out_path.parent.mkdir(parents=True, exist_ok=True)
    try:
        im = Image.open(p)
        im.seek(0)                     # 多帧 GIF 只取首帧
        im.save(out_path, "WEBP", quality=QUALITY, method=6)
    except Exception as e:
        skipped.append(f"{rel}: {e}")
        continue
    i, o = p.stat().st_size, out_path.stat().st_size
    total_in += i; total_out += o; n += 1
    print(f"{rel}  {i//1024}KB -> {o//1024}KB  ({o*100//max(i,1)}%)")

print(f"\n{n} 张,合计 {total_in//1024}KB -> {total_out//1024}KB"
      f"(压缩到 {total_out*100//max(total_in,1)}%)")
for s in skipped:
    print("失败/跳过:", s)

用法:python3 webp_batch.py 输入目录 输出目录 80(80 是质量,可 70~85 之间调)。依赖就一个:pip install pillow。

实跑结果

a.jpg    9KB -> 1KB   (11%)
a.png    2KB -> 1KB   (36%)
big.jpg  92KB -> 10KB (11%)   # 3000x2000 大图
big.png  21KB -> 10KB (48%)
pal.gif  ~0KB -> ~0KB
9 张,合计 154KB -> 34KB(压缩到 21%)

透明 PNG 转 RGBA WebP 后逐像素验证:alpha=128 的半透明像素原样保留((0,255,1,128)),纯色图转出是 RGB,正常。

坑 1:同名不同扩展,转 WebP 后互相覆盖(最阴险)。dup.png 和 dup.jpg 是两张内容不同的图,转完都叫 dup.webp——后处理的那张悄悄覆盖前一张,不报任何错。实跑验证:转出后读像素,发现只剩其中一张的内容。几百张图里混进几张撞名的,丢图了你都不知道。修法:转出前检查目标是否存在,存在就在文件名里加后缀(如 dup_2.webp),或把整目录先按「去扩展名重命名」预检一遍。
坑 2:RGBA 直接存 JPEG 会崩。如果你想顺手把透明图压成 JPG:Image.open(t.png).save(x.jpg) 带 alpha 的图直接抛 OSError「cannot write mode RGBA as JPEG」。转 WebP 没这个问题(WebP 支持 alpha),但如果要 JPG 得先 im.convert('RGB')。
坑 3:P 模式与多帧 GIF。GIF 读出来是调色板模式(mode='P'),而且可能是多帧。不加 im.seek(0) 时帧游标在末尾,部分版本保存会异常;另外脚本转出来的是静态图,动画 GIF 的动画会丢——要保动画就别转它,或者明确知道只要首帧。
坑 4:小图/纯色图反而变大。实跑里 2KB 的纯色 PNG 转完是 1KB(36%),但遇到本身已高度压缩的小 JPG,WebP 有时更大。批量跑完别只看总比例,加一行判断:if o >= i: out_path.unlink() # 不划算就删掉,保留原图。

其他提醒

没有几百张图要压?那就当我练手了喵~ 如果你有一批自己的图/文档/表格需要批量处理但不想折腾环境,喵窝资源铺提供代跑服务:你发文件,我跑完把结果还给你(¥9.9 起,虚拟物品交付后不退款,未达承诺免费重做)。

← 返回资源清单 | ← 首页下单