307 lines
7.2 KiB
Markdown
307 lines
7.2 KiB
Markdown
|
|
# 后端Fabric.js JSON格式规范
|
|||
|
|
|
|||
|
|
## 标准格式要求
|
|||
|
|
|
|||
|
|
### 1. 根对象结构
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"version": "5.3.0",
|
|||
|
|
"width": 1350,
|
|||
|
|
"height": 1800,
|
|||
|
|
"objects": [
|
|||
|
|
// 对象数组
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 对象类型要求(只使用标准Fabric.js类型)
|
|||
|
|
|
|||
|
|
#### ✅ 允许的标准类型:
|
|||
|
|
- `rect` - 矩形
|
|||
|
|
- `circle` - 圆形
|
|||
|
|
- `textbox` - 文本框
|
|||
|
|
- `text` - 文本
|
|||
|
|
- `image` - 图片
|
|||
|
|
- `line` - 线条
|
|||
|
|
- `polygon` - 多边形
|
|||
|
|
- `path` - 路径
|
|||
|
|
- `group` - 组
|
|||
|
|
|
|||
|
|
#### ❌ 禁止的自定义类型:
|
|||
|
|
- `CustomRect` -> 应改为 `rect`
|
|||
|
|
- `CustomTextbox` -> 应改为 `textbox`
|
|||
|
|
- `CustomCircle` -> 应改为 `circle`
|
|||
|
|
- `CustomGroup` -> 应改为 `group`
|
|||
|
|
- `ThinTailArrow` -> 应改为 `path` 或 `rect`
|
|||
|
|
- `Arrow` -> 应改为 `path` 或 `rect`
|
|||
|
|
|
|||
|
|
### 3. 基本对象属性要求
|
|||
|
|
|
|||
|
|
#### 所有对象必须包含:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "rect", // 标准类型
|
|||
|
|
"left": 100, // 数值,非null
|
|||
|
|
"top": 50, // 数值,非null
|
|||
|
|
"width": 200, // 数值 > 0
|
|||
|
|
"height": 100, // 数值 > 0
|
|||
|
|
"fill": "#ffffff",
|
|||
|
|
"opacity": 1,
|
|||
|
|
"angle": 0,
|
|||
|
|
"scaleX": 1,
|
|||
|
|
"scaleY": 1
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 文本对象额外属性:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "textbox",
|
|||
|
|
"text": "实际文本内容", // 非空字符串
|
|||
|
|
"fontSize": 16, // 数值 > 0
|
|||
|
|
"fontFamily": "Arial", // 有效字体名
|
|||
|
|
"fill": "#000000"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 图片对象要求:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "image",
|
|||
|
|
"src": "https://example.com/image.jpg", // 必须是完整有效的URL
|
|||
|
|
"width": 300, // 实际图片宽度
|
|||
|
|
"height": 200 // 实际图片高度
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**重要:图片src必须是可访问的完整URL,不能是:**
|
|||
|
|
- 相对路径如 `preview1.jpg`
|
|||
|
|
- 本地路径如 `./images/test.png`
|
|||
|
|
- 占位符如 `image1.jpg`
|
|||
|
|
|
|||
|
|
### 4. 组对象格式:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "group",
|
|||
|
|
"objects": [
|
|||
|
|
// 组内的标准对象
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 完整示例:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"version": "5.3.0",
|
|||
|
|
"width": 1350,
|
|||
|
|
"height": 1800,
|
|||
|
|
"objects": [
|
|||
|
|
{
|
|||
|
|
"type": "rect",
|
|||
|
|
"left": 100,
|
|||
|
|
"top": 100,
|
|||
|
|
"width": 200,
|
|||
|
|
"height": 150,
|
|||
|
|
"fill": "#ff0000",
|
|||
|
|
"opacity": 1,
|
|||
|
|
"angle": 0,
|
|||
|
|
"scaleX": 1,
|
|||
|
|
"scaleY": 1
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"type": "textbox",
|
|||
|
|
"left": 50,
|
|||
|
|
"top": 300,
|
|||
|
|
"width": 300,
|
|||
|
|
"height": 50,
|
|||
|
|
"text": "这是文本内容",
|
|||
|
|
"fontSize": 24,
|
|||
|
|
"fontFamily": "Arial",
|
|||
|
|
"fill": "#000000",
|
|||
|
|
"opacity": 1
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"type": "image",
|
|||
|
|
"left": 400,
|
|||
|
|
"top": 100,
|
|||
|
|
"width": 200,
|
|||
|
|
"height": 200,
|
|||
|
|
"src": "https://example.com/path/to/image.jpg",
|
|||
|
|
"opacity": 1
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 复杂装饰元素处理策略
|
|||
|
|
|
|||
|
|
### 问题:复杂的装饰性元素(如按钮、装饰图案)
|
|||
|
|
- **旧方案**:使用多个形状组合(rect + circle + path等)
|
|||
|
|
- **新方案**:将复杂元素预渲染为图像
|
|||
|
|
|
|||
|
|
### 实现方式:
|
|||
|
|
1. **后端预渲染**:将复杂的按钮样式、装饰图案等渲染为PNG图像
|
|||
|
|
2. **托管图像**:将这些装饰图像托管在可访问的URL上
|
|||
|
|
3. **JSON引用**:在fabric.js JSON中使用标准`image`对象引用
|
|||
|
|
|
|||
|
|
### 示例:按钮元素
|
|||
|
|
```json
|
|||
|
|
// ❌ 旧方式:复杂形状组合
|
|||
|
|
{
|
|||
|
|
"type": "group",
|
|||
|
|
"objects": [
|
|||
|
|
{"type": "rect", "fill": "linear-gradient(...)", ...},
|
|||
|
|
{"type": "circle", "fill": "rgba(...)", ...},
|
|||
|
|
{"type": "path", "path": "M10,10 L20,20...", ...}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 新方式:预渲染图像
|
|||
|
|
{
|
|||
|
|
"type": "image",
|
|||
|
|
"left": 100,
|
|||
|
|
"top": 200,
|
|||
|
|
"width": 120,
|
|||
|
|
"height": 40,
|
|||
|
|
"src": "https://your-domain.com/api/decorative/button_style_1.png",
|
|||
|
|
"opacity": 1
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 关键要求总结:
|
|||
|
|
|
|||
|
|
1. **只使用Fabric.js标准对象类型**
|
|||
|
|
2. **所有数值属性必须有效(非null、非0宽高)**
|
|||
|
|
3. **图片src必须是完整可访问的URL**
|
|||
|
|
4. **包含完整的width/height信息**
|
|||
|
|
5. **遵循标准JSON结构**
|
|||
|
|
6. **复杂装饰元素使用预渲染图像**
|
|||
|
|
|
|||
|
|
这样前端就可以直接使用 `canvas.loadFromJSON()` 而无需任何预处理!
|
|||
|
|
|
|||
|
|
## 装饰性图像处理流程
|
|||
|
|
|
|||
|
|
### 完整的端到端流程:
|
|||
|
|
|
|||
|
|
1. **Python端生成装饰图像**
|
|||
|
|
- 使用PIL动态生成按钮、标签、价格背景等装饰元素
|
|||
|
|
- 返回base64编码的PNG图像数据
|
|||
|
|
- 在fabric.js JSON中使用占位符URL(https://placeholder.qiniu.com/decorative/)
|
|||
|
|
|
|||
|
|
2. **Java端处理装饰图像**
|
|||
|
|
- 接收装饰图像的base64数据
|
|||
|
|
- 上传每个装饰图像到七牛云存储
|
|||
|
|
- 获取七牛云的真实URL
|
|||
|
|
- 替换fabric.js JSON中的占位符URL为真实URL
|
|||
|
|
|
|||
|
|
3. **前端使用**
|
|||
|
|
- 接收更新后的fabric.js JSON(包含真实的图像URL)
|
|||
|
|
- 直接使用`canvas.loadFromJSON()`加载完整设计
|
|||
|
|
|
|||
|
|
### API响应结构:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"requestId": "poster-20250101-120000-abc123",
|
|||
|
|
"templateId": "vibrant",
|
|||
|
|
"resultImagesBase64": [...],
|
|||
|
|
"fabricJsons": [
|
|||
|
|
{
|
|||
|
|
"id": "fabric_json_0",
|
|||
|
|
"data": "base64_encoded_json...",
|
|||
|
|
"jsonData": {
|
|||
|
|
"version": "5.3.0",
|
|||
|
|
"width": 1350,
|
|||
|
|
"height": 1800,
|
|||
|
|
"objects": [
|
|||
|
|
{
|
|||
|
|
"type": "image",
|
|||
|
|
"src": "https://qiniu-domain.com/poster/decorative/2025/01/01/button_1234567890.png",
|
|||
|
|
"left": 100,
|
|||
|
|
"top": 200,
|
|||
|
|
"width": 200,
|
|||
|
|
"height": 60
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"decorativeImages": {
|
|||
|
|
"button": {
|
|||
|
|
"originalId": "button",
|
|||
|
|
"type": "button",
|
|||
|
|
"qiniuUrl": "https://qiniu-domain.com/poster/decorative/2025/01/01/button_1234567890.png",
|
|||
|
|
"uploadSuccess": true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 实现状态
|
|||
|
|
|
|||
|
|
### ✅ 已完成:
|
|||
|
|
- 标准fabric.js JSON格式输出
|
|||
|
|
- 简化的文本布局(只使用textbox/text)
|
|||
|
|
- 装饰性图像生成器(按钮、标签、价格背景)
|
|||
|
|
- 装饰图像上传到七牛云的完整流程
|
|||
|
|
- fabric.js JSON中占位符URL自动替换
|
|||
|
|
- 统一1350x1800基础尺寸
|
|||
|
|
- 端到端的装饰图像处理工作流
|
|||
|
|
|
|||
|
|
## 统一生成架构(重大改进)
|
|||
|
|
|
|||
|
|
### 问题解决:
|
|||
|
|
**原问题**:fabric.js JSON和PNG分开生成,导致参数不一致、位置偏差等问题。
|
|||
|
|
|
|||
|
|
**解决方案**:VibrantTemplate统一生成模式
|
|||
|
|
- PNG和Fabric.js JSON在同一次render调用中生成
|
|||
|
|
- 使用完全相同的参数、计算逻辑、渲染上下文
|
|||
|
|
- 消除任何可能的差异来源
|
|||
|
|
|
|||
|
|
### 技术实现:
|
|||
|
|
|
|||
|
|
1. **VibrantTemplate.generate()扩展**:
|
|||
|
|
```python
|
|||
|
|
# 新增参数
|
|||
|
|
generation_result = template.generate(
|
|||
|
|
content=content,
|
|||
|
|
images=images,
|
|||
|
|
generate_fabric_json=True # 启用统一生成
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 返回结构
|
|||
|
|
{
|
|||
|
|
'png': PIL.Image,
|
|||
|
|
'fabric_json': Dict,
|
|||
|
|
'metadata': {
|
|||
|
|
'gradient_start': int,
|
|||
|
|
'theme_color': str,
|
|||
|
|
'elements_count': int
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **渲染上下文共享**:
|
|||
|
|
- 图像处理参数
|
|||
|
|
- 渐变起始位置
|
|||
|
|
- 颜色提取结果
|
|||
|
|
- 文本布局计算
|
|||
|
|
- 所有几何计算
|
|||
|
|
|
|||
|
|
3. **向后兼容性**:
|
|||
|
|
- 自动检测模板是否支持新参数
|
|||
|
|
- 无缝回退到独立生成模式
|
|||
|
|
- 不影响现有的模板实现
|
|||
|
|
|
|||
|
|
### ✅ 已完成:
|
|||
|
|
- 标准fabric.js JSON格式输出
|
|||
|
|
- 简化的文本布局(只使用textbox/text)
|
|||
|
|
- 装饰性图像生成器(按钮、标签、价格背景)
|
|||
|
|
- 装饰图像上传到七牛云的完整流程
|
|||
|
|
- fabric.js JSON中占位符URL自动替换
|
|||
|
|
- 统一1350x1800基础尺寸
|
|||
|
|
- 端到端的装饰图像处理工作流
|
|||
|
|
- **VibrantTemplate统一生成架构**
|
|||
|
|
- **PNG和JSON完全一致的渲染逻辑**
|
|||
|
|
|
|||
|
|
### 🔄 进行中:
|
|||
|
|
- 测试统一生成模式的一致性验证
|