fix(title): 标题/字幕字号按 video_width/720 等比缩放,修复成片标题比预览过小 #2023
Reference in New Issue
Block a user
Delete Branch "fix/title-fontsize-scaling"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
问题
用户反馈最终生成视频中标题字体明显小于模板预览/选择时的字号。
根因
前端
titleCanvas.ts已明确titleConfig.size的语义是「720p 基准宽度下的 px 字号」,按scale = videoWidth / 720缩放渲染到预览 Canvas;但后端三个渲染路径直接使用原始 size 值:packages/domain/ass_subtitle_builder.py(主 ASS 路径)packages/domain/video_filter_builder.py::build_title_drawtext_filter(drawtext 降级路径)apps/worker/video_processing/subtitle_generator.py::generate_ass_from_timeline(ASR 时间轴字幕)在 1080×1920 竖屏/1920×1080 横屏等非 720p 输出下,标题字号/描边/阴影/边距未随视频分辨率等比放大。
此外
subtitle_generator.py存在min(int(size), 36)的上限钳位,任何分辨率下标题字号都被强行压到 ≤36,进一步放大问题。修复
以 720p 为基准,按
video_width / 720等比缩放所有长度类参数:主 ASS 路径 (
ass_subtitle_builder.py)_scale_len(value, video_width):整数入返回 int,浮点入保留 float(支持 1.5 等细描边)_scale_cfg(cfg, defaults):先 setdefault 填 size 默认值(title=36、subtitle=24),再统一缩放size/font_size/margin_top/bg_padding/bg_radius/line_overrides[*].size;pos_x/pos_y为百分比(0-100) 不缩放drawtext 降级路径 (
video_filter_builder.py)_scale_title_len(value, output_width)font_size / border_width / shadowx / shadowy / top|bottom y-offset(50px)统一缩放ASR 字幕路径 (
subtitle_generator.py)_scale_lenmin(..., 36)上限钳位;stroke/shadow/margin 统一缩放不缩放的字段:颜色/字体/对齐/粗体/斜体等枚举/布尔;pos_x/pos_y 百分比;AI 数字人 WYSIWYG PNG overlay 路径(前端 Canvas 按 videoWidth 直接绘制,后端仅 overlay=0:0 叠加,无需后端缩放)。
测试
TestTitleFontsizeScaling/TestDrawtextFontsizeScaling共 16 个测试:720p 不变、1080p 1.5×、1920p 8/3×、描边宽/阴影偏移/边距/位置边距/line_overrides sizetest_subtitle_generator.py::test_720p_resolution中 PlayResX/Y 与 video_width/height 互换的断言笔误test_1970_musetalk_server.py两个 ffmpeg timeout/FileNotFound flaky,与本次改动无关,在 develop HEAD 上可复现),28 skipped影响面
所有带标题/字幕的视频生成任务,在 1080p/1080×1920/1920×1080/1920×1920/4K 分辨率下,标题和字幕字号、描边宽度、阴影偏移、边距会按 video_width/720 等比放大,效果与前端预览一致。720p 输出保持一字节不变。
🚀 预览环境已部署
## 问题 用户反馈最终生成视频中标题字体比模板预览/选择时看到的小很多。 前端 titleCanvas.ts 已明确 titleConfig.size 的语义是「720p 基准宽度下的 px 字号」, 按 scale = videoWidth/720 缩放渲染到预览 Canvas;但后端三个渲染路径 (ass_subtitle_builder / drawtext 降级 / subtitle_generator ASR)直接使用原始 size 值, 在 1080×1920 竖屏/1920×1080 横屏等非 720p 输出下,标题字号未随分辨率等比放大, 导致成片标题明显小于前端预览。 此外 apps/worker/video_processing/subtitle_generator.py 中存在 `min(int(title_cfg.get("size", 36)), 36)` 的上限钳位,任何分辨率下标题字号 都会被强行压到 ≤36,进一步放大了问题。 ## 修复 三个渲染路径统一以 720p 为基准,按 video_width/720 等比缩放所有长度类参数: - packages/domain/ass_subtitle_builder.py - 新增 _scale_len(value, video_width) 工具:整数输入返回 int,浮点输入保留 float - build_ass_content 内新增 _scale_cfg(cfg, defaults) 内部函数: 先 setdefault 填充 size 默认值(title=36、subtitle=24),再统一缩放 size/font_size、margin_top/bg_padding/bg_radius、line_overrides[*].size; pos_x/pos_y 是百分比(0-100)不缩放 - 描边宽(默认 2)、阴影 blur(默认 4)、阴影 offset_x/y(默认 2)在字段提取 处经 _scale_len 缩放,避免双重缩放 - TITLE_MARGIN_TOP/BOTTOM/SIDE 常量经 _scale_len 成局部 _margin_top/bottom/side - subtitle outline_width(1.0)经 _scale_len 缩放(保持 float 以支持 1.5 等小数) - packages/domain/video_filter_builder.py (build_title_drawtext_filter 降级路径) - 新增 _scale_title_len(value, output_width) 工具 - font_size、border_width(描边)、shadowx/shadowy(阴影偏移)、top/bottom 位置 y 偏移(50px)统一按 output_width/720 缩放 - apps/worker/video_processing/subtitle_generator.py (ASR 时间轴字幕路径) - 复用 ass_subtitle_builder._scale_len - subtitle: font_size 默认 24、outline_width 默认 1.5、margin_v/l/r 默认 60/40/40 全部按 video_width/720 缩放 - title: 移除 min(..., 36) 上限钳位;s_width/sh_blur/sh_offset、margin_top/side 统一缩放;_wrap_title_text 传入缩放后的 margin_l/r ## 不缩放的字段 颜色/字体/对齐/粗体/斜体等枚举/布尔值不缩放; pos_x/pos_y 为百分比(0-100)不缩放; AI 数字人 WYSIWYG PNG overlay 路径(build_title_overlay_filter)由前端 Canvas 按 videoWidth 直接绘制,后端只 overlay=0:0 叠加,无需后端缩放。 ## 测试 - 既有断言固定值的单测:将 video_width 改为 720(720p 基准下缩放比=1,断言值不变) - 新增 TestTitleFontsizeScaling / TestDrawtextFontsizeScaling 共 16 个测试用例: 720p 不变、1080p 1.5×、1920p 8/3×、描边宽/阴影偏移/边距/位置边距/逐行覆盖 size 等场景 - 修正 test_subtitle_generator.py::test_720p_resolution 中 PlayResX/Y 与 video_width/height 互换的断言错误 - 全量单测:15978 passed, 2 failed(均为 test_1970_musetalk_server.py 中 ffmpeg 超时/FileNotFound 的 flaky,与本次改动无关,在 develop HEAD 上复现) 28 skipped87468d78c5toc068a5c46e🗑️ 预览环境已清理
PR #2023 已关闭或合并,对应的预览环境已被清理。