141 lines
5.1 KiB
Python
141 lines
5.1 KiB
Python
# -*- coding: utf-8 -*-
|
||
|
||
import os
|
||
import re
|
||
import sys
|
||
import subprocess
|
||
import shutil
|
||
import tempfile
|
||
import zipfile
|
||
|
||
# --- 配置区 ---
|
||
IMAGE_EXTENSIONS = ('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.tiff')
|
||
# --- 配置区结束 ---
|
||
|
||
def check_ffmpeg():
|
||
"""检查系统中是否安装了 ffmpeg"""
|
||
if shutil.which("ffmpeg") is None:
|
||
print("错误:找不到 ffmpeg。")
|
||
print("请确保你已经安装了 ffmpeg,并将其添加到了系统的 PATH 环境变量中。")
|
||
print("安装指南: https://ffmpeg.org/download.html")
|
||
return False
|
||
return True
|
||
|
||
def extract_number_from_filename(filename):
|
||
"""从文件名中提取最后一个遇到的数字序列用于排序。"""
|
||
numbers = re.findall(r'\d+', filename)
|
||
if numbers:
|
||
return int(numbers[-1])
|
||
print(f"警告:文件名 '{filename}' 中未找到数字,将按0进行排序。")
|
||
return 0
|
||
|
||
def main():
|
||
"""主执行函数"""
|
||
print("--- 图片序列转 WebP 并压缩为 ZIP 脚本 (支持自定义起始编号) ---")
|
||
|
||
# 1. 检查命令行参数 (现在支持3个或4个参数)
|
||
if not (3 <= len(sys.argv) <= 4):
|
||
print("\n使用方法:")
|
||
print(f" python {sys.argv[0]} <源图片文件夹> <输出的ZIP文件名> [<起始编号>]")
|
||
print("\n示例 (从0开始):")
|
||
print(f" python {sys.argv[0]} ./my_images my_archive.zip")
|
||
print("\n示例 (从40开始):")
|
||
print(f" python {sys.argv[0]} ./my_images my_archive.zip 40")
|
||
sys.exit(1)
|
||
|
||
source_dir = sys.argv[1]
|
||
output_zip_name = sys.argv[2]
|
||
|
||
# 初始化起始编号为默认值 0
|
||
start_index = 0
|
||
|
||
# 如果提供了第三个参数,则用它作为起始编号
|
||
if len(sys.argv) == 4:
|
||
try:
|
||
start_index = int(sys.argv[3])
|
||
if start_index < 0:
|
||
print("错误:起始编号不能为负数。")
|
||
sys.exit(1)
|
||
except ValueError:
|
||
print(f"错误:提供的起始编号 '{sys.argv[3]}' 不是一个有效的整数。")
|
||
sys.exit(1)
|
||
|
||
if not output_zip_name.lower().endswith('.zip'):
|
||
output_zip_name += '.zip'
|
||
|
||
# 2. 验证输入
|
||
if not check_ffmpeg():
|
||
sys.exit(1)
|
||
|
||
if not os.path.isdir(source_dir):
|
||
print(f"错误:源文件夹 '{source_dir}' 不存在或不是一个目录。")
|
||
sys.exit(1)
|
||
|
||
# 3. 查找并排序图片文件
|
||
print(f"\n[1/5] 正在扫描文件夹: {source_dir}")
|
||
try:
|
||
all_files = os.listdir(source_dir)
|
||
image_files = [f for f in all_files if f.lower().endswith(IMAGE_EXTENSIONS)]
|
||
except OSError as e:
|
||
print(f"错误:无法读取文件夹 '{source_dir}': {e}")
|
||
sys.exit(1)
|
||
|
||
if not image_files:
|
||
print("指定的文件夹中未找到任何支持的图片文件。")
|
||
sys.exit(0)
|
||
|
||
sorted_images = sorted(image_files, key=extract_number_from_filename)
|
||
|
||
print("找到并排序后的图片文件:")
|
||
for img in sorted_images:
|
||
print(f" - {img}")
|
||
|
||
# 使用临时目录来存放生成的 webp 文件
|
||
with tempfile.TemporaryDirectory() as temp_dir:
|
||
print(f"\n[2/5] 开始转换图片 (起始编号: {start_index})...")
|
||
total_files = len(sorted_images)
|
||
|
||
# 4. 依次使用 ffmpeg 进行编码
|
||
for index, image_name in enumerate(sorted_images):
|
||
# 计算最终的输出文件名编号
|
||
output_number = start_index + index
|
||
output_filename = f"{output_number}.webp"
|
||
|
||
input_path = os.path.join(source_dir, image_name)
|
||
output_path = os.path.join(temp_dir, output_filename)
|
||
|
||
command = ["ffmpeg", "-i", input_path, "-y", output_path]
|
||
|
||
print(f" [{index + 1}/{total_files}] 正在转换: {image_name} -> {output_filename}")
|
||
|
||
try:
|
||
subprocess.run(
|
||
command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8'
|
||
)
|
||
except subprocess.CalledProcessError as e:
|
||
print(f" 错误: 转换 '{image_name}' 时失败。\n FFmpeg 错误信息:\n{e.stderr}")
|
||
except Exception as e:
|
||
print(f" 发生未知错误: {e}")
|
||
|
||
# 5. 将临时目录中的 WebP 文件压缩成 ZIP
|
||
print(f"\n[3/5] 正在将 WebP 文件压缩到: {output_zip_name}")
|
||
|
||
try:
|
||
with zipfile.ZipFile(output_zip_name, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||
webp_files_to_zip = sorted(os.listdir(temp_dir), key=lambda f: int(f.split('.')[0]))
|
||
|
||
for webp_file in webp_files_to_zip:
|
||
file_path_in_temp = os.path.join(temp_dir, webp_file)
|
||
zipf.write(file_path_in_temp, arcname=webp_file)
|
||
print(f" - 已添加 {webp_file} 到 ZIP 包")
|
||
|
||
except Exception as e:
|
||
print(f"错误:创建 ZIP 文件时失败: {e}")
|
||
sys.exit(1)
|
||
|
||
print("\n[4/5] 临时文件已自动清理。")
|
||
print(f"\n[5/5] --- 所有任务完成!输出文件已保存为 '{output_zip_name}' ---")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |