Video-Gen / modules /subtitles.py
jacky3102's picture
Update modules/subtitles.py
c11aa65 verified
Raw
History Blame Contribute Delete
2.98 kB
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
# ============================================================
# 字幕解析
# ============================================================
def parse_srt(srt_text: str):
segments = []
for block in srt_text.strip().split("\n\n"):
lines = block.strip().split("\n")
if len(lines) >= 3:
times = lines[1].split(" --> ")
segments.append((timestamp_to_seconds(times[0]), timestamp_to_seconds(times[1]), "\n".join(lines[2:])))
return segments
def timestamp_to_seconds(ts: str):
ts = ts.replace(",", ".")
h, m, s = ts.split(":")
return int(h) * 3600 + int(m) * 60 + float(s)
# ============================================================
# 字幕绘制(白字黑边,固定样式,无特效参数)
# ============================================================
def _draw_subtitle_lines(frame, text, font_path, video_w, video_h, font_size=None):
"""内部通用:白色文字 + 黑色描边,居中底部显示"""
if not text:
return frame
img_rgba = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)).convert("RGBA")
draw = ImageDraw.Draw(img_rgba)
if font_size is None or font_size <= 0:
font_size = max(18, min(video_w // 22, 40))
try:
font_obj = ImageFont.truetype(font_path, font_size) if font_path else ImageFont.load_default()
except:
font_obj = ImageFont.load_default()
# 自动换行
max_text_width = int(video_w * 0.85)
lines, current_line = [], ""
for char in text:
test_line = current_line + char
if draw.textbbox((0, 0), test_line, font=font_obj)[2] > max_text_width and current_line:
lines.append(current_line)
current_line = char
else:
current_line = test_line
if current_line:
lines.append(current_line)
line_height = font_size + 10
bottom_margin = int(video_h * 0.08)
y_start = video_h - bottom_margin - len(lines) * line_height
for i, line in enumerate(lines):
tw = draw.textbbox((0, 0), line, font=font_obj)[2]
tx = (video_w - tw) // 2
ty = y_start + i * line_height
# 黑色描边
draw.text((tx, ty), line, fill=(255, 255, 255, 255), font=font_obj,
stroke_width=2, stroke_fill=(0, 0, 0, 220))
return cv2.cvtColor(np.array(img_rgba.convert("RGB")), cv2.COLOR_RGB2BGR)
def draw_subtitle(frame, text, font_path, video_w, video_h,
font_size=None, **kwargs):
return _draw_subtitle_lines(frame, text, font_path, video_w, video_h, font_size)
def draw_typewriter_subtitle(frame, full_text, visible_chars, font_path, video_w, video_h,
font_size=None, **kwargs):
if not full_text or visible_chars <= 0:
return frame
return _draw_subtitle_lines(frame, full_text[:visible_chars], font_path, video_w, video_h, font_size)