Skip to content

Instantly share code, notes, and snippets.

@Zayrick
Created December 26, 2025 03:32
Show Gist options
  • Select an option

  • Save Zayrick/9a5c3c7cca78561aa800c47dd5ef9f93 to your computer and use it in GitHub Desktop.

Select an option

Save Zayrick/9a5c3c7cca78561aa800c47dd5ef9f93 to your computer and use it in GitHub Desktop.
批量将 webm 目录下的 VP9 透明通道视频文件并行转换为保留透明度的 GIF 动图。
#!/usr/bin/env python3
"""
批量将 webm 目录下的所有 .webm 文件转换为带透明通道的 .gif
使用 libvpx-vp9 解码器正确读取 VP9 alpha 通道
使用 palettegen/paletteuse 保留透明度
禁用 GIF offsetting 和 transdiff 避免白色活动矩形
准备工作:
---------
1. Python 依赖:
本脚本仅使用 Python 标准库,无需安装额外 pip 包
2. FFmpeg 安装 (必需):
- Windows:
方法一: 使用 winget (推荐)
winget install FFmpeg
方法二: 使用 scoop
scoop install ffmpeg
方法三: 手动下载
从 https://www.gyan.dev/ffmpeg/builds/ 下载
解压后将 bin 目录添加到系统 PATH
- macOS:
brew install ffmpeg
- Linux (Ubuntu/Debian):
sudo apt update && sudo apt install ffmpeg
安装后验证: ffmpeg -version
3. 目录结构:
脚本同级目录下需要:
- webm/ 存放待转换的 .webm 文件
- gif/ 输出目录 (自动创建)
"""
import subprocess
import sys
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
def convert_webm_to_gif(webm_path: Path, output_dir: Path) -> tuple[Path, bool, str]:
"""
将单个 webm 文件转换为透明 gif
返回: (文件路径, 是否成功, 消息)
"""
gif_name = webm_path.stem + ".gif"
gif_path = output_dir / gif_name
cmd = [
"ffmpeg",
"-y", # 覆盖输出
"-c:v", "libvpx-vp9", # 使用 libvpx 解码器以正确读取 alpha
"-i", str(webm_path),
"-an", # 无音频
"-filter_complex",
"[0:v]format=rgba,split[v][p];"
"[p]palettegen=reserve_transparent=1:stats_mode=diff[pal];"
"[v][pal]paletteuse=alpha_threshold=128:dither=sierra2_4a",
"-gifflags", "-offsetting", # 禁用帧偏移(避免白色矩形)
"-gifflags", "-transdiff", # 禁用帧间透明差异优化
"-loop", "0", # 无限循环
str(gif_path),
]
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=120,
)
if result.returncode == 0:
return (webm_path, True, f"✓ {webm_path.name} -> {gif_name}")
else:
return (webm_path, False, f"✗ {webm_path.name}: {result.stderr[:200]}")
except subprocess.TimeoutExpired:
return (webm_path, False, f"✗ {webm_path.name}: 超时")
except Exception as e:
return (webm_path, False, f"✗ {webm_path.name}: {e}")
def main():
script_dir = Path(__file__).parent
webm_dir = script_dir / "webm"
output_dir = script_dir / "gif"
# 确保输出目录存在
output_dir.mkdir(exist_ok=True)
# 获取所有 webm 文件
webm_files = sorted(webm_dir.glob("*.webm"))
total = len(webm_files)
if total == 0:
print("没有找到 .webm 文件")
sys.exit(1)
print(f"找到 {total} 个 webm 文件,开始转换...")
print(f"输出目录: {output_dir.absolute()}\n")
success_count = 0
fail_count = 0
# 使用线程池并行转换(ffmpeg 主要是 I/O 和外部进程,线程池足够)
max_workers = 4 # 控制并发数量,避免资源耗尽
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(convert_webm_to_gif, f, output_dir): f
for f in webm_files
}
for i, future in enumerate(as_completed(futures), 1):
webm_path, success, msg = future.result()
print(f"[{i}/{total}] {msg}")
if success:
success_count += 1
else:
fail_count += 1
print(f"\n转换完成: {success_count} 成功, {fail_count} 失败")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment