baodan/api/insurance/poster/format_registry.py
wsb1224 e1770be4cc 现在选择“长图海报”后,在“海报尺寸”下方可以切换:
自动高度
自定义高度:1920–30000px,默认 4500px
自定义高度会同步影响画布预览、任务快照、renderDocument、历史恢复和最终 PNG。若内容超过指定高度,系统会阻止导出并提示最低所需高度,不会静默裁掉底部内容。
关键修改:
[PosterCreativePanel.vue (line 51)](D:/work/code/python/coding/baodanagent/frontend/src/components/poster/workspace/PosterCreativePanel.vue:51)
[PosterHtmlCanvas.vue (line 1)](D:/work/code/python/coding/baodanagent/frontend/src/components/poster/long/PosterHtmlCanvas.vue:1)
[poster-exporter.ts (line 95)](D:/work/code/python/coding/baodanagent/frontend/src/utils/poster-exporter.ts:95)
[format_registry.py (line 17)](D:/work/code/python/coding/baodanagent/api/insurance/poster/format_registry.py:17)
[render_validation.py (line 13)](D:/work/code/python/coding/baodanagent/api/insurance/poster/render_validation.py:13)
验证结果:33 项海报测试通过、Vue 类型检查通过、生产构建通过、UI 静态检查通过
2026-07-31 22:05:57 +08:00

115 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""海报输出格式注册表。
逻辑尺寸用于 HTML 排版,输出尺寸用于最终 PNG背景素材尺寸用于图片模型。
三者不得通过同一个宽高字符串互相推断。
"""
from copy import deepcopy
class PosterFormatError(ValueError):
"""海报格式不受支持。"""
CUSTOM_LONG_HEIGHT_MIN = 1920
CUSTOM_LONG_HEIGHT_MAX = 30000
_FORMATS = (
{
"id": "single_2_3",
"label": "竖版单图 2:3",
"outputMode": "single",
"layout": {"width": 512, "height": 768},
"output": {"width": 1024, "height": 1536},
"exportSize": "1024x1536",
"backgroundAssetSize": "1024x1536",
},
{
"id": "single_9_16",
"label": "竖屏单图 9:16",
"outputMode": "single",
"layout": {"width": 540, "height": 960},
"output": {"width": 1080, "height": 1920},
"exportSize": "1080x1920",
"backgroundAssetSize": "1024x1536",
},
{
"id": "long_1242_auto",
"label": "完整方案长图",
"outputMode": "long",
"layout": {"width": 414, "height": None},
"output": {"width": 1242, "height": None},
"exportSize": "1242xauto",
"backgroundAssetSize": "1024x1536",
},
)
_FORMAT_BY_ID = {item["id"]: item for item in _FORMATS}
_DEFAULT_BY_MODE = {
"single": "single_2_3",
"long": "long_1242_auto",
}
_LEGACY_FORMATS = {
("single", "1024x1792"): "single_2_3",
("single", "1024x1536"): "single_2_3",
("single", "1080x1920"): "single_9_16",
("long", "1080x2160"): "long_1242_auto",
("long", "1080x3240"): "long_1242_auto",
("long", "1080x4320"): "long_1242_auto",
("long", "1242xauto"): "long_1242_auto",
}
def list_poster_formats() -> list[dict]:
"""返回可供前端选择的安全格式副本。"""
return deepcopy(list(_FORMATS))
def resolve_custom_long_height(value, output_mode: str) -> int | None:
"""解析长图自定义输出高度None 表示内容驱动的自动高度。"""
if value is None or value == "" or value == "auto":
return None
if output_mode != "long":
raise PosterFormatError("自定义高度仅长图模式可用")
if isinstance(value, bool):
raise PosterFormatError("长图高度必须是整数")
try:
height = int(value)
except (TypeError, ValueError) as exc:
raise PosterFormatError("长图高度必须是整数") from exc
if isinstance(value, float) and not value.is_integer():
raise PosterFormatError("长图高度必须是整数")
if not CUSTOM_LONG_HEIGHT_MIN <= height <= CUSTOM_LONG_HEIGHT_MAX:
raise PosterFormatError(
f"长图高度必须在 {CUSTOM_LONG_HEIGHT_MIN}{CUSTOM_LONG_HEIGHT_MAX}px 之间"
)
return height
def resolve_poster_format(
format_id: str | None = None,
legacy_size: str | None = None,
output_mode: str = "single",
) -> dict:
"""解析并校验海报格式,未知值必须明确失败。"""
mode = str(output_mode or "single")
if mode not in _DEFAULT_BY_MODE:
raise PosterFormatError(f"不支持的输出模式: {output_mode}")
if format_id:
spec = _FORMAT_BY_ID.get(str(format_id))
if not spec:
raise PosterFormatError(f"不支持的海报格式: {format_id}")
elif legacy_size:
resolved_id = _LEGACY_FORMATS.get((mode, str(legacy_size)))
if not resolved_id:
raise PosterFormatError(f"不支持的海报尺寸: {legacy_size}")
spec = _FORMAT_BY_ID[resolved_id]
else:
spec = _FORMAT_BY_ID[_DEFAULT_BY_MODE[mode]]
if spec["outputMode"] != mode:
mode_label = "长图" if mode == "long" else "单图"
raise PosterFormatError(f"格式 {spec['id']} 不支持{mode_label}模式")
return deepcopy(spec)