本文目录导读:

我来为您介绍一个使用Python实现批量图片压缩的完整案例。
使用PIL/Pillow库压缩图片
安装依赖
pip install Pillow
基础压缩实现
import os
from PIL import Image
from pathlib import Path
def compress_image(input_path, output_path, quality=85):
"""
压缩单张图片
Args:
input_path: 输入图片路径
output_path: 输出图片路径
quality: 压缩质量 (1-100),越小压缩率越高
"""
try:
# 打开图片
img = Image.open(input_path)
# 如果图片有透明度,转换为RGB
if img.mode in ('RGBA', 'LA', 'P'):
rgb_img = Image.new('RGB', img.size, (255, 255, 255))
rgb_img.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
img = rgb_img
# 保存压缩后的图片
img.save(output_path, 'JPEG', optimize=True, quality=quality)
return True
except Exception as e:
print(f"压缩失败 {input_path}: {str(e)}")
return False
def batch_compress_images(input_dir, output_dir, quality=85, file_types=['.jpg', '.jpeg', '.png']):
"""
批量压缩图片
Args:
input_dir: 输入目录
output_dir: 输出目录
quality: 压缩质量
file_types: 要处理的文件类型列表
"""
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 统计信息
total_files = 0
compressed_files = 0
total_original_size = 0
total_compressed_size = 0
# 遍历输入目录
for file_path in Path(input_dir).rglob('*'):
if file_path.suffix.lower() in file_types:
total_files += 1
original_size = file_path.stat().st_size
total_original_size += original_size
# 构建输出路径(保持目录结构)
relative_path = file_path.relative_to(input_dir)
output_path = Path(output_dir) / relative_path
output_path.parent.mkdir(parents=True, exist_ok=True)
# 压缩图片
if compress_image(str(file_path), str(output_path), quality):
compressed_size = output_path.stat().st_size
total_compressed_size += compressed_size
compressed_files += 1
# 计算压缩率
compression_ratio = (1 - compressed_size / original_size) * 100
print(f"✓ {relative_path}: {original_size/1024:.1f}KB -> {compressed_size/1024:.1f}KB ({compression_ratio:.1f}%)")
else:
print(f"✗ {relative_path}: 压缩失败")
# 输出统计信息
print("\n" + "="*50)
print(f"压缩完成统计:")
print(f"处理文件数: {compressed_files}/{total_files}")
print(f"原始总大小: {total_original_size/1024/1024:.2f}MB")
print(f"压缩后大小: {total_compressed_size/1024/1024:.2f}MB")
print(f"总压缩率: {(1-total_compressed_size/total_original_size)*100:.1f}%")
# 使用示例
if __name__ == "__main__":
# 压缩当前目录下的images文件夹中的图片到compressed_images文件夹
batch_compress_images(
input_dir="./images",
output_dir="./compressed_images",
quality=85,
file_types=['.jpg', '.jpeg', '.png']
)
进阶版本:支持更多选项
import os
from PIL import Image
from pathlib import Path
from typing import List, Optional
import concurrent.futures
class ImageCompressor:
"""图片压缩器类"""
def __init__(self, quality=85, max_size=None, scale_factor=1.0):
"""
初始化压缩器
Args:
quality: JPEG压缩质量
max_size: 最大尺寸(像素),如果图片长边超过此值则进行缩放
scale_factor: 缩放因子
"""
self.quality = quality
self.max_size = max_size
self.scale_factor = scale_factor
def compress_single(self, input_path: str, output_path: str) -> Optional[dict]:
"""
压缩单张图片,返回压缩信息
Returns:
压缩信息字典,失败返回None
"""
try:
img = Image.open(input_path)
# 处理透明度
if img.mode in ('RGBA', 'LA', 'P'):
if img.mode == 'P':
img = img.convert('RGBA')
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[-1])
img = background
elif img.mode != 'RGB':
img = img.convert('RGB')
# 缩放处理
if self.max_size or self.scale_factor != 1.0:
width, height = img.size
if self.scale_factor != 1.0:
new_width = int(width * self.scale_factor)
new_height = int(height * self.scale_factor)
elif self.max_size:
ratio = min(self.max_size / width, self.max_size / height)
new_width = int(width * ratio)
new_height = int(height * ratio)
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# 根据原图格式选择保存方式
suffix = Path(input_path).suffix.lower()
if suffix in ['.png']:
# PNG格式使用不同的保存参数
img.save(output_path, 'PNG', optimize=True)
else:
img.save(output_path, 'JPEG', optimize=True, quality=self.quality)
# 返回压缩信息
original_size = Path(input_path).stat().st_size
compressed_size = Path(output_path).stat().st_size
return {
'path': input_path,
'original_size': original_size,
'compressed_size': compressed_size,
'compression_ratio': (1 - compressed_size / original_size) * 100
}
except Exception as e:
print(f"压缩失败 {input_path}: {str(e)}")
return None
def batch_compress(self, input_dir: str, output_dir: str,
file_types: List[str] = None,
max_workers: int = 4,
preserve_structure: bool = True):
"""
批量压缩图片
Args:
input_dir: 输入目录
output_dir: 输出目录
file_types: 文件类型列表
max_workers: 并行工作线程数
preserve_structure: 是否保持目录结构
"""
if file_types is None:
file_types = ['.jpg', '.jpeg', '.png', '.bmp', '.webp']
os.makedirs(output_dir, exist_ok=True)
# 收集所有图片文件
image_files = []
for file_path in Path(input_dir).rglob('*'):
if file_path.suffix.lower() in [ft.lower() for ft in file_types]:
image_files.append(file_path)
print(f"找到 {len(image_files)} 个图片文件")
# 使用线程池并行处理
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = []
for file_path in image_files:
if preserve_structure:
relative_path = file_path.relative_to(input_dir)
output_path = Path(output_dir) / relative_path
else:
output_path = Path(output_dir) / file_path.name
output_path.parent.mkdir(parents=True, exist_ok=True)
# 提交任务
future = executor.submit(
self.compress_single,
str(file_path),
str(output_path)
)
futures.append(future)
# 收集结果
for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
results.append(result)
print(f"✓ {Path(result['path']).name}: "
f"{result['original_size']/1024:.1f}KB → "
f"{result['compressed_size']/1024:.1f}KB "
f"({result['compression_ratio']:.1f}%)")
# 输出汇总
self._print_summary(results)
def _print_summary(self, results: List[dict]):
"""打印汇总信息"""
if not results:
print("没有成功处理的文件")
return
total_original = sum(r['original_size'] for r in results)
total_compressed = sum(r['compressed_size'] for r in results)
avg_ratio = sum(r['compression_ratio'] for r in results) / len(results)
print("\n" + "="*50)
print("压缩完成统计:")
print(f"成功处理: {len(results)} 个文件")
print(f"原始总大小: {total_original/1024/1024:.2f} MB")
print(f"压缩后大小: {total_compressed/1024/1024:.2f} MB")
print(f"总压缩率: {(1-total_compressed/total_original)*100:.1f}%")
print(f"平均压缩率: {avg_ratio:.1f}%")
# 使用示例
def main():
# 创建压缩器实例
compressor = ImageCompressor(
quality=80, # 压缩质量
max_size=1920, # 最大边长限制
scale_factor=1.0 # 缩放因子(1.0保持不变)
)
# 批量压缩(保持目录结构)
compressor.batch_compress(
input_dir="./images",
output_dir="./compressed",
file_types=['.jpg', '.jpeg', '.png'],
max_workers=4
)
if __name__ == "__main__":
main()
带命令行界面的版本
import argparse
from pathlib import Path
def main_cli():
"""命令行界面"""
parser = argparse.ArgumentParser(description='批量图片压缩工具')
parser.add_argument('input_dir', help='输入目录')
parser.add_argument('output_dir', help='输出目录')
parser.add_argument('-q', '--quality', type=int, default=85,
help='压缩质量 (1-100),默认85')
parser.add_argument('-m', '--max-size', type=int, default=None,
help='最大尺寸,超过则缩放')
parser.add_argument('-s', '--scale', type=float, default=1.0,
help='缩放因子,默认1.0')
parser.add_argument('-w', '--workers', type=int, default=4,
help='并行处理数量,默认4')
parser.add_argument('-t', '--types', nargs='+',
default=['.jpg', '.jpeg', '.png'],
help='处理的文件类型')
args = parser.parse_args()
# 验证参数
if not Path(args.input_dir).exists():
print(f"输入目录不存在: {args.input_dir}")
return
if args.quality < 1 or args.quality > 100:
print("质量参数必须在1-100之间")
return
# 创建压缩器并执行
compressor = ImageCompressor(
quality=args.quality,
max_size=args.max_size,
scale_factor=args.scale
)
compressor.batch_compress(
input_dir=args.input_dir,
output_dir=args.output_dir,
file_types=args.types,
max_workers=args.workers
)
if __name__ == "__main__":
main_cli()
使用说明
命令行使用
# 基本使用 python image_compressor.py ./images ./compressed # 指定质量参数 python image_compressor.py ./images ./compressed -q 70 # 限制图片大小 python image_compressor.py ./images ./compressed -m 1920 # 缩放图片 python image_compressor.py ./images ./compressed -s 0.5 # 自定义文件类型 python image_compressor.py ./images ./compressed -t .jpg .png # 使用更多线程 python image_compressor.py ./images ./compressed -w 8
作为模块使用
from image_compressor import ImageCompressor
# 创建压缩器
compressor = ImageCompressor(quality=80, max_size=1920)
# 批量压缩
compressor.batch_compress(
input_dir="./photos",
output_dir="./compressed_photos"
)
这个方案具有以下特点:
- 性能优化:使用线程池并行处理,提高处理速度
- 质量可控:可调整压缩质量和缩放比例
- 格式支持:支持常见图片格式(JPG、PNG、BMP等)
- 目录结构保持:可选择保持原始目录结构
- 错误处理:单个文件失败不影响其他文件处理
- 统计信息:输出压缩前后的详细信息
您可以根据实际需求选择合适的版本或进行定制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播