我给自己写了一个本地图片批量压缩器:尺寸、格式、体积一次处理
目录
- 缘起:图片能打开,不代表适合直接使用
- 需求拆解:压缩不是把质量拉到最低
- 技术选型:Pillow 足够完成日常处理
- 核心实现一:尺寸计算与方向校正
- 核心实现二:格式转换与安全导出
- UI 定制:先看预计结果,再开始批处理
- 三个最容易让图片变样的坑
- 结尾:批量工具应该稳定执行明确规则
1. 缘起:图片能打开,不代表适合直接使用
我电脑里有很多“看起来没问题”的图片:手机照片一张十几兆,截图宽度超过 4K,商品图混着 JPG、PNG 和 WebP,博客配图则经常因为尺寸太大导致页面加载缓慢。
每次真正使用之前,我都要重复几步:
- 把过大的图片缩到合适尺寸;
- 将不需要透明背景的 PNG 转成 JPG;
- 调整压缩质量,避免文件体积过大;
- 删除相机位置等不需要的元数据;
- 按统一规则输出到新目录。
单张处理不难,几十张图片就很消耗耐心。在线压缩网站虽然方便,却要把原图上传,而且经常限制数量和单文件大小。专业图像软件功能很强,但我只是想执行一套固定规则。
于是我决定写一个本地批处理工具:选中目录、设置目标尺寸和格式、查看预估结果,然后一次导出全部图片。
2. 需求拆解:压缩不是把质量拉到最低
“压缩图片”很容易被理解成一个质量滑块,但真正使用时至少包含尺寸、编码、透明度和输出安全几个方面。
| 诉求(人话) | 拆解后(可验收) |
|---|---|
| 图片体积变小 | 支持限制最长边和设置编码质量 |
| 不要拉伸变形 | 始终保持原始宽高比 |
| 格式统一 | 支持输出 JPG、PNG 和 WebP |
| 原图不能丢 | 默认写入独立输出目录,禁止覆盖源文件 |
| 批量前心里有数 | 展示数量、原体积和预计输出体积 |
| 处理失败可追踪 | 导出成功、跳过和失败报告 |
第一版不加入裁剪、滤镜和水印。它们需要用户对每张图片作视觉判断,而压缩器的目标是对整批文件执行一致且可预测的规则。
心得:批处理适合确定性操作。需要逐张判断的能力,不应该为了“功能更多”硬塞进来。
3. 技术选型:Pillow 足够完成日常处理
程序使用 Python 编写,图片读取和编码交给 Pillow:
| 能力 | 方案 |
|---|---|
| 图片解码与编码 | Pillow |
| 尺寸缩放 | Image.Resampling.LANCZOS |
| EXIF 方向处理 | ImageOps.exif_transpose() |
| 文件扫描 | pathlib |
| 并发执行 | ThreadPoolExecutor |
| 桌面界面 | tkinter |
Pillow 已经覆盖常见图片格式,也能控制 JPG 和 WebP 的质量、PNG 优化以及 ICC 色彩配置。对一个日常压缩工具来说,没有必要接入完整图像编辑框架。
批处理默认只使用少量工作线程。图片编码会消耗 CPU 和内存,如果同时处理十几张高分辨率照片,速度未必更快,反而可能让电脑瞬间占满内存。
心得:批处理的并发数量应该由单个任务的资源消耗决定,而不是由文件数量决定。
4. 核心实现一:尺寸计算与方向校正
手机照片常通过 EXIF 方向字段表示旋转状态。像素本身可能是横向的,只是查看软件根据元数据将它显示为竖图。因此缩放前要先应用方向校正。
from PIL import Image, ImageOps
def load_image(path):
with Image.open(path) as source:
image = ImageOps.exif_transpose(source)
return image.copy()
尺寸限制采用“最长边不超过指定值”的规则。小图默认不放大,避免为了统一尺寸制造模糊像素。
def fit_size(width, height, max_edge, allow_upscale=False):
scale = max_edge / max(width, height)
if not allow_upscale:
scale = min(scale, 1.0)
return (
max(1, round(width * scale)),
max(1, round(height * scale)),
)
真正缩放时使用高质量重采样:
def resize_image(image, max_edge):
target = fit_size(*image.size, max_edge)
if target == image.size:
return image
return image.resize(target, Image.Resampling.LANCZOS)
预览区域会同时显示原始尺寸和目标尺寸。如果图片本来就小于限制,它会被标记为“仅重新编码”,而不是让用户误以为所有文件都发生了缩放。
5. 核心实现二:格式转换与安全导出
格式转换最容易出问题的是透明通道。JPG 不支持透明背景,直接把 RGBA 图片保存为 JPG 会失败,或者得到不可控的背景色。因此转换时必须让用户选择填充颜色。
from PIL import Image
def flatten_alpha(image, background=(255, 255, 255)):
if image.mode not in ("RGBA", "LA"):
return image.convert("RGB")
rgba = image.convert("RGBA")
canvas = Image.new("RGBA", rgba.size, (*background, 255))
canvas.alpha_composite(rgba)
return canvas.convert("RGB")
导出参数按照目标格式分别处理:
def save_image(image, path, format_name, quality):
options = {}
if format_name == "JPEG":
options.update(quality=quality, optimize=True, progressive=True)
elif format_name == "WEBP":
options.update(quality=quality, method=4)
elif format_name == "PNG":
options.update(optimize=True, compress_level=6)
image.save(path, format=format_name, **options)
为了避免程序中途崩溃留下半张图片,每个文件先写入输出目录中的临时文件。保存成功并能重新打开验证后,再原子替换为最终文件名。
输出目录默认是源目录旁边的 compressed,并且不允许选择源目录本身。遇到同名文件时,程序默认跳过并写入报告,除非用户明确选择覆盖。
心得:图片压缩可以有损,文件处理流程不能冒险。源文件和未完成输出都必须受到保护。
6. UI 定制:先看预计结果,再开始批处理
界面分成三个区域:左侧是输入目录和文件列表,中间是参数,右侧是抽样预览与统计。
常用设置只有几项:
- 目标格式;
- 最长边像素;
- JPG 或 WebP 质量;
- 透明背景填充色;
- 是否保留 ICC 色彩配置;
- 是否清除 EXIF 元数据。
用户调整参数后,程序只抽取几张不同尺寸的图片生成预览,并估算输出体积。估算值会明确标记为“抽样结果”,不会伪装成精确数字。真正的压缩率取决于每张图片的内容复杂度。
开始按钮旁边持续显示“将处理多少张、跳过多少张、输出到哪里”。批处理过程中可以停止后续任务,但不会强行中断正在编码的文件,避免产生损坏结果。
完成后,界面展示原始总体积、输出总体积、节省比例和失败数量。点击失败项可以看到具体原因,而不是只弹出一句“部分文件处理失败”。
7. 三个最容易让图片变样的坑
坑一:忽略 EXIF 方向导致图片横过来。 很多手机照片依赖方向字段显示。若先删除元数据再按原像素保存,竖图可能变成横图。正确顺序是先应用方向,再决定是否清除 EXIF。
坑二:透明图片转 JPG 出现黑底。 透明区域没有固定颜色,直接丢弃 Alpha 通道时可能变成黑色。转换前必须合成到用户明确选择的背景色上,并在预览中展示结果。
坑三:颜色配置丢失导致观感变化。 部分照片带有 Display P3 等 ICC 配置。删除配置后,不同软件可能按 sRGB 解释像素,颜色会发生偏差。工具默认保留 ICC 配置;若目标平台只接受 sRGB,则需要先完成正确的色彩空间转换,而不是简单删除配置文件。
此外,GIF 和 WebP 可能包含动画。第一版检测到多帧图片时直接跳过并提示,不把第一帧悄悄保存成静态图。静态压缩和动画转码是两个不同任务。
8. 结尾:批量工具应该稳定执行明确规则
完成这个工具后,我处理博客配图和商品图的流程变得很固定:把原图放进目录,选择最长边和目标格式,查看抽样预览,然后导出到新目录。
它没有自动美化,也不会判断哪张照片更好看。它只负责把一套明确规则稳定应用到每个文件:
- 校正方向;
- 按比例缩放;
- 正确处理透明度和颜色;
- 使用目标格式编码;
- 安全写入并生成报告。
真正省时间的不是某一次压缩更快,而是以后不必再逐张重复相同操作,也不用担心今天和明天导出的参数不一致。
如果你也想写一个图片压缩工具,可以先支持 JPG 输入、限制最长边和输出到新目录。等这个流程稳定后,再加入 PNG、WebP、透明通道与元数据选项。图片格式的边界很多,功能越多越需要真实样本验证。
好的批处理工具并不替人做审美决定,它只是让机械操作变得一致、透明并且可复查。
- 点赞
- 收藏
- 关注作者
评论(0)