From cfc7e4d32cf61c89700697406eea73e89c57ee7e Mon Sep 17 00:00:00 2001 From: hbrain Date: Mon, 25 May 2026 00:05:57 +0000 Subject: [PATCH] Support multiline captions --- README.md | 1 + movmaker.py | 33 +++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b00f97b..d29f2a2 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ Optional per-file captions are supported: ```text IMG_001.jpg: Eiffel Tower IMG_002.jpg: Louvre +IMG_003.jpg: First line | Second line ``` ## Usage diff --git a/movmaker.py b/movmaker.py index 15eee78..88e91cb 100755 --- a/movmaker.py +++ b/movmaker.py @@ -451,7 +451,7 @@ def build_video( filters.append(f"[{current}]copy[{title_label}]") caption_label = title_label - caption_size = subtitle_font_size if title_lines else max(40, height // 18) + caption_size = max(16, int((subtitle_font_size if title_lines else max(40, height // 18)) * 0.5)) for idx, caption in enumerate(captions): if not caption: continue @@ -474,19 +474,24 @@ def build_video( f"if(lt(t\\,{start + caption_fade:.3f})\\,(t-{start:.3f})/{caption_fade:.3f}\\," f"if(lt(t\\,{end - caption_fade:.3f})\\,1\\,({end:.3f}-t)/{caption_fade:.3f}))" ) if caption_fade > 0 else "1" - next_label = f"caption{idx}" - filters.append( - f"[{caption_label}]drawtext=fontfile='{stamp_bold_font}':text='{drawtext_escape(caption)}':x=(w-text_w)/2:y=h-text_h-62:" - f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:" - f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{next_label}]" - ) - bold_label = f"caption{idx}b" - filters.append( - f"[{next_label}]drawtext=fontfile='{stamp_bold_font}':text='{drawtext_escape(caption)}':x=(w-text_w)/2+1:y=h-text_h-62:" - f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:" - f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{bold_label}]" - ) - caption_label = bold_label + caption_lines = [line.strip() for line in caption.split("|") if line.strip()] + line_gap = int(caption_size * 1.2) + block_height = line_gap * (len(caption_lines) - 1) + for line_idx, caption_line in enumerate(caption_lines): + y_expr = f"h-text_h-62-{block_height - line_idx * line_gap}" + next_label = f"caption{idx}_{line_idx}" + filters.append( + f"[{caption_label}]drawtext=fontfile='{stamp_bold_font}':text='{drawtext_escape(caption_line)}':x=(w-text_w)/2:y={y_expr}:" + f"fontsize={caption_size}:fontcolor=white:borderw=0:shadowcolor=black@0.75:shadowx=2:shadowy=2:" + f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{next_label}]" + ) + bold_label = f"caption{idx}_{line_idx}b" + filters.append( + f"[{next_label}]drawtext=fontfile='{stamp_bold_font}':text='{drawtext_escape(caption_line)}':x=(w-text_w)/2+1:y={y_expr}:" + f"fontsize={caption_size}:fontcolor=white:borderw=0:shadowcolor=black@0.75:shadowx=2:shadowy=2:" + f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{bold_label}]" + ) + caption_label = bold_label stamp_size = max(14, height // 65) stamp_lines = [x for x in [data.title, data.date, data.place] if x]