fix: 标题换行计算使用原始font_size,与CSS预览一致 #1519

Merged
auto-approve-bot merged 1 commits from fix/title-wrap-fontsize-consistency into develop 2026-08-27 12:46:01 +08:00
2 changed files with 45 additions and 3 deletions
+3 -3
View File
@@ -224,8 +224,8 @@ def _wrap_title_text(
if available_width <= 0:
return text
# 换行宽度必须与实际渲染(补偿后的 ASS Fontsize)一致,否则换行位置会错位
ass_font_size = _compensate_ass_fontsize(font_size)
# 换行计算使用原始 font_size,与 CSS 预览一致;1.35x 补偿仅用于 ASS Fontsize 渲染
# 先按已有 \N 分段,每段独立自动换行,最后用 \N 拼回
segments = text.split("\\N")
@@ -238,7 +238,7 @@ def _wrap_title_text(
for ch in seg:
# CJK 字符按全角估算,其他按半角
char_width = float(ass_font_size) if ord(ch) > 0x2E80 else ass_font_size * 0.55
char_width = float(font_size) if ord(ch) > 0x2E80 else font_size * 0.55
if current_width + char_width > available_width and current_line:
lines.append(current_line)
@@ -15,6 +15,7 @@ from packages.domain.ass_subtitle_builder import (
TITLE_MARGIN_BOTTOM,
TITLE_MARGIN_SIDE,
TITLE_MARGIN_TOP,
_wrap_title_text,
build_ass_content,
build_ass_style,
escape_ass_text,
@@ -579,3 +580,44 @@ class TestConstants:
assert isinstance(TITLE_MARGIN_TOP, int)
assert isinstance(TITLE_MARGIN_BOTTOM, int)
assert isinstance(TITLE_MARGIN_SIDE, int)
# ============================================================
# _wrap_title_text 换行逻辑验证
# ============================================================
class TestWrapTitleTextFontSizeConsistency:
"""验证换行计算使用原始 font_size,与 CSS 预览一致。"""
def test_font_size_113_uses_original_not_compensated(self):
"""font_size=113 时,每行应容纳8个字(113px字宽),而非6个字(153px字宽)。"""
# 标题"永康拾掇脚阔头"共7个字
# 可用宽度 = 1080 - 60 - 60 = 960px
# 用 font_size=113char_width=113960/113 ≈ 8.5,每行8个字
# 7个字 < 8个字,应该在一行内
title = "永康拾掇脚阔头"
result = _wrap_title_text(title, video_width=1080, font_size=113, margin_l=60, margin_r=60)
# 不应该有换行
assert "\\N" not in result
assert result == title
def test_long_title_wraps_correctly(self):
"""长标题应该按 font_size 字宽正确换行。"""
# 16个中文字,每行8个字,应该换行为2行
title = "永康拾掇脚阔头来一个笑一个哈哈哈"
result = _wrap_title_text(title, video_width=1080, font_size=113, margin_l=60, margin_r=60)
# 应该有一个换行
assert result.count("\\N") == 1
# 每行8个字
lines = result.split("\\N")
assert len(lines) == 2
assert len(lines[0]) == 8
assert len(lines[1]) == 8
def test_mixed_cjk_and_ascii(self):
"""混合中英文时,英文按半角宽度计算。"""
# "测试test" = 2个中文(2*113=226) + 4个英文(4*113*0.55=248.6) = 474.6px
title = "测试test"
result = _wrap_title_text(title, video_width=1080, font_size=113, margin_l=60, margin_r=60)
# 总宽度474.6px < 960px,应该在一行内
assert "\\N" not in result