查看: 1368|回复: 3

Python脚本实现Webp PNG JPG图片批量互转与无损压缩

[复制链接]
发表于 昨天 14:00 | 显示全部楼层 |阅读模式
在网站图片优化、客户交付或系统图标上传等场景中,经常需要把图片在 WebP、PNG、JPG 之间互相转换,同时兼顾体积压缩。手动用画图工具逐张处理效率太低,用 Python 结合 Pillow 可以快速实现批量转换与压缩。

Pillow 是 Python 最常用的图像处理库,它可以把任意常见格式的图片读取为统一的 Image 对象,再按指定格式保存。转换时主要涉及有损/无损格式差异、透明通道处理和压缩质量参数。JPG 使用有损压缩且不支持透明;PNG 使用无损压缩且支持透明;WebP 是 Google 推出的网页图片格式,体积通常更小;BMP 无压缩,TIFF 支持多层,适合存档。

环境准备:
pip install Pillow

代码实现分为三个工具函数。

一、单张格式转换
convert_image(input_file, output_format='jpg', quality=85, max_size=None) 接收输入路径、目标格式、质量值和最大尺寸。打开图片后,若指定 max_size 则用 thumbnail 等比缩放;若输出格式为 jpg/jpeg/bmp 且原图是 RGBA,则先用白色背景合成,去掉透明通道;输出文件名自动替换扩展名;保存时按格式设置不同参数:jpg/jpeg 用 quality+optimize,webp 用 quality+method=6,png 用 optimize。最后打印原图与新图体积差。
  1. import os
  2. from pathlib import Path
  3. from PIL import Image
  4. SUPPORTED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.webp', '.bmp', '.tiff', '.gif'}
  5. def convert_image(input_file, output_format='jpg', quality=85, max_size=None):
  6.     input_path = Path(input_file)
  7.     img = Image.open(input_path)
  8.     if max_size:
  9.         img.thumbnail(max_size, Image.LANCZOS)
  10.     if output_format in ('jpg', 'jpeg', 'bmp') and img.mode == 'RGBA':
  11.         background = Image.new('RGB', img.size, (255, 255, 255))
  12.         background.paste(img, mask=img.split()[3])
  13.         img = background
  14.     output_file = input_path.with_suffix(f'.{output_format}')
  15.     save_kwargs = {}
  16.     if output_format in ('jpg', 'jpeg'):
  17.         save_kwargs = {'quality': quality, 'optimize': True}
  18.     elif output_format == 'webp':
  19.         save_kwargs = {'quality': quality, 'method': 6}
  20.     elif output_format == 'png':
  21.         save_kwargs = {'optimize': True}
  22.     img.save(output_file, **save_kwargs)
  23.     original_size = input_path.stat().st_size
  24.     new_size = output_file.stat().st_size
  25.     ratio = (1 - new_size / original_size) * 100
  26.     print(f"{input_path.name} ({original_size / 1024:.1f}KB) → "
  27.           f"{output_file.name} ({new_size / 1024:.1f}KB) "
  28.           f"[{'+' if ratio < 0 else '-'}{abs(ratio):.1f}%]")
  29.     return output_file
复制代码

二、批量转换文件夹
batch_convert_folder(input_dir, output_dir, output_format='jpg', quality=85) 遍历输入目录中的所有支持格式文件,输出到指定目录。对 RGBA 透明图同样做白色背景处理;jpg/jpeg 使用 quality+optimize,webp 使用 quality+method=6。最后统计转换张数和节省空间。
  1. def batch_convert_folder(input_dir, output_dir, output_format='jpg', quality=85):
  2.     input_path = Path(input_dir)
  3.     output_path = Path(output_dir)
  4.     output_path.mkdir(parents=True, exist_ok=True)
  5.     count = 0
  6.     total_saved = 0
  7.     for file_path in input_path.iterdir():
  8.         if file_path.is_file() and file_path.suffix.lower() in SUPPORTED_EXTENSIONS:
  9.             output_file = output_path / f"{file_path.stem}.{output_format}"
  10.             img = Image.open(file_path)
  11.             original_size = file_path.stat().st_size
  12.             if output_format in ('jpg', 'jpeg', 'bmp') and img.mode == 'RGBA':
  13.                 background = Image.new('RGB', img.size, (255, 255, 255))
  14.                 background.paste(img, mask=img.split()[3])
  15.                 img = background
  16.             save_kwargs = {}
  17.             if output_format in ('jpg', 'jpeg'):
  18.                 save_kwargs = {'quality': quality, 'optimize': True}
  19.             elif output_format == 'webp':
  20.                 save_kwargs = {'quality': quality, 'method': 6}
  21.             img.save(output_file, **save_kwargs)
  22.             new_size = output_file.stat().st_size
  23.             total_saved += original_size - new_size
  24.             count += 1
  25.     print(f"\n批量转换完成: {count} 张图片")
  26.     print(f"节省空间: {total_saved / 1024 / 1024:.2f} MB")
复制代码

三、批量压缩(保持原格式)
batch_compress_images(input_dir, output_dir, quality=75, max_width=1920, max_height=1080) 遍历 jpg/jpeg/png/webp 文件,先将图片等比缩放到不超过 max_width×max_height,再按质量参数保存。注意:原代码中 save_kwargs 只在 jpg/jpeg 分支定义,若处理 png/webp 会报错;实际使用时需要为 png/webp 补充对应的保存参数。这一点在原作者提供的示例中也未覆盖,读者需留意。
  1. def batch_compress_images(input_dir, output_dir, quality=75, max_width=1920, max_height=1080):
  2.     input_path = Path(input_dir)
  3.     output_path = Path(output_dir)
  4.     output_path.mkdir(parents=True, exist_ok=True)
  5.     count = 0
  6.     total_saved = 0
  7.     for file_path in input_path.iterdir():
  8.         if file_path.is_file() and file_path.suffix.lower() in {'.jpg', '.jpeg', '.png', '.webp'}:
  9.             img = Image.open(file_path)
  10.             if max_width and max_height:
  11.                 img.thumbnail((max_width, max_height), Image.LANCZOS)
  12.             save_kwargs = {}
  13.             if file_path.suffix.lower() in ('.jpg', '.jpeg'):
  14.                 save_kwargs = {'quality': quality, 'optimize': True}
  15.             # 注意:原代码没有处理 png/webp 的保存参数
  16.             output_file = output_path / file_path.name
  17.             img.save(output_file, **save_kwargs)
  18.             original_size = file_path.stat().st_size
  19.             new_size = output_file.stat().st_size
  20.             total_saved += original_size - new_size
  21.             count += 1
  22.     print(f"批量压缩完成: {count} 张图片")
  23.     print(f"节省空间: {total_saved / 1024 / 1024:.2f} MB")
复制代码

四、使用示例
主入口示范了批量转 WebP 的调用方式。单张转换和批量压缩的调用已注释,按需放开即可。
  1. if __name__ == "__main__":
  2.     # convert_image("photo.png", output_format='jpg', quality=85)
  3.     batch_convert_folder("产品图片", "产品图片_WebP", output_format='webp', quality=80)
  4.     # batch_compress_images("原始照片", "压缩照片", quality=75, max_width=1920)
复制代码

常见问题:
Q1: GIF 动图转换后不动了?
Pillow 默认只读取 GIF 的第一帧,所以动画会丢失。要保留动画,可以安装 imageio:pip install imageio,然后用 imageio.mimread 读取所有帧,再用 imageio.mimwrite 写出 WebP(duration=0.1 控制帧间隔)。

Q2: JPG 转 PNG 后体积变大很多?
因为 JPG 是有损压缩,PNG 是无损压缩,JPG 转 PNG 会把原本丢失的信息重新“放大”保存,导致体积增加。如果目标是减小体积,反向从 PNG 转 JPG 更合适。

总结:
- 格式转换:img.save('output.jpg') 即可自动按扩展名转换。
- 压缩质量:quality=75 左右能在体积和画质间取得平衡。
- 尺寸缩放:img.thumbnail() 按比例缩小,避免拉伸变形。
- 透明处理:JPG 不支持 alpha 通道,RGBA 转 RGB 时先用白色背景合成。

这样一套脚本可以覆盖日常图片处理需求,在批量转换和压缩场景下替代人工操作,节省大量时间。
回复

使用道具 举报

发表于 昨天 19:00 | 显示全部楼层

Re: Python脚本实现Webp PNG JPG图片批量互转与无损压缩

这个脚本写得很实用,正好最近在处理网站图片优化,收藏了。特别是透明通道转白底的处理很贴心,避免了很多时候JPG直接打开透明图会变黑底的问题。想问一下,WebP的method=6在批量大图的时候速度会不会比较慢?有没有考虑加一个线程池或者进度显示的选项?
回复 支持 反对

使用道具 举报

发表于 昨天 19:00 | 显示全部楼层

Re: Python脚本实现Webp PNG JPG图片批量互转与无损压缩

这个脚本很实用,正好最近在整理网站图片,手动用PS一张张转太痛苦了。我试了下批量转WebP,体积确实小了很多,尤其是不透明图片。 有个小建议:对于带透明通道的PNG转成JPG时,默认用白底填充有时候会和原图视觉差异较大,如果能在函数里加个参数允许自定义背景色(比如透明转成黑色底或者棋盘格)就更灵活了。另外,批量转换时如果输入目录里有子文件夹的话,目前只会处理当前层级的文件,如果能递归遍历就更方便了。 不过总体逻辑很清晰,尤其是用thumbnail等比缩放那一步,对需要控制最大尺寸的场景非常有用。感谢分享!
回复 支持 反对

使用道具 举报

发表于 昨天 19:00 | 显示全部楼层

Re: Python脚本实现Webp PNG JPG图片批量互转与无损压缩

楼主这脚本挺实用的,正好我最近在处理一批网站素材。有个小建议:如果原图是灰度模式或CMYK模式,转换时可能要先转成RGB,不然某些格式会报错;另外批量转换那边如果输入输出目录相同,会不会覆盖原文件?可以考虑加个自动重命名或备份逻辑。总之代码写得很清晰,收藏了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-1 02:38 , Processed in 0.021875 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部