Python图片压缩方法全解:从入门到进阶
图片占网页流量60%以上,一张10MB的照片能拖慢整个页面加载速度。Python生态里压缩图片的方法不少,但适合你的可能就两三种。
这篇把主流方案捋一遍,告诉你什么场景用什么工具。
一、先分清两条路
| 类型 | 原理 | 压缩率 | 信息损失 | 典型场景 |
|---|---|---|---|---|
| 无损压缩 | 消除数据冗余,解码后与原图完全一致 | 10%-30% | 无 | 医学影像、PNG透明图、技术图纸 |
| 有损压缩 | 丢弃人眼不敏感的高频细节 | 50%-90% | 有 | 网页配图、社媒分享、缩略图 |
绝大多数场景,选有损就够了。quality=85 时人眼几乎无法分辨,体积已砍掉60%。
二、六种主流方法
1. Pillow —— 最通用,首选
Python图像处理的标准库,装完就能用。
pipinstallPillow三种压缩手段:
fromPILimportImage img=Image.open("photo.jpg")# ① 降质量(最常用)img.save("small.jpg",quality=85,optimize=True)# ② 缩尺寸img_resized=img.resize((1920,1080),Image.LANCZOS)img_resized.save("resized.jpg",quality=85)# ③ 换格式(PNG → JPEG,体积常减50%+)ifimg.mode=='RGBA':img=img.convert('RGB')img.save("converted.jpg","JPEG",quality=85)| 参数 | 推荐值 | 说明 |
|---|---|---|
| quality | 85 | 质量与体积的最佳平衡点 |
| optimize | True | 额外尝试无损压缩JPEG |
| resample | LANCZOS | 高质量缩放算法 |
适合: 日常开发、批量处理、离线场景。
2. TinyPNG API —— 压缩率最高
不是Python库,但有官方Python SDK,一行调用:
pipinstalltinifyimporttinify tinify.key="YOUR_API_KEY"source=tinify.from_file("input.png")source.to_file("output.png")# 自动选最优参数| 指标 | Pillow (quality=85) | TinyPNG |
|---|---|---|
| PNG压缩率 | 20%-30% | 50%-80% |
| JPG压缩率 | 40%-60% | 50%-70% |
| 免费额度 | 无限制 | 月500张 |
适合: 对压缩率要求极高、图片量不大的场景。
3. WebP格式转换 —— 谷歌出品,体积最小
WebP是目前综合压缩率最优的图片格式,同画质下比JPEG小25%-35%。
fromPILimportImage img=Image.open("photo.jpg")img.save("photo.webp","WEBP",quality=80)| 对比项 | JPEG | WebP |
|---|---|---|
| 同质量体积 | 100KB | 65-75KB |
| 浏览器支持 | 99% | 96%(IE不支持) |
| 透明通道 | ❌ | ✅ |
适合: 现代化网站、不需要兼容IE的项目。
4. PyVips —— 性能怪兽,内存极低
Pillow的问题:大图(>50MB)会吃光内存。PyVips用流式处理,100MB图片只占几十MB内存。
pipinstallpyvipsimportpyvips img=pyvips.Image.thumbnail("huge.jpg",1920)img.write_to_file("small.jpg",Q=85)| 指标 | Pillow | PyVips |
|---|---|---|
| 100张10MB图 | 耗时40秒,峰值内存2GB | 耗时8秒,峰值内存200MB |
| 大图支持 | 勉强 | 轻松 |
适合: 批量处理大图、服务器端图片处理。
5. OpenCV —— 视频帧/实时流首选
如果你在处理视频帧或摄像头流,OpenCV比Pillow快得多。
importcv2 img=cv2.imread("photo.jpg")cv2.imwrite("small.jpg",img,[cv2.IMWRITE_JPEG_QUALITY,85])适合: 视频处理、实时流、需要同时做图像分析的场景。
6. K-means聚类 —— 算法级压缩,可控色彩数
不改格式,直接减少图片色彩数量。原理:把相近颜色归为一类。
importnumpyasnpfromsklearn.clusterimportKMeansfromPILimportImage img=Image.open("photo.jpg")pixels=np.array(img).reshape(-1,3)kmeans=KMeans(n_clusters=64)# 只保留64种颜色kmeans.fit(pixels)new_pixels=kmeans.cluster_centers_[kmeans.labels_]new_img=Image.fromarray(new_pixels.reshape(img.size[1],img.size[0],3).astype('uint8'))new_img.save("kmeans.jpg")| 色彩数 | 效果 | 压缩率 |
|---|---|---|
| 256 | 轻微色块感 | ~40% |
| 64 | 明显海报化 | ~60% |
| 16 | 强烈艺术感 | ~75% |
适合: 图标处理、艺术化效果、学习算法原理。
三、方法对比总表
| 方法 | 压缩率 | 速度 | 内存 | 难度 | 最佳场景 |
|---|---|---|---|---|---|
| Pillow | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐ | 通用首选 |
| TinyPNG | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐ | 追求极致压缩 |
| WebP | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐ | 现代Web项目 |
| PyVips | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | 大图批量处理 |
| OpenCV | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | 视频/实时流 |
| K-means | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | 艺术化/学习 |
四、怎么选?看这个决策树
需要压缩图片? │ ├─ 几张图,临时用 → 在线工具(tinypng.com),别写代码 │ ├─ 批量 + 离线 → Pillow(本文方法1),够用 │ ├─ 压缩率优先 → TinyPNG API │ ├─ 网站配图 → WebP格式 │ ├─ 图片>50MB / 批量>1000张 → PyVips │ ├─ 视频帧处理 → OpenCV │ └─ 玩算法 / 艺术化 → K-means五、一个能直接用的批量脚本
把上面最常用的方案合在一起:
importosfromPILimportImagedefcompress_batch(input_dir,output_dir,quality=85,max_width=1920):os.makedirs(output_dir,exist_ok=True)forfinos.listdir(input_dir):ifnotf.lower().endswith(('.jpg','.jpeg','.png','.bmp')):continuein_path=os.path.join(input_dir,f)out_path=os.path.join(output_dir,f)withImage.open(in_path)asimg:ifimg.modein('RGBA','P'):img=img.convert('RGB')ifimg.width>max_width:ratio=max_width/img.width img=img.resize((max_width,int(img.height*ratio)),Image.LANCZOS)img.save(out_path,'JPEG',quality=quality,optimize=True)orig=os.path.getsize(in_path)/1024new=os.path.getsize(out_path)/1024print(f"{f}:{orig:.0f}KB →{new:.0f}KB ({1-new/orig:.0%})")compress_batch("./原图","./压缩",quality=85)最后说一句
别追求"最好的压缩方法",够用的才是最好的。大多数情况下,Pillow + quality=85 + optimize=True,已经能解决90%的问题。
先把这一招用熟,再根据实际瓶颈考虑换工具。
