更新版本,压缩图片跟小一点源码
resize2K.py
"""
批量处理图片像素大小,将大于目标像素的图片按比例调整到目标像素以下
目标像素: 3686400 (即 3686400 + 20000 的阈值)
"""
from PIL import Image
import os
import json
import glob
Image.MAX_IMAGE_PIXELS = None
TARGET_PIXELS = 3686400 / 2
THRESHOLD_PIXELS = TARGET_PIXELS + 20000
WHITELIST_FILE = "whitelist.json"
def load_whitelist():
"""加载白名单"""
if os.path.exists(WHITELIST_FILE):
try:
with open(WHITELIST_FILE, 'r', encoding='utf-8') as f:
return set(json.load(f))
except Exception as e:
print(f"加载白名单失败: {e},将创建新的白名单")
return set()
return set()
def save_whitelist(whitelist):
"""保存白名单"""
try:
with open(WHITELIST_FILE, 'w', encoding='utf-8') as f:
json.dump(list(whitelist), f, ensure_ascii=False, indent=2)
print(f"白名单已保存: {WHITELIST_FILE}")
except Exception as e:
print(f"保存白名单失败: {e}")
def needs_resize(width, height):
"""检查图片是否需要调整"""
total_pixels = width * height
print(f" 像素检查: {width} x {height} = {total_pixels:,} (阈值: {THRESHOLD_PIXELS:,})")
return total_pixels > THRESHOLD_PIXELS
def calculate_new_size(width, height):
"""计算调整后的新尺寸,保持宽高比"""
current_pixels = width * height
scale_ratio = (TARGET_PIXELS / current_pixels) ** 0.5
new_width = int(width * scale_ratio)
new_height = int(height * scale_ratio)
final_pixels = new_width * new_height
if final_pixels > TARGET_PIXELS:
adjustment = (TARGET_PIXELS / final_pixels) ** 0.5
new_width = int(new_width * adjustment)
new_height = int(new_height * adjustment)
print(f" 缩放计算: {width}x{height} -> {new_width}x{new_height}")
print(f" 像素变化: {current_pixels:,} -> {new_width * new_height:,}")
return new_width, new_height
def resize_image_direct(input_path, output_path, quality=85):
"""直接处理图片 - 包含超大图片删除功能"""
try:
with Image.open(input_path) as img:
if img.mode != 'RGB':
img = img.convert('RGB')
width, height = img.size
total_pixels = width * height
if total_pixels > 150000000:
print(f" ⚠️ 图片像素过大: {total_pixels:,} > 150,000,000")
print(f" 🗑️ 删除文件: {os.path.basename(input_path)}")
img.close()
try:
os.remove(input_path)
if os.path.exists(input_path):
print(" ✗ 文件删除失败")
return False
else:
print(" ✓ 文件已成功删除")
return True
except Exception as delete_error:
print(f" ✗ 删除文件时出错: {delete_error}")
return False
print(f" 图片尺寸: {width}x{height} (像素: {total_pixels:,})")
new_width, new_height = calculate_new_size(width, height)
if new_width == width and new_height == height:
print(" 无需调整,尺寸相同")
return False
print(f" 新尺寸: {new_width}x{new_height}")
print(f" 缩放比例: {new_width/width*100:.1f}%")
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
resized_img.save(output_path, 'JPEG', quality=quality, optimize=True)
if os.path.exists(output_path):
new_size = os.path.getsize(output_path) / 1024
print(f" 文件大小: {new_size:.1f}KB")
print(f" ✓ 调整完成: {output_path}")
return True
else:
print(" ✗ 文件保存失败")
return False
except Exception as e:
print(f" ✗ 处理失败: {e}")
return False
def process_single_image(input_path, output_path=None, quality=85):
"""处理单张图片"""
try:
print(f"\n处理图片: {os.path.basename(input_path)}")
if not os.path.exists(input_path):
print(f" ✗ 文件不存在: {input_path}")
return False, 0
with Image.open(input_path) as img:
width, height = img.size
total_pixels = width * height
print(f" 原尺寸: {width}x{height}")
print(f" 总像素: {total_pixels:,}")
if not needs_resize(width, height):
print(" ✓ 无需调整,像素未超过阈值")
return False, total_pixels
if output_path is None:
output_path = input_path
success = resize_image_direct(input_path, output_path, quality)
return success, total_pixels
except Exception as e:
print(f" ✗ 处理错误: {e}")
return False, 0
def batch_process_images(quality=85, overwrite=True):
"""批量处理当前目录下的所有JPG图片"""
print("开始批量处理图片...")
print(f"目标像素: {TARGET_PIXELS:,}")
print(f"调整阈值: {THRESHOLD_PIXELS:,}")
print("-" * 60)
jpg_files = []
for pattern in ["*.jpg", "*.JPG", "*.jpeg", "*.JPEG"]:
jpg_files.extend(glob.glob(pattern))
jpg_files = list(set(jpg_files))
if not jpg_files:
print("当前目录下未找到JPG图片文件")
print("支持的格式: .jpg, .jpeg (不区分大小写)")
return
print(f"找到 {len(jpg_files)} 个JPG文件:")
for i, file in enumerate(jpg_files, 1):
print(f" {i}. {file}")
print()
whitelist = load_whitelist()
if whitelist:
print(f"白名单中有 {len(whitelist)} 个文件:")
for file in whitelist:
print(f" - {file}")
else:
print("白名单为空")
print()
processed_count = 0
resized_count = 0
skipped_whitelist = 0
skipped_small = 0
for jpg_file in jpg_files:
filename = os.path.basename(jpg_file)
if filename in whitelist:
print(f"跳过白名单文件: {filename}")
skipped_whitelist += 1
continue
if overwrite:
output_path = jpg_file
else:
name, ext = os.path.splitext(jpg_file)
output_path = f"{name}_resized{ext}"
success, original_pixels = process_single_image(jpg_file, output_path, quality)
if success:
processed_count += 1
resized_count += 1
else:
processed_count += 1
if original_pixels <= THRESHOLD_PIXELS and original_pixels > 0:
whitelist.add(filename)
skipped_small += 1
print(f" ✓ 添加到白名单: {filename}")
if skipped_small > 0:
save_whitelist(whitelist)
print("-" * 60)
print("处理完成!统计信息:")
print(f"总文件数: {len(jpg_files)}")
print(f"已处理: {processed_count}")
print(f"已调整: {resized_count}")
print(f"跳过(白名单): {skipped_whitelist}")
print(f"跳过(像素小): {skipped_small}")
print(f"白名单文件数: {len(whitelist)}")
def debug_single_file(filename):
"""调试单个文件"""
if not os.path.exists(filename):
print(f"文件不存在: {filename}")
return
print(f"调试文件: {filename}")
with Image.open(filename) as img:
width, height = img.size
total_pixels = width * height
print(f"尺寸: {width}x{height}")
print(f"像素: {total_pixels:,}")
print(f"阈值: {THRESHOLD_PIXELS:,}")
print(f"需要调整: {needs_resize(width, height)}")
if needs_resize(width, height):
new_width, new_height = calculate_new_size(width, height)
print(f"新尺寸: {new_width}x{new_height}")
print(f"新像素: {new_width * new_height:,}")
def main():
"""主函数"""
import argparse
parser = argparse.ArgumentParser(description='批量调整图片像素大小')
parser.add_argument('--quality', '-q', type=int, default=85,
help='JPEG质量 (1-100,默认85)')
parser.add_argument('--no-overwrite', action='store_true',
help='不覆盖原文件,创建新文件')
parser.add_argument('--whitelist', action='store_true',
help='显示白名单')
parser.add_argument('--remove', metavar='FILENAME',
help='从白名单中移除指定文件')
parser.add_argument('--clear-whitelist', action='store_true',
help='清空白名单')
parser.add_argument('--debug', metavar='FILENAME',
help='调试单个文件')
args = parser.parse_args()
if not 1 <= args.quality <= 100:
print("错误:质量参数必须在1-100之间")
return
if args.debug:
debug_single_file(args.debug)
elif args.whitelist:
whitelist = load_whitelist()
if whitelist:
print("白名单文件:")
for filename in sorted(whitelist):
print(f" - {filename}")
else:
print("白名单为空")
elif args.remove:
whitelist = load_whitelist()
if args.remove in whitelist:
whitelist.remove(args.remove)
save_whitelist(whitelist)
print(f"已从白名单移除: {args.remove}")
else:
print(f"文件不在白名单中: {args.remove}")
elif args.clear_whitelist:
if os.path.exists(WHITELIST_FILE):
os.remove(WHITELIST_FILE)
print("白名单已清空")
else:
print("白名单文件不存在")
else:
overwrite = not args.no_overwrite
batch_process_images(quality=args.quality, overwrite=overwrite)
if __name__ == "__main__":
import sys
if len(sys.argv) == 1:
print("图片像素批量调整工具")
print("功能:将像素大于3,706,400的图片调整到3,686,400像素以下")
print("\n直接开始批量处理...")
print("=" * 60)
batch_process_images(quality=85, overwrite=True)
else:
main()