270 lines
7.6 KiB
Markdown
270 lines
7.6 KiB
Markdown
|
|
# VibrantTemplate 模板分析
|
||
|
|
|
||
|
|
> 文件: `poster/templates/vibrant_template.py`
|
||
|
|
> 大小: 78KB / 1757 行
|
||
|
|
> 创建日期: 2024-12-10
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 一、功能概述
|
||
|
|
|
||
|
|
VibrantTemplate 是"活力风格"海报模板,适用于旅游、美食分享等场景。
|
||
|
|
|
||
|
|
**核心特点**:
|
||
|
|
- 底部毛玻璃效果文案区域
|
||
|
|
- 自适应字体大小
|
||
|
|
- 双栏布局 (左栏: 按钮+列表 / 右栏: 价格+票种)
|
||
|
|
- 支持 PNG / PSD / Fabric.js JSON 多种输出
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 二、功能模块拆解
|
||
|
|
|
||
|
|
### 2.1 入口方法
|
||
|
|
|
||
|
|
```python
|
||
|
|
generate(images, content, theme_color, glass_intensity, num_variations, **kwargs)
|
||
|
|
```
|
||
|
|
|
||
|
|
**流程**:
|
||
|
|
1. 判断是否需要生成 Fabric.js JSON
|
||
|
|
2. 如果需要 → `_unified_render()` (PNG + JSON)
|
||
|
|
3. 否则 → `_generate_legacy()` (仅 PNG)
|
||
|
|
|
||
|
|
### 2.2 核心功能模块
|
||
|
|
|
||
|
|
| 模块 | 方法 | 行数 | 职责 |
|
||
|
|
|-----|------|------|------|
|
||
|
|
| **图片处理** | `resize_image` | - | 调整图片到目标尺寸 |
|
||
|
|
| **渐变检测** | `_detect_gradient_start_position` | 197-215 | 智能检测毛玻璃起始位置 |
|
||
|
|
| **颜色提取** | `_extract_glass_colors_from_image` | 275-296 | 从图片提取毛玻璃颜色 |
|
||
|
|
| **毛玻璃效果** | `_create_frosted_glass_overlay` | 236-273 | 创建渐变半透明覆盖层 |
|
||
|
|
| **布局计算** | `_calculate_content_margins` | 400-435 | 计算内容区域边距 |
|
||
|
|
| **字体自适应** | `_calculate_optimal_font_size_enhanced` | 298-374 | 二分查找最佳字体大小 |
|
||
|
|
| **文字渲染** | `_render_texts` | 376-398 | 渲染所有文本元素 |
|
||
|
|
| **标题渲染** | `_render_title_subtitle` | 446-484 | 渲染标题和副标题 |
|
||
|
|
| **左栏渲染** | `_render_left_column` | 486-508 | 渲染按钮和项目列表 |
|
||
|
|
| **右栏渲染** | `_render_right_column` | 510-549 | 渲染价格、票种、备注 |
|
||
|
|
| **页脚渲染** | `_render_footer` | 437-444 | 渲染页脚标签 |
|
||
|
|
| **PSD 生成** | `generate_layered_psd` | 551-649 | 生成分层 PSD 文件 |
|
||
|
|
| **图层创建** | `_create_detailed_text_layers` | 782-855 | 创建分离的文字图层 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 三、内容数据结构
|
||
|
|
|
||
|
|
```python
|
||
|
|
content = {
|
||
|
|
# 主标题 (自适应字体 60-210px)
|
||
|
|
"title": "正佳极地海洋世界",
|
||
|
|
|
||
|
|
# 副标题/Slogan (自适应字体 30-113px)
|
||
|
|
"slogan": "都说海洋馆是约会圣地!",
|
||
|
|
|
||
|
|
# 价格 (自适应字体 60-180px)
|
||
|
|
"price": "199",
|
||
|
|
|
||
|
|
# 票种
|
||
|
|
"ticket_type": "夜场票",
|
||
|
|
|
||
|
|
# 左栏按钮文字
|
||
|
|
"content_button": "套餐内容",
|
||
|
|
|
||
|
|
# 左栏列表项
|
||
|
|
"content_items": [
|
||
|
|
"正佳极地海洋世界夜场票1张",
|
||
|
|
"有效期至2025.06.02",
|
||
|
|
"多种动物表演全部免费"
|
||
|
|
],
|
||
|
|
|
||
|
|
# 备注 (右栏底部)
|
||
|
|
"remarks": [
|
||
|
|
"工作日可直接入园",
|
||
|
|
"周末请提前1天预约"
|
||
|
|
],
|
||
|
|
|
||
|
|
# 页脚标签
|
||
|
|
"tag": "#520特惠",
|
||
|
|
"pagination": "1/3"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 四、配置项
|
||
|
|
|
||
|
|
### 4.1 颜色主题
|
||
|
|
|
||
|
|
```python
|
||
|
|
colors = {
|
||
|
|
'ocean_deep': [(0, 30, 80), (20, 120, 220)], # 海洋蓝
|
||
|
|
'sunset_warm': [(255, 94, 77), (255, 154, 0)], # 日落橙
|
||
|
|
'cool_mint': [(64, 224, 208), (127, 255, 212)], # 薄荷绿
|
||
|
|
'royal_purple': [(75, 0, 130), (138, 43, 226)], # 皇家紫
|
||
|
|
'forest_green': [(34, 139, 34), (144, 238, 144)], # 森林绿
|
||
|
|
'fire_red': [(220, 20, 60), (255, 69, 0)], # 火焰红
|
||
|
|
'gray_gradient': [(128, 128, 128), (211, 211, 211)],
|
||
|
|
'dark_gray': [(15, 15, 15), (30, 30, 30)]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 毛玻璃效果
|
||
|
|
|
||
|
|
```python
|
||
|
|
glass_effect = {
|
||
|
|
'max_opacity': 240, # 最大不透明度
|
||
|
|
'blur_radius': 22, # 模糊半径
|
||
|
|
'transition_height': 120, # 过渡区域高度
|
||
|
|
'intensity_multiplier': 1.5 # 强度系数 (可调)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.3 硬编码参数 (问题)
|
||
|
|
|
||
|
|
| 参数 | 值 | 位置 |
|
||
|
|
|-----|-----|------|
|
||
|
|
| 标题字体范围 | 60-210px | 多处 |
|
||
|
|
| 副标题字体范围 | 30-113px | 多处 |
|
||
|
|
| 价格字体范围 | 60-180px | 多处 |
|
||
|
|
| 标准边距 | 38px | `_estimate_content_height` |
|
||
|
|
| 内容行高 | 48px | `_estimate_content_height` |
|
||
|
|
| 页脚位置 | height - 45 | 多处 |
|
||
|
|
| 字体路径 | 硬编码绝对路径 | 46行 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 五、问题分析
|
||
|
|
|
||
|
|
### 5.1 代码复杂度
|
||
|
|
|
||
|
|
| 问题 | 说明 |
|
||
|
|
|-----|------|
|
||
|
|
| **文件过大** | 1757 行,难以维护 |
|
||
|
|
| **重复代码** | `_create_text_only_layer` 定义了两次 (712-745, 747-780) |
|
||
|
|
| **职责混杂** | 布局、渲染、颜色、字体逻辑混在一起 |
|
||
|
|
| **硬编码参数** | 大量数值散落在代码中 |
|
||
|
|
|
||
|
|
### 5.2 可维护性
|
||
|
|
|
||
|
|
| 问题 | 影响 |
|
||
|
|
|-----|------|
|
||
|
|
| 字体路径硬编码 | 部署环境变化需修改代码 |
|
||
|
|
| 颜色配置在代码中 | 新增主题需改代码 |
|
||
|
|
| 布局参数分散 | 调整布局需修改多处 |
|
||
|
|
| 缺少单元测试 | 修改易引入 bug |
|
||
|
|
|
||
|
|
### 5.3 扩展性
|
||
|
|
|
||
|
|
| 问题 | 影响 |
|
||
|
|
|-----|------|
|
||
|
|
| 布局固定为双栏 | 无法支持其他布局 |
|
||
|
|
| 内容字段固定 | 新增字段需改代码 |
|
||
|
|
| 渲染逻辑耦合 | PNG/JSON/PSD 共用代码导致复杂 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 六、重构建议
|
||
|
|
|
||
|
|
### 6.1 模块拆分
|
||
|
|
|
||
|
|
```
|
||
|
|
poster/templates/vibrant/
|
||
|
|
├── __init__.py # 导出 VibrantTemplate
|
||
|
|
├── template.py # 主模板类 (精简)
|
||
|
|
├── config.py # 配置定义 (颜色、字体、布局)
|
||
|
|
├── layout.py # 布局计算
|
||
|
|
├── effects.py # 毛玻璃等特效
|
||
|
|
├── text_renderer.py # 文字渲染
|
||
|
|
└── exporters/
|
||
|
|
├── png_exporter.py # PNG 输出
|
||
|
|
├── psd_exporter.py # PSD 输出
|
||
|
|
└── json_exporter.py # Fabric.js JSON 输出
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6.2 配置外部化
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# config/poster_templates/vibrant.yaml
|
||
|
|
name: vibrant
|
||
|
|
description: 活力风格模板
|
||
|
|
|
||
|
|
size: [1350, 1800]
|
||
|
|
|
||
|
|
fonts:
|
||
|
|
chinese: assets/font/兰亭粗黑简.TTF
|
||
|
|
fallback: default
|
||
|
|
|
||
|
|
colors:
|
||
|
|
ocean_deep: [[0, 30, 80], [20, 120, 220]]
|
||
|
|
sunset_warm: [[255, 94, 77], [255, 154, 0]]
|
||
|
|
# ...
|
||
|
|
|
||
|
|
glass_effect:
|
||
|
|
max_opacity: 240
|
||
|
|
blur_radius: 22
|
||
|
|
transition_height: 120
|
||
|
|
intensity_multiplier: 1.5
|
||
|
|
|
||
|
|
layout:
|
||
|
|
title:
|
||
|
|
font_size_range: [60, 210]
|
||
|
|
width_ratio: 0.98
|
||
|
|
subtitle:
|
||
|
|
font_size_range: [30, 113]
|
||
|
|
width_ratio: 0.95
|
||
|
|
price:
|
||
|
|
font_size_range: [60, 180]
|
||
|
|
width_ratio: 0.7
|
||
|
|
margins:
|
||
|
|
left: 60
|
||
|
|
right: 60
|
||
|
|
footer: 45
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6.3 重构优先级
|
||
|
|
|
||
|
|
| 任务 | 优先级 | 复杂度 | 收益 |
|
||
|
|
|-----|--------|--------|------|
|
||
|
|
| 删除重复代码 | 🔴 高 | 低 | 立即减少 bug |
|
||
|
|
| 配置外部化 | 🔴 高 | 中 | 提高可维护性 |
|
||
|
|
| 模块拆分 | 🟡 中 | 高 | 提高可读性 |
|
||
|
|
| 单元测试 | 🟡 中 | 中 | 保障质量 |
|
||
|
|
| 布局系统抽象 | 🟢 低 | 高 | 支持更多模板 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 七、渲染流程图
|
||
|
|
|
||
|
|
```
|
||
|
|
generate()
|
||
|
|
│
|
||
|
|
├─ generate_fabric_json=True
|
||
|
|
│ └─ _unified_render() x2
|
||
|
|
│ ├─ output_format='png' → PNG Image
|
||
|
|
│ └─ output_format='json' → Fabric.js JSON
|
||
|
|
│
|
||
|
|
└─ generate_fabric_json=False
|
||
|
|
└─ _generate_legacy()
|
||
|
|
├─ resize_image() # 调整图片
|
||
|
|
├─ _estimate_content_height() # 预估内容高度
|
||
|
|
├─ _detect_gradient_start_position() # 检测渐变位置
|
||
|
|
├─ _create_composite_image() # 创建合成图
|
||
|
|
│ ├─ _extract_glass_colors_from_image()
|
||
|
|
│ └─ _create_frosted_glass_overlay()
|
||
|
|
└─ _render_texts() # 渲染文字
|
||
|
|
├─ _calculate_content_margins()
|
||
|
|
├─ _render_footer()
|
||
|
|
├─ _render_title_subtitle()
|
||
|
|
├─ _render_left_column()
|
||
|
|
└─ _render_right_column()
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 八、下一步行动
|
||
|
|
|
||
|
|
1. **立即**: 删除重复的 `_create_text_only_layer` 方法
|
||
|
|
2. **短期**: 将硬编码参数提取到配置文件
|
||
|
|
3. **中期**: 拆分为独立模块
|
||
|
|
4. **长期**: 建立统一的模板系统架构
|