This commit is contained in:
Ubuntu
2026-07-03 16:58:28 +08:00
commit 32b43f85bd
6240 changed files with 1987678 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
#!/usr/bin/env python3
"""
图片尺寸处理工具 - 固定宽度,智能高度
目标尺寸: 宽1620px,高≤2880px(9:16比例)
处理逻辑:
1. 先按宽度1620px等比例压缩
2. 压缩后高度>2880px: 从中间裁剪多余部分
3. 压缩后高度<2880px: 保持实际高度
"""
import os
import sys
import subprocess
from pathlib import Path
# 配置
TARGET_WIDTH = 1620
MAX_HEIGHT = 2880
SOURCE_DIR = Path('/home/ubuntu/images')
OUTPUT_DIR = SOURCE_DIR / 'resized_output'
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 Exception as e:
print(f" ❌ 无法获取图片尺寸: {e}")
return None, None
def process_image(input_path, output_path):
"""
处理图片:
1. 先按宽度1620px等比例压缩
2. 如果高度>2880,从中间裁剪
3. 如果高度<2880,保持原样
"""
try:
# 第一步: 按宽度1620px等比例压缩
# 使用 ^ 表示最小尺寸,确保宽度至少1620,然后裁剪
temp_path = str(output_path) + '.tmp.jpg'
cmd_resize = [
'convert', str(input_path),
'-resize', f'{TARGET_WIDTH}x', # 宽度固定1620,高度自适应
'-quality', '95',
temp_path
]
subprocess.run(cmd_resize, check=True, capture_output=True)
# 获取压缩后的尺寸
new_width, new_height = get_image_size(temp_path)
if not new_width:
os.remove(temp_path)
return False, "无法获取压缩后尺寸"
print(f" 等比压缩后: {new_width}x{new_height}")
# 第二步: 处理高度
if new_height > MAX_HEIGHT:
# 高度超过2880,从中间裁剪
offset_y = (new_height - MAX_HEIGHT) // 2
cmd_crop = [
'convert', temp_path,
'-crop', f'{TARGET_WIDTH}x{MAX_HEIGHT}+0+{offset_y}',
'+repage', # 重置页面信息
'-quality', '95',
str(output_path)
]
subprocess.run(cmd_crop, check=True, capture_output=True)
final_height = MAX_HEIGHT
action = f"居中裁剪至{MAX_HEIGHT}px"
else:
# 高度小于等于2880,保持原样,只复制
os.rename(temp_path, output_path)
final_height = new_height
action = f"保持实际高度{new_height}px"
# 清理临时文件
if os.path.exists(temp_path):
os.remove(temp_path)
return True, action
except Exception as e:
print(f" ❌ 处理失败: {e}")
return False, str(e)
def format_size(size_bytes):
"""格式化文件大小"""
if size_bytes < 1024:
return f"{size_bytes}B"
elif size_bytes < 1024 * 1024:
return f"{size_bytes/1024:.1f}KB"
else:
return f"{size_bytes/(1024*1024):.1f}MB"
def main():
print("=" * 70)
print(f"🖼️ 图片尺寸处理工具")
print(f" 目标宽度: {TARGET_WIDTH}px")
print(f" 最大高度: {MAX_HEIGHT}px (超出则居中裁剪)")
print(f" 输出目录: {OUTPUT_DIR}")
print("=" * 70)
# 检查ImageMagick
try:
subprocess.run(['identify', '--version'], capture_output=True, check=True)
except:
print("❌ 错误: 未安装 ImageMagick")
print(" 请安装: sudo apt install imagemagick")
sys.exit(1)
if not SOURCE_DIR.exists():
print(f"❌ 目录不存在: {SOURCE_DIR}")
sys.exit(1)
# 创建输出目录
OUTPUT_DIR.mkdir(exist_ok=True)
# 支持的图片格式
extensions = {'.jpg', '.jpeg', '.png', '.webp', '.gif', '.bmp', '.tiff'}
# 收集需要处理的图片
to_process = []
for file in SOURCE_DIR.iterdir():
if file.is_file() and file.suffix.lower() in extensions:
# 跳过输出目录和备份目录
if file.parent.name in ['resized_output', 'original_backup']:
continue
width, height = get_image_size(file)
if width:
to_process.append({
'file': file,
'orig_width': width,
'orig_height': height
})
if not to_process:
print(f"\n❌ 未找到需要处理的图片")
return
print(f"\n📋 找到 {len(to_process)} 张图片:\n")
for item in to_process:
ratio = item['orig_width'] / item['orig_height']
estimated_height = int(TARGET_WIDTH / ratio)
action = "需裁剪" if estimated_height > MAX_HEIGHT else "保持"
print(f" {item['file'].name}: {item['orig_width']}x{item['orig_height']} → {TARGET_WIDTH}x{estimated_height} ({action})")
# 确认
response = input(f"\n是否开始处理? [y/N]: ").strip().lower()
if response != 'y':
print("\n❌ 已取消")
return
# 处理图片
print("\n" + "=" * 70)
success_count = 0
for i, item in enumerate(to_process, 1):
file = item['file']
output_path = OUTPUT_DIR / f"{file.stem}_1620x{MAX_HEIGHT}{file.suffix}"
print(f"\n[{i}/{len(to_process)}] {file.name}")
print(f" 原图: {item['orig_width']}x{item['orig_height']}")
# 处理
success, action = process_image(file, output_path)
if success:
final_width, final_height = get_image_size(output_path)
orig_size = file.stat().st_size
new_size = output_path.stat().st_size
print(f" 结果: {final_width}x{final_height}")
print(f" 动作: {action}")
print(f" 大小: {format_size(orig_size)} → {format_size(new_size)}")
print(f" 保存: {output_path.name}")
success_count += 1
else:
print(f" ❌ 失败: {action}")
# 汇总
print("\n" + "=" * 70)
print(f"✅ 完成: {success_count}/{len(to_process)} 张图片已处理")
print(f"📁 输出目录: {OUTPUT_DIR}")
if success_count > 0:
print(f"\n💡 提示:")
print(f" - 处理后的图片在: {OUTPUT_DIR}/")
print(f" - 原图未改动,保留在: {SOURCE_DIR}/")
print(f" - 文件名格式: 原名_1620x2880.扩展名")
if __name__ == '__main__':
main()