133 lines
3.9 KiB
Python
133 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
图片尺寸压缩工具
|
|
将宽度超过 2180 像素的图片等比例压缩
|
|
"""
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
# 配置
|
|
MAX_WIDTH = 2180
|
|
SOURCE_DIR = Path('/home/ubuntu/images')
|
|
BACKUP_DIR = SOURCE_DIR / 'original_backup'
|
|
|
|
def get_image_size(filepath):
|
|
"""获取图片尺寸"""
|
|
try:
|
|
result = subprocess.run(
|
|
['identify', '-format', '%w %h', str(filepath)],
|
|
capture_output=True, text=True, check=True
|
|
)
|
|
width, height = map(int, result.stdout.strip().split())
|
|
return width, height
|
|
except:
|
|
return None, None
|
|
|
|
def resize_image(filepath, output_path):
|
|
"""压缩图片,保持比例,宽度限制为 MAX_WIDTH"""
|
|
try:
|
|
# 使用 ImageMagick convert
|
|
# -resize 2180x> 表示宽度最大2180,高度自适应,>表示只缩小不放大
|
|
cmd = [
|
|
'convert', str(filepath),
|
|
'-resize', f'{MAX_WIDTH}x>',
|
|
'-quality', '90', # 保持较好质量
|
|
str(output_path)
|
|
]
|
|
subprocess.run(cmd, check=True, capture_output=True)
|
|
return True
|
|
except Exception as e:
|
|
print(f" ❌ 压缩失败: {e}")
|
|
return False
|
|
|
|
def main():
|
|
print("=" * 60)
|
|
print(f"🖼️ 图片尺寸压缩工具")
|
|
print(f" 最大宽度: {MAX_WIDTH}px")
|
|
print(f" 源目录: {SOURCE_DIR}")
|
|
print("=" * 60)
|
|
|
|
if not SOURCE_DIR.exists():
|
|
print(f"❌ 目录不存在: {SOURCE_DIR}")
|
|
sys.exit(1)
|
|
|
|
# 支持的图片格式
|
|
extensions = {'.jpg', '.jpeg', '.png', '.webp', '.gif', '.bmp'}
|
|
|
|
# 收集需要处理的图片
|
|
to_process = []
|
|
for file in SOURCE_DIR.iterdir():
|
|
if file.is_file() and file.suffix.lower() in extensions:
|
|
width, height = get_image_size(file)
|
|
if width and width > MAX_WIDTH:
|
|
to_process.append({
|
|
'file': file,
|
|
'width': width,
|
|
'height': height
|
|
})
|
|
|
|
if not to_process:
|
|
print("\n✅ 所有图片尺寸都符合要求,无需压缩")
|
|
return
|
|
|
|
print(f"\n📋 发现 {len(to_process)} 张需要压缩的图片:\n")
|
|
|
|
for item in to_process:
|
|
print(f" {item['file'].name}: {item['width']}x{item['height']}")
|
|
|
|
# 确认
|
|
print(f"\n⚠️ 将备份原图到: {BACKUP_DIR}")
|
|
response = input("\n是否开始压缩? [y/N]: ").strip().lower()
|
|
|
|
if response != 'y':
|
|
print("\n❌ 已取消")
|
|
return
|
|
|
|
# 创建备份目录
|
|
BACKUP_DIR.mkdir(exist_ok=True)
|
|
|
|
# 处理图片
|
|
print("\n" + "=" * 60)
|
|
success_count = 0
|
|
|
|
for i, item in enumerate(to_process, 1):
|
|
file = item['file']
|
|
print(f"\n[{i}/{len(to_process)}] {file.name}")
|
|
print(f" 原尺寸: {item['width']}x{item['height']}")
|
|
|
|
# 备份原图
|
|
backup_path = BACKUP_DIR / file.name
|
|
try:
|
|
os.rename(file, backup_path)
|
|
except Exception as e:
|
|
print(f" ❌ 备份失败: {e}")
|
|
continue
|
|
|
|
# 压缩
|
|
if resize_image(backup_path, file):
|
|
new_width, new_height = get_image_size(file)
|
|
orig_size = backup_path.stat().st_size / 1024
|
|
new_size = file.stat().st_size / 1024
|
|
|
|
print(f" 新尺寸: {new_width}x{new_height}")
|
|
print(f" 大小: {orig_size:.1f}KB → {new_size:.1f}KB")
|
|
success_count += 1
|
|
else:
|
|
# 恢复备份
|
|
os.rename(backup_path, file)
|
|
print(f" ❌ 已恢复原图")
|
|
|
|
# 汇总
|
|
print("\n" + "=" * 60)
|
|
print(f"✅ 完成: {success_count}/{len(to_process)} 张图片已压缩")
|
|
print(f"📁 备份位置: {BACKUP_DIR}")
|
|
|
|
if success_count > 0:
|
|
print(f"\n💡 如需恢复,执行:")
|
|
print(f" cp {BACKUP_DIR}/* {SOURCE_DIR}/")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|