6.5 KiB
6.5 KiB
画布模板导入导出包(.wcd)方案(规划)
状态:第一版已实现(画布导出
.wcd、首页导入.wcd)。 目的:实现画布/设计的完整导入导出,要求包内不仅包含画布尺寸、背景、图层、元素摆放信息,还要把元素用到的素材一起带出去,使得包可以在另一台机器或另一个实例中导入复用。
1. 包格式
建议采用 Zip 包,文件后缀为 .wcd。没有必要自定义二进制格式。
预期目录结构:
example.wcd
├── manifest.json // 包元数据与 schema version
├── document.json // CanvasDocument:画布结构
├── preview.png // 可选封面图
├── fonts/ // 可选字体文件
│ └── ...
└── assets/
├── asset-001.svg
├── asset-002.png
└── asset-003.svg
2. manifest.json
{
"format": "wordcloud-canvas",
"version": 1,
"name": "海报模板",
"description": "示例模板",
"createdAt": "2026-08-06T00:00:00Z",
"canvas": {
"width": 1600,
"height": 1000,
"background": "#ffffff"
},
"assets": [
{
"id": "asset-001",
"originalAssetId": "asset_xxx",
"name": "词云 A",
"type": "svg",
"mimeType": "image/svg+xml",
"sha256": "abc...",
"size": 1024
}
],
"fonts": []
}
字段说明:
format:固定标识,防止其他 Zip 被误导入。version:包格式版本,后续升级时便于兼容。assets[].id:包内临时 ID,只在这个包内有效。originalAssetId:导出时的来源素材 ID,仅记录,不要求导入后保留。sha256:可选,导入时用于去重。
3. document.json
document.json 就是当前前端的 CanvasDocument 模型:
width:画布宽度。height:画布高度。background:画布背景色。layers:图层列表。layerFolders:图层文件夹列表。elements:元素列表。
对 Sticker 元素有一个关键规则:导出时把 assetId 替换成包内临时 ID。
示例:
{
"width": 1600,
"height": 1000,
"background": "#ffffff",
"layers": [
{ "id": "layer-1", "name": "词云", "visible": true, "locked": false }
],
"layerFolders": [],
"elements": [
{
"id": "element-1",
"type": "sticker",
"assetId": "asset-001",
"x": 100,
"y": 80,
"width": 800,
"height": 500,
"rotation": 0,
"opacity": 1
}
]
}
4. 导出流程
建议由后端提供导出接口,例如:
GET /api/designs/{id}/export
或当前模板库扩展为:
GET /api/design-templates/{id}/export
导出步骤:
- 从数据库读取画布文档
design_documents。 - 序列化
CanvasDocument。 - 遍历 Sticker 元素,收集所有真实素材 ID。
- 读取每个素材文件字节。
- 为每个素材生成包内 ID,例如
asset-001。 - 用包内 ID 替换
document.json中的assetId。 - 把素材写入
assets/目录。 - 可选:生成
preview.png作为导入时的缩略图。 - 可选:如果模板使用了后端字体,把字体文件写入
fonts/。 - 生成
manifest.json。 - 打包为
.wcd并返回。
5. 导入流程
建议后端提供导入接口,例如:
POST /api/designs/import
multipart/form-data: file=.wcd
导入步骤:
- 把
.wcd解压到临时目录。 - 校验
manifest.json:- 是否是
wordcloud-canvas格式。 version是否兼容。document.json是否结构合法。
- 是否是
- 读取
document.json并通过现有normalizeDocument逻辑归一化。 - 逐个处理
assets/下素材:- 计算 SHA-256。
- 如果素材表中已有相同 SHA-256,复用已有素材 ID。
- 否则调用素材导入逻辑写入
assets表 + 文件系统。
- 把
document.json中的包内assetId重新映射为真实素材 ID。 - 保存为新的
design_documents。 - 可选:把
preview.png作为模板封面。 - 返回新设计/模板 ID。
6. 与现有模板系统的关系
当前模板保存是把 CanvasDocument 和 reference_asset_ids 写到目录 JSON 里:
- 在线模板:保持后端素材引用,适合当前实例内复用。
.wcd:把素材一起打包,适合跨机器/离线/换实例导入导出。
两者最终统一到:
design_documents:存画布文档。assets:存素材元数据。design_templates:存模板元数据并引用素材。
.wcd 只是外部交换容器。
7. 边界与设计决策
先不做自定义二进制格式
Zip + JSON 足够,方便调试、校验和后续扩展。
不把素材 base64 塞进 document.json
素材单独放文件,避免 JSON 膨胀;document.json 只保存引用 ID。
素材缺失处理
导出时如果某个素材文件缺失,可以选择:
- 导出失败并提示哪个素材缺失。
- 或在
manifest中标记为missing,导入时提示并跳过。
建议第一版采用“导出失败并提示”,保证导入包完整。
字体处理
第一版建议只保留 fontFamily 字符串,不打包字体。
后续如果确实需要跨机器还原,再把字体文件放进 fonts/,导入时注册到字体库。
去重
assets.sha256 是导入去重的关键字段:
- 包内相同素材只存一次。
- 多次导入相同素材时直接复用数据库中的现有素材。
8. 分阶段实施
阶段一:最小可用包(已完成)
- 定义
.wcd,包含manifest.json、document.json、assets/。 - 支持导出当前画布或模板。
- 支持解压导入,只处理贴纸素材和画布布局。
- 不处理字体,不生成 preview。
阶段二:导入体验完善
- 生成
preview.png。 - 导入时检查素材缺失。
- 支持同一设计重复导入去重。
阶段三:与 PostgreSQL 打通
POST /api/designs/import最终写入design_documents。- 素材导入自动写入
assets表。 - 导出接口直接读取
design_documents和assets,不再依赖前端状态。
9. 相关文件参考
frontend/src/lib/svgExport.ts:当前图层 ZIP 导出。frontend/src/lib/templateLibrary.ts:当前模板保存/读取。frontend/src/lib/canvasDocument.ts:CanvasDocument模型与归一化。frontend/src/types.ts:CanvasDocument、StickerAsset等类型。backend/service/app.py:当前/api/assets、/api/design-templates接口。docs/DESIGN_DATA_STORAGE_PLAN.md:存储层重构后文档落库设计。