Files
wordcloud/docs/CANVAS_EXPORT_PACKAGE.md
T

6.5 KiB
Raw Blame History

画布模板导入导出包(.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

导出步骤:

  1. 从数据库读取画布文档 design_documents
  2. 序列化 CanvasDocument
  3. 遍历 Sticker 元素,收集所有真实素材 ID。
  4. 读取每个素材文件字节。
  5. 为每个素材生成包内 ID,例如 asset-001
  6. 用包内 ID 替换 document.json 中的 assetId
  7. 把素材写入 assets/ 目录。
  8. 可选:生成 preview.png 作为导入时的缩略图。
  9. 可选:如果模板使用了后端字体,把字体文件写入 fonts/
  10. 生成 manifest.json
  11. 打包为 .wcd 并返回。

5. 导入流程

建议后端提供导入接口,例如:

POST /api/designs/import
multipart/form-data: file=.wcd

导入步骤:

  1. .wcd 解压到临时目录。
  2. 校验 manifest.json
    • 是否是 wordcloud-canvas 格式。
    • version 是否兼容。
    • document.json 是否结构合法。
  3. 读取 document.json 并通过现有 normalizeDocument 逻辑归一化。
  4. 逐个处理 assets/ 下素材:
    • 计算 SHA-256。
    • 如果素材表中已有相同 SHA-256,复用已有素材 ID。
    • 否则调用素材导入逻辑写入 assets 表 + 文件系统。
  5. document.json 中的包内 assetId 重新映射为真实素材 ID。
  6. 保存为新的 design_documents
  7. 可选:把 preview.png 作为模板封面。
  8. 返回新设计/模板 ID。

6. 与现有模板系统的关系

当前模板保存是把 CanvasDocumentreference_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.jsondocument.jsonassets/
  • 支持导出当前画布或模板。
  • 支持解压导入,只处理贴纸素材和画布布局。
  • 不处理字体,不生成 preview。

阶段二:导入体验完善

  • 生成 preview.png
  • 导入时检查素材缺失。
  • 支持同一设计重复导入去重。

阶段三:与 PostgreSQL 打通

  • POST /api/designs/import 最终写入 design_documents
  • 素材导入自动写入 assets 表。
  • 导出接口直接读取 design_documentsassets,不再依赖前端状态。

9. 相关文件参考

  • frontend/src/lib/svgExport.ts:当前图层 ZIP 导出。
  • frontend/src/lib/templateLibrary.ts:当前模板保存/读取。
  • frontend/src/lib/canvasDocument.tsCanvasDocument 模型与归一化。
  • frontend/src/types.tsCanvasDocumentStickerAsset 等类型。
  • backend/service/app.py:当前 /api/assets/api/design-templates 接口。
  • docs/DESIGN_DATA_STORAGE_PLAN.md:存储层重构后文档落库设计。