写了一个开箱即用的批量图片转 WebP 脚本

WebP 是 Google 推出的一种现代图片格式,在同等画质下体积比 JPEG 小 25%-35%,比 PNG 小得更多。对于博客网站和前端项目来说,全量切到 WebP 能显著减少页面加载速度。

周末花了点时间写了一个 Python 脚本 convert2webp,解决一个一直懒得动手的需求:批量把图片文件夹里的各种格式拖进去,一键转成 WebP,顺便看看能省多少空间。


为什么要用 WebP

在介绍脚本之前,先简单说说为什么值得花时间做这件事:

对比项 PNG JPEG WebP
无损压缩 支持 不支持 支持,比 PNG 小 26%
有损压缩 基准 比 JPEG 小 25-35%
透明度 支持 不支持 支持
动图 支持(替代 GIF)

根据 Google 的官方数据,WebP 无损图片比 PNG 体积小 26%,有损图片比同等 SSIM 质量的 JPEG 小 25-35%。对于流量来自移动端的场景,省下来的每一 KB 都在加快首屏速度。

浏览器兼容性方面,主流现代浏览器(Chrome、Firefox、Edge、Safari 14+)都已原生支持 WebP。如果你需要兼容老旧浏览器,可以用 <picture> 标签做降级兜底(不过个人博客就不太需要操这个心了):

1
2
3
4
<picture>
<source srcset="image.webp" type="image/webp">
<img src="image.png" alt="fallback">
</picture>

convert2webp 脚本

这个脚本的设计目标很朴素:丢到图片文件夹里双击,完事。

使用方式

脚本只有一个文件,依赖 Python 3,首次运行会自动安装 Pillow,不需要手动装任何东西。

最简单的用法——直接命令行跑:

1
python3 convert2webp.py

不过最舒服的用法还是把脚本丢到图片文件夹里双击:

macOS —— 用附带的 Convert2WebP.command(chmod +x 后双击):

1
2
3
#!/bin/bash
cd "$(dirname "$0")"
python3 convert2webp.py

Windows —— 用附带的 Convert2WebP.bat(双击):

1
2
3
4
@echo off
cd /d "%~dp0"
python convert2webp.py
pause

运行之后,脚本会扫描当前目录下所有常见格式的图片,在下方新建一个 webp/ 文件夹存放转换结果,并在终端打印每张图的压缩率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
==================================================
🖼️ 批量图片转 WebP 工具
==================================================
📁 工作目录: /Users/yuhaozhe/Pictures/blog-assets
⚙️ 质量: 85 | 模式: 有损

🔍 找到 12 张图片

[1/12] ✅ hero.png 120KB → 32KB (-73.3%)
[2/12] ✅ screenshot.jpg 340KB → 68KB (-80.0%)
...

==================================================
✅ 成功: 12/12
💾 总大小: 2.3MB → 0.5MB (-78.3%)
📂 输出目录: /Users/yuhaozhe/Pictures/blog-assets/webp
==================================================

功能特性

  • 自动安装依赖 —— 第一次运行自动 pip install Pillow,到手即用
  • 支持超多格式 —— PNG、JPG、JPEG、BMP、TIFF、GIF、ICO 全都能吃
  • 保留原文件 —— 输出全部丢到 webp/ 子目录,不动原始图片
  • 文件名防冲突 —— 如果 photo.webp 已存在,自动命名为 photo_1.webpphoto_2.webp
  • 动图处理 —— 遇到 GIF 只取第一帧,避免动图转成静态 WebP 后体积异常
  • 透明通道保留 —— RGBA 图片正常处理,不会丢掉透明度
  • 详细日志 —— 每张图显示压缩前后大小和压缩百分比,最后还有汇总

核心代码

脚本不长,两百行不到,核心转换逻辑就这些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from PIL import Image

SUPPORTED_EXT = {'.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.tif', '.gif', '.ico', '.webp'}
OUTPUT_DIR = 'webp'
QUALITY = 85
LOSSLESS = False

def convert_to_webp(src_path, dst_path):
img = Image.open(src_path)
# 处理 GIF 动图只取第一帧
if getattr(img, "is_animated", False):
img = img.copy()
# 统一颜色模式
if img.mode in ('RGBA', 'LA', 'PA'):
img = img.convert('RGBA')
elif img.mode == 'P':
img = img.convert('RGBA')
elif img.mode not in ('RGB', 'L'):
img = img.convert('RGB')
# 保存为 WebP
img.save(dst_path, 'webp', quality=QUALITY, lossless=LOSSLESS)

剩下就是扫描文件、建目录、算大小这些体力活,完整代码贴在文末。

自定义配置

脚本顶部有三个配置项,打开 .py 文件就能改:

1
2
QUALITY = 85       # WebP 质量 (1-100),越大越清晰
LOSSLESS = False # True = 无损(文件大),False = 有损(文件小)

不同场景的建议值:

场景 推荐质量
产品图、照片 80-85
图标、UI 元素 90-95 或无损
缩略图、背景图 60-70
存档需求 无损模式

备选方案:cwebp

如果你对压缩参数有极致控制欲(比如想调 -m 6 -pass 10),Google 官方的 cwebp 编码器是最强的。

安装

1
2
3
brew install webp        # macOS
sudo apt install webp # Ubuntu/Debian
scoop install webp # Windows

单文件转换:

1
cwebp -q 80 input.png -o output.webp

批量处理整个目录:

1
2
find . -type f \( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" \) \
-exec sh -c 'cwebp -q 80 "$1" -o "${1%.*}.webp"' _ {} \;

日常用的话 Pillow 脚本已经够用,cwebp 更适合对压缩质量有极致追求或者要集成到自动化流水线的场景。


避坑指南

1. 处理后的文件比原文件大?

WebP 对照片类图片压缩效果最好,但对某些简单图形、截图、扁平色块的 PNG,WebP 无损模式的文件体积可能反而比原文件大。遇到这种情况,可以尝试有损模式或者保持原格式。

2. 不要删除原始文件

建议转换完成后统一清理,而不是转换时直接覆盖。万一对质量不满意,还能用原图重新压。

3. 文件命名冲突

如果源文件有 photo.jpgphoto.png,转换后都会变成 photo.webp,两个文件会互相覆盖。脚本已经做了防冲突处理(自动加序号后缀),但如果在意输出文件名,建议转换前先检查:

1
2
find . -type f \( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" \) \
-exec basename {} \; | sed 's/\.[^.]*$//' | sort | uniq -d

总结

这次写的 convert2webp 主打一个开箱即用,不需要理解命令行参数,不需要手动装依赖,双击就能跑。代码放在 convert2webp 这个 repo 里,包含了 Python 脚本和两个平台的启动器。

如果你有其他常用的 WebP 转换工具,下面做个简单对比:

方案 适合人群 特点
convert2webp.py 懒人 丢文件夹双击,自动装依赖
cwebp 命令行发烧友 Google 官方,压缩参数最细
ImageMagick 已有该工具链 可同时做缩放/裁剪
Sharp 脚本 前端项目 可集成 CI/CD

不管用哪种方案,WebP 迁移都是一次性的工作,带来的加载速度提升却是长久的。如果你还在用原始图片格式往外丢,花半小时做一次全量迁移吧,值得。