带统计带进度条多线程的python批量压缩图片
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, file_size_kb else: logging.info(f"跳过小于{size_threshold_kb}KB的图片: {input_path}") return False, file_size_kb except Exception as e: logging.error(f"压缩图片时发生错误: {input_path}. 错误信息: {str(e)}") return False, 0 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 total_compressed_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) # 提交任务到线程池 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="多线程处理"): success, file_size_kb = future.result() if success: compressed_images += 1 total_original_size += file_size_kb total_compressed_size += os.path.getsize(future.result()) / 1024 # 更新进度条 progress_bar.update(1) # 关闭进度条 progress_bar.close() # 计算压缩比例 compression_ratio = 1.0 - (total_compressed_size / total_original_size) if total_original_size > 0 else 0 # 记录统计信息 logging.info(f"总共图片数: {total_images}") logging.info(f"成功压缩图片数: {compressed_images}") logging.info(f"总原始大小: {total_original_size:.2f} KB") logging.info(f"总压缩后大小: {total_compressed_size:.2f} KB") logging.info(f"总压缩比例: {compression_ratio * 100:.2f}%") # 输出日志文件路径 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("图片压缩完成。日志文件详见压缩日志。")