-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpie_timer.py
More file actions
107 lines (89 loc) · 3.62 KB
/
Copy pathpie_timer.py
File metadata and controls
107 lines (89 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import os, math, shutil, argparse
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
import imageio_ffmpeg as ffmpeg
from tqdm import tqdm
# 解析尺寸参数 (格式: WxH)
def parse_size(size_str):
try:
width, height = map(int, size_str.split('x'))
return (width, height)
except ValueError:
raise argparse.ArgumentTypeError("尺寸格式必须为 WxH,例如 1024x768")
# 解析颜色参数 (格式: R,G,B)
def parse_color(color_str):
try:
r, g, b = map(int, color_str.split(','))
if all(0 <= x <= 255 for x in (r, g, b)):
return (r, g, b)
raise ValueError("颜色值必须在0-255之间")
except ValueError:
raise argparse.ArgumentTypeError("颜色格式必须为 R,G,B,例如 255,0,0")
# ----------------- 参数区 -----------------
TOTAL_MIN = 1 # 倒计时分钟
FPS = 24 # 帧率
SIZE = (1024,1024) # 画布分辨率
PIE_COLOR = (255,255,255) # 饼图颜色
REVERSE = False # 是否反向倒计时 (从100%到0%)
# ----------------------------------------
TOTAL_SEC = TOTAL_MIN * 60
TOTAL_FRAMES = TOTAL_SEC * FPS
RADIUS = SIZE[0] // 2 - 40
CENTER = (SIZE[0] // 2, SIZE[1] // 2)
TMP_DIR = Path("frames")
TMP_DIR.mkdir(exist_ok=True)
def make_frame(n: int):
"""生成第 n 帧图片"""
# 始终使用 RGBA 模式,背景完全透明
img = Image.new("RGBA", SIZE, (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
percent = n / TOTAL_FRAMES
if REVERSE:
angle = (1 - percent) * 360 # 反向倒计时
else:
angle = percent * 360 # 正向倒计时
# 只画饼图扇形,背景透明
if angle > 0:
draw.pieslice([CENTER[0]-RADIUS, CENTER[1]-RADIUS,
CENTER[0]+RADIUS, CENTER[1]+RADIUS],
-90, -90 + angle,
fill=PIE_COLOR + (255,))
img.save(TMP_DIR / f"{n:06d}.png")
def main():
print("🥧 开始生成帧序列...")
for i in tqdm(range(TOTAL_FRAMES), ncols=80):
make_frame(i)
print("🎞 正在合成 MOV 视频...")
ffmpeg_path = ffmpeg.get_ffmpeg_exe()
pattern = str(TMP_DIR / "%06d.png")
# 始终使用 ProRes 4444 编码,输出 MOV 格式
cmd = [
ffmpeg_path,
"-y", "-framerate", str(FPS), "-i", pattern,
"-c:v", "prores_ks", "-profile:v", "4444", "-pix_fmt", "yuva444p10le",
OUT_FILE
]
os.system(" ".join(cmd))
# 可选:清理临时帧
shutil.rmtree(TMP_DIR)
print(f"✅ 完成:{OUT_FILE}")
if __name__ == "__main__":
# 解析命令行参数
parser = argparse.ArgumentParser(description='圆饼计时器生成器')
parser.add_argument('-m', '--minutes', type=int, default=TOTAL_MIN, help='倒计时分钟数 (默认: 1)')
parser.add_argument('-f', '--fps', type=int, default=FPS, help='帧率 (默认: 24)')
parser.add_argument('-s', '--size', type=parse_size, default=SIZE, help='画布尺寸,格式 WxH (默认: 1024x1024)')
parser.add_argument('-p', '--pie-color', type=parse_color, default=PIE_COLOR, help='饼图颜色,格式 R,G,B (默认: 255,255,255)')
parser.add_argument('-r', '--reverse', action='store_true', help='启用反向倒计时 (从100%到0%)')
args = parser.parse_args()
# 更新参数
TOTAL_MIN = args.minutes
FPS = args.fps
SIZE = args.size
PIE_COLOR = args.pie_color
REVERSE = args.reverse
TOTAL_SEC = TOTAL_MIN * 60
TOTAL_FRAMES = TOTAL_SEC * FPS
# 始终输出 MOV 格式
OUT_FILE = f"pietimer_{TOTAL_MIN}min_{SIZE[0]}x{SIZE[1]}{'_reverse' if REVERSE else ''}.mov"
main()