from PIL import Image
import os
import logging
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
from tqdm import tqdm
def resize_and_compress_image(input_path, quality, size_threshold_kb, max_width):
try:
# 获取图片文件大小
file_size_kb = os.path.getsize(input_path) / 1024
# 仅当图片大小大于300KB时进行压缩
if file_size_kb > size_threshold_kb:
# 打开图片
img = Image.open(input_path)
# 调整宽度为最大值1000像素
if img.width > max_width:
ratio = max_width / float(img.width)
new_height = int(float(img.height) * float(ratio))
img = img.resize((max_width, new_height), Image.LANCZOS)
# 覆盖保存为JPEG或PNG格式,根据文件类型设置相应的参数
if input_path.lower().endswith(('.jpg', '.jpeg')):
img.save(input_path, 'JPEG', quality=quality, optimize=True)
elif input_path.lower().endswith('.png'):
img.save(input_path, 'PNG', optimize=True)
logging.info(f"成功压缩图片: {input_path}")
return True
else:
logging.info(f"跳过小于{size_threshold_kb}KB的图片: {input_path}")
return False
except Exception as e:
logging.error(f"压缩图片时发生错误: {input_path}. 错误信息: {str(e)}")
return False
def resize_and_compress_images(input_folder, quality=85, size_threshold_kb=300, max_width=1000, num_threads=4):
# 设置日志
log_file = f"compression_log_{datetime.now().strftime('%Y%m%d%H%M%S')}.txt"
logging.basicConfig(filename=log_file, level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
# 获取总图片数
total_images = sum([len(files) for _, _, files in os.walk(input_folder)])
# 初始化tqdm
progress_bar = tqdm(total=total_images, desc="处理进度")
# 统计信息
compressed_images = 0
total_original_size = 0
# 设置线程池
with ThreadPoolExecutor(max_workers=num_threads) as executor:
futures = []
for root, dirs, files in os.walk(input_folder):
for image_file in files:
input_path = os.path.join(root, image_file)
# 获取图片文件大小
file_size_kb = os.path.getsize(input_path) / 1024
total_original_size += file_size_kb
# 提交任务到线程池
future = executor.submit(resize_and_compress_image, input_path, quality, size_threshold_kb, max_width)
futures.append(future)
# 等待所有任务完成
for future in tqdm(futures, total=len(futures), desc="多线程处理"):
if future.result():
compressed_images += 1
# 更新进度条
progress_bar.update(1)
# 关闭进度条
progress_bar.close()
# 记录统计信息
logging.info(f"总共图片数: {total_images}")
logging.info(f"成功压缩图片数: {compressed_images}")
# 输出日志文件路径
print(f"日志文件路径: {os.path.abspath(log_file)}")
if __name__ == "__main__":
# 输入文件夹(包含待压缩的JPEG和PNG图片)
input_folder = "input_images"
# 设置压缩质量(仅适用于JPEG,0-100,100为最高质量)
compression_quality = 85
# 设置图片大小阈值(大于该阈值才进行压缩)
size_threshold_kb = 300
# 设置最大宽度
max_width = 1000
# 设置线程数
num_threads = 4
# 执行图片压缩(直接覆盖原文件)
resize_and_compress_images(input_folder, quality=compression_quality, size_threshold_kb=size_threshold_kb, max_width=max_width, num_threads=num_threads)
print("图片压缩完成。日志文件详见压缩日志。")