场景引入
- 网站需要 webp 格式的图片以提升加载速度
- 客户要求 jpg 格式方便查看
- 系统只接受 png 格式的图标
- 图片太大,需要压缩后发送
手动用画图工具一张一张转换?太慢了。本节用 python 实现批量格式转换和压缩。
技术原理
pillow 支持几乎所有常见图片格式:
读取图片(任意格式) → pil image 对象 → 保存为指定格式
| 格式 | 特点 | 适用场景 |
|---|---|---|
| jpg/jpeg | 有损压缩,不支持透明 | 照片、产品图 |
| png | 无损压缩,支持透明 | 图标、截图 |
| webp | google 格式,体积小 | 网页图片 |
| bmp | 无压缩 | 老系统兼容 |
| tiff | 无损,支持多层 | 印刷、存档 |
环境准备
pip install pillow
完整代码
import os
from pathlib import path
from pil import image
# 支持的图片格式
supported_extensions = {'.jpg', '.jpeg', '.png', '.webp', '.bmp', '.tiff', '.gif'}
# ==================== 方案 1:单个格式转换 ====================
def convert_image(input_file, output_format='jpg', quality=85, max_size=none):
"""
转换图片格式
参数:
input_file: 输入图片路径
output_format: 输出格式 'jpg'/'png'/'webp'/'bmp'
quality: 压缩质量(1-100,仅对 jpg/webp 有效)
max_size: 最大尺寸 (width, height) 或 none
"""
input_path = path(input_file)
img = image.open(input_path)
# 如果需要调整大小
if max_size:
img.thumbnail(max_size, image.lanczos)
# 处理 rgba → rgb(jpg 不支持透明通道)
if output_format in ('jpg', 'jpeg', 'bmp') and img.mode == 'rgba':
# 白色背景替代透明
background = image.new('rgb', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3])
img = background
# 生成输出文件名
output_file = input_path.with_suffix(f'.{output_format}')
# 保存参数
save_kwargs = {}
if output_format in ('jpg', 'jpeg'):
save_kwargs = {'quality': quality, 'optimize': true}
elif output_format == 'webp':
save_kwargs = {'quality': quality, 'method': 6}
elif output_format == 'png':
save_kwargs = {'optimize': true}
img.save(output_file, **save_kwargs)
# 打印对比
original_size = input_path.stat().st_size
new_size = output_file.stat().st_size
ratio = (1 - new_size / original_size) * 100
print(f"{input_path.name} ({original_size / 1024:.1f}kb) → "
f"{output_file.name} ({new_size / 1024:.1f}kb) "
f"[{'+' if ratio < 0 else '-'}{abs(ratio):.1f}%]")
return output_file
# ==================== 方案 2:批量转换 ====================
def batch_convert_folder(input_dir, output_dir, output_format='jpg', quality=85):
"""
批量转换文件夹中的所有图片
"""
input_path = path(input_dir)
output_path = path(output_dir)
output_path.mkdir(parents=true, exist_ok=true)
count = 0
total_saved = 0
for file_path in input_path.iterdir():
if file_path.is_file() and file_path.suffix.lower() in supported_extensions:
output_file = output_path / f"{file_path.stem}.{output_format}"
img = image.open(file_path)
original_size = file_path.stat().st_size
# 处理 rgba → rgb
if output_format in ('jpg', 'jpeg', 'bmp') and img.mode == 'rgba':
background = image.new('rgb', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3])
img = background
save_kwargs = {}
if output_format in ('jpg', 'jpeg'):
save_kwargs = {'quality': quality, 'optimize': true}
elif output_format == 'webp':
save_kwargs = {'quality': quality, 'method': 6}
img.save(output_file, **save_kwargs)
new_size = output_file.stat().st_size
total_saved += original_size - new_size
count += 1
print(f"\n批量转换完成: {count} 张图片")
print(f"节省空间: {total_saved / 1024 / 1024:.2f} mb")
# ==================== 方案 3:批量压缩(不改变格式) ====================
def batch_compress_images(input_dir, output_dir, quality=75, max_width=1920, max_height=1080):
"""
批量压缩图片(保持原格式,降低质量和尺寸)
"""
input_path = path(input_dir)
output_path = path(output_dir)
output_path.mkdir(parents=true, exist_ok=true)
count = 0
total_saved = 0
for file_path in input_path.iterdir():
if file_path.is_file() and file_path.suffix.lower() in {'.jpg', '.jpeg', '.png', '.webp'}:
img = image.open(file_path)
# 缩小尺寸
if max_width and max_height:
img.thumbnail((max_width, max_height), image.lanczos)
save_kwargs = {}
if file_path.suffix.lower() in ('.jpg', '.jpeg'):
save_kwargs = {'quality': quality, 'optimize': true}
output_file = output_path / file_path.name
img.save(output_file, **save_kwargs)
original_size = file_path.stat().st_size
new_size = output_file.stat().st_size
total_saved += original_size - new_size
count += 1
print(f"批量压缩完成: {count} 张图片")
print(f"节省空间: {total_saved / 1024 / 1024:.2f} mb")
# ==================== 使用示例 ====================
if __name__ == "__main__":
# 单个转换
# convert_image("photo.png", output_format='jpg', quality=85)
# 批量转 webp(网页优化)
batch_convert_folder("产品图片", "产品图片_webp", output_format='webp', quality=80)
# 批量压缩
# batch_compress_images("原始照片", "压缩照片", quality=75, max_width=1920)常见问题
q1:gif 动图转换后不动了?
pillow 默认只读取 gif 的第一帧。如需保留动画,使用 imageio:
pip install imageio
import imageio
frames = imageio.mimread('animation.gif')
imageio.mimwrite('output.webp', frames, duration=0.1)
q2:jpg 转 png 后体积变大很多?
jpg 是有损压缩,png 是无损压缩。jpg → png 会"放大"原本被压缩的信息。建议反向转换(png → jpg)来减小体积。
总结
| 操作 | 方法 | 效果 |
|---|---|---|
| 格式转换 | img.save('output.jpg') | 自动转换 |
| 压缩质量 | quality=75 | 降低文件大小 |
| 缩小尺寸 | img.thumbnail() | 等比例缩放 |
| 透明处理 | rgba → rgb | jpg 兼容 |
到此这篇关于python实现图片格式(webp/png/jpg)批量互转及无损压缩的文章就介绍到这了,更多相关python图片格式转换内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论