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
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""自动压缩图片,无需交互"""
import os
import subprocess
from pathlib import Path
MAX_WIDTH = 2180
SOURCE_DIR = Path('/home/ubuntu/images')
BACKUP_DIR = SOURCE_DIR / 'original_backup'
def get_size(f):
try:
r = subprocess.run(['identify', '-format', '%w %h', str(f)], capture_output=True, text=True)
return map(int, r.stdout.strip().split())
except:
return None, None
def resize(f, out):
try:
cmd = ['convert', str(f), '-resize', f'{MAX_WIDTH}x>', '-quality', '90', str(out)]
subprocess.run(cmd, check=True, capture_output=True)
return True
except Exception as e:
print(f" 失败: {e}")
return False
# 创建备份目录
BACKUP_DIR.mkdir(exist_ok=True)
exts = {'.jpg', '.jpeg', '.png', '.webp'}
images = []
for f in SOURCE_DIR.iterdir():
if f.is_file() and f.suffix.lower() in exts:
w, h = get_size(f)
if w and w > MAX_WIDTH:
images.append({'file': f, 'w': w, 'h': h})
print(f"压缩 {len(images)} 张图片...\n")
success = 0
for i, item in enumerate(images, 1):
f = item['file']
print(f"[{i}/{len(images)}] {f.name}")
# 备份
backup = BACKUP_DIR / f.name
os.rename(f, backup)
# 压缩
if resize(backup, f):
nw, nh = get_size(f)
orig_kb = backup.stat().st_size / 1024
new_kb = f.stat().st_size / 1024
print(f" {item['w']}x{item['h']} → {nw}x{nh}")
print(f" {orig_kb:.1f}KB → {new_kb:.1f}KB\n")
success += 1
else:
os.rename(backup, f)
print(f"✅ 完成: {success}/{len(images)} 张")
print(f"📁 备份: {BACKUP_DIR}")
+132
View File
@@ -0,0 +1,132 @@
#!/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()
+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()