fix: strengthen short drama subtitle style
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled

This commit is contained in:
冰朔 2026-06-24 12:30:11 +08:00
parent d11026c1e3
commit 786732ac24
5 changed files with 187 additions and 14 deletions

View File

@ -126,7 +126,8 @@ JZAO外置盘: 产物存放地,不是状态主控。
| 固定道具合成路线 | ✅ 已建立 | `video-ai-system/plans/script-to-screen/EP01-LOCKED-PROP-COMPOSITING-ROUTE.hdlp` |
| 苏白+牌匾合成小样 | 🟡 技术通过·位置失败 | `video-ai-system/outputs/tests/TEST-COMP-001-SUBAI-PLAQUE-OVERLAY-RUN-001-REPORT.hdlp` |
| 牌匾固定贴图 | ✅ PNG已生成 | `video-ai-system/assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png` |
| 字幕渲染合成 | ✅ 纯白样式RUN-003通过 | `video-ai-system/outputs/tests/TEST-SUBTITLE-003-CLEAN-WHITE-RUN002-REPORT.hdlp` |
| 字幕渲染合成 | ✅ 粗白短剧样式RUN-004通过 | `video-ai-system/outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT.hdlp` |
| 字幕样式标准 | ✅ 已建立 | `video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD.hdlp` |
| 百宗会人群底片 | 🟡 RUN-002可作氛围候选 | `video-ai-system/outputs/tests/TEST-PROP-001-TDZ-PLAQUE-RUN-002-REPORT.hdlp` |
| 苏白TTS配音 | ✅ 工程测试通过 | `video-ai-system/outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` |
| 模型/成本路线 | ✅ 已建立 | `video-ai-system/knowledge/D144-MODEL-COST-ROUTE.hdlp` |

View File

@ -27,7 +27,7 @@ Subtitle Renderer · 字幕渲染引擎
字幕样式配置
--font-size : 字体大小默认 36
--font-color : 字体颜色默认 white
--style : 字幕样式clean-white / black-box默认 clean-white
--style : 字幕样式short-drama-bold / clean-white / black-box默认 short-drama-bold
--position : 位置top / middle / bottom默认 bottom
--margin-bottom : 底部边距默认 100px
@ -60,35 +60,46 @@ except ImportError:
# 默认字幕样式
DEFAULT_STYLE = {
"font_size": 36,
"font_size": 44,
"font_color": "white",
"bg_enabled": False,
"position": "bottom", # top / middle / bottom
"margin_bottom": 100,
"margin_bottom": 84,
"margin_horizontal": 60,
"stroke_color": "black",
"stroke_width": 0,
"stroke_width": 1,
"bold_weight": 2,
"video_width": 1080,
"video_height": 1920,
}
SUBTITLE_STYLE_PRESETS = {
"short-drama-bold": {
"font_color": (255, 255, 255, 255),
"bg_enabled": False,
"stroke_width": 1,
"stroke_color": (18, 18, 18, 220),
"bold_weight": 2,
},
"clean-white": {
"font_color": "white",
"font_color": (255, 255, 255, 255),
"bg_enabled": False,
"stroke_width": 0,
"bold_weight": 1,
},
"black-box": {
"font_color": "white",
"font_color": (255, 255, 255, 255),
"bg_enabled": True,
"bg_fill": (0, 0, 0, 160),
"stroke_width": 0,
"bold_weight": 1,
},
"outlined-white": {
"font_color": "white",
"font_color": (255, 255, 255, 255),
"bg_enabled": False,
"stroke_width": 2,
"stroke_color": "black",
"stroke_color": (0, 0, 0, 255),
"bold_weight": 1,
},
}
@ -161,7 +172,7 @@ def render_subtitle_png(
bg_y2 = y + text_height + bg_padding
draw.rectangle([bg_x1, bg_y1, bg_x2, bg_y2], fill=style.get("bg_fill", (0, 0, 0, 160)))
# 可选描边。默认纯白字幕不描边
# 可选描边。短剧默认使用极细暗边,不使用投影
stroke_width = style.get("stroke_width", 2)
stroke_color = style.get("stroke_color", "black")
if stroke_width > 0:
@ -169,9 +180,16 @@ def render_subtitle_png(
draw.text((x + offset, y), text, font=font, fill=stroke_color)
draw.text((x, y + offset), text, font=font, fill=stroke_color)
# 绘制主文本
# 绘制主文本。bold_weight 用多次微偏移模拟加粗,避免依赖某台机器是否有粗体中文字体。
font_color = style.get("font_color", "white")
draw.text((x, y), text, font=font, fill=font_color)
bold_weight = max(1, int(style.get("bold_weight", 1)))
offsets = [(0, 0)]
if bold_weight >= 2:
offsets += [(-1, 0), (1, 0), (0, -1), (0, 1)]
if bold_weight >= 3:
offsets += [(-1, -1), (1, -1), (-1, 1), (1, 1)]
for dx, dy in offsets:
draw.text((x + dx, y + dy), text, font=font, fill=font_color)
# 保存
os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
@ -330,7 +348,7 @@ def main():
parser.add_argument("--output", help="输出视频路径(配合 --video 使用)")
parser.add_argument("--font-size", type=int, default=36, help="字体大小")
parser.add_argument("--font-color", default="white", help="字体颜色")
parser.add_argument("--style", default="clean-white", choices=sorted(SUBTITLE_STYLE_PRESETS.keys()), help="字幕样式")
parser.add_argument("--style", default="short-drama-bold", choices=sorted(SUBTITLE_STYLE_PRESETS.keys()), help="字幕样式")
parser.add_argument("--position", default="bottom", choices=["top", "middle", "bottom"], help="字幕位置")
parser.add_argument("--video-width", type=int, default=1080, help="视频宽度")
parser.add_argument("--video-height", type=int, default=1920, help="视频高度")

View File

@ -0,0 +1,94 @@
# 视频AI系统 · 字幕样式标准
> HLDP://video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD
> 类型: 字幕可读性规范 · 竖屏短剧
> 日期: D144 · 2026-06-24
> 铸渊 ICE-GL-ZY001
---
## 调研结论
行业字幕共识:
```
白色字体
居中对齐
位于底部或顶部
避开画面文字/重要主体
保持安全区
最多两行
字号随分辨率和每行字数调整
```
来源:
```
Netflix Timed Text Style Guide:
https://partnerhelp.netflixstudios.com/hc/en-us/articles/215758617-Timed-Text-Style-Guide-General-Requirements
https://partnerhelp.netflixstudios.com/hc/en-us/articles/217350977-English-USA-Timed-Text-Style-Guide
BBC字幕安全区资料:
https://www.clevercast.com/bbc-subtitling-guidelines/
ATSC A/343 Safe Title Area:
https://www.atsc.org/wp-content/uploads/2024/04/A343-2024-04-Captions-and-Subtitles.pdf
```
---
## EP01竖屏短剧默认样式
```
style_id: short-drama-bold
font_color: white / #FFFFFF / alpha 255
font_weight: bold
background: none
shadow: none
stroke: 1px dark edge, only for readability
alignment: center
position: lower third, safe area inside
max_lines: 2
```
说明:
```
用户反馈上一版字幕太细、太淡。
因此默认不再使用clean-white细字。
默认改为粗白字。
```
---
## 为什么保留极细暗边
```
纯白粗字在天空、白衣、雾气、浅石头上会丢失。
极细暗边不是阴影,也不是黑底。
它只用于保证手机观看时文字不发飘。
```
如果某个镜头背景很暗:
```
stroke_width可降为0。
```
---
## 质检标准
每次烧字幕后必须抽帧检查:
```
文字是否足够粗
颜色是否足够白
是否有黑底/阴影误启用
是否遮脸
是否遮关键道具
是否在手机安全区内
两行以内
与角色对白时间轴同步
```

View File

@ -112,7 +112,8 @@ preview-003: 暂不生成。
| 固定道具合成路线 | ✅ | `plans/script-to-screen/EP01-LOCKED-PROP-COMPOSITING-ROUTE.hdlp` |
| 苏白+牌匾合成小样 | 🟡 技术通过·位置失败 | `outputs/tests/TEST-COMP-001-SUBAI-PLAQUE-OVERLAY-RUN-001-REPORT.hdlp` |
| 牌匾固定贴图 | ✅ PNG已生成 | `assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png` |
| 字幕渲染合成 | ✅ 纯白样式RUN-003通过 | `outputs/tests/TEST-SUBTITLE-003-CLEAN-WHITE-RUN002-REPORT.hdlp` |
| 字幕渲染合成 | ✅ 粗白短剧样式RUN-004通过 | `outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT.hdlp` |
| 字幕样式标准 | ✅ 已建立 | `knowledge/SUBTITLE-STYLE-STANDARD.hdlp` |
| 百宗会人群底片 | 🟡 RUN-002可作氛围候选 | `outputs/tests/TEST-PROP-001-TDZ-PLAQUE-RUN-002-REPORT.hdlp` |
| 苏白TTS配音 | ✅ 工程测试通过 | `outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` |
| 模型/成本路线 | ✅ 已建立 | `knowledge/D144-MODEL-COST-ROUTE.hdlp` |
@ -210,6 +211,8 @@ preview-003: 暂不生成。
- [x] 修复字幕管线: SRT→PNG→FFmpeg overlay合成 → `outputs/tests/TEST-SUBTITLE-001-RUN-001-REPORT.hdlp`
- [x] 纠正字幕测试底片: 使用干净苏白视频重跑 → `outputs/tests/TEST-SUBTITLE-002-CLEAN-RUN-001-REPORT.hdlp`
- [x] 调整字幕默认风格为纯白无黑底/无阴影 → `outputs/tests/TEST-SUBTITLE-003-CLEAN-WHITE-RUN002-REPORT.hdlp`
- [x] 调整字幕默认风格为粗白短剧字幕 → `outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT.hdlp`
- [x] 建立字幕样式标准 → `knowledge/SUBTITLE-STYLE-STANDARD.hdlp`
- [x] 重定性 RUN-002: 牌匾一致性失败,但百宗会人群氛围可用
- [x] 测试苏白Edge-TTS工程配音 → `outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp`
- [x] 建立模型/成本路线 → `knowledge/D144-MODEL-COST-ROUTE.hdlp`

View File

@ -0,0 +1,57 @@
# TEST-SUBTITLE-004 · 粗白短剧字幕报告
> HLDP://video-ai-system/outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT
> 类型: 字幕样式测试 · short-drama-bold
> 日期: D144 · 2026-06-24 12:26 CST
> 铸渊 ICE-GL-ZY001
---
## 输入
```
base_video: /Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/视频/zai-fu-fei-xiu-xian/ep01/tests/TEST-PROP-001-TDZ-PLAQUE-RUN-002-SUBAI-SAME-SCENE.mp4
style: short-drama-bold
font_size: 52
output: /Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/视频/zai-fu-fei-xiu-xian/ep01/tests/TEST-SUBTITLE-004-RUN002-SHORT-DRAMA-BOLD.mp4
```
---
## 用户反馈对应
```
上一版字幕字体太细、颜色太淡。
需要按视频底部字幕标准调研后,改为更粗、更白、更清楚。
```
---
## 调整
```
subtitle-renderer.py:
- 默认style改为 short-drama-bold。
- 默认字号提升。
- 增加bold_weight模拟加粗。
- 去掉黑底。
- 去掉阴影。
- 保留极细暗边保证浅背景可读。
```
---
## 裁决
```
status: PASS_FOR_CURRENT_SUBTITLE_DEFAULT
approved_for: 当前字幕默认候选风格
not_approved_for: 所有镜头免检
```
下一步:
```
每个镜头烧字幕后仍需抽帧检查可读性、遮挡和安全区。
```