无限二创:图片节点工具设计¶
文档定位:唯一详设(product/canvas 仅一句概述)。对应实现:
src/infinitecanvas/;架构总览:infinitecanvas.md
1. 目标¶
在无限画布的图片节点上提供两类编辑能力:
- 本地交互编辑:裁剪、标注、画笔(用户可控、即时反馈)
- AI 图生图编辑:抠图、去水印、扩图、智能分层(参考原图 + 固定提示词)
xyflow 仅负责节点壳(选中、工具栏挂载、缩放);图像编辑为业务自研。
2. 工具一览¶
| 工具栏项 | action | 技术 | 结果落点 |
|---|---|---|---|
| 裁剪 | crop |
Konva 弹层 | 新建图片节点(源右侧 + 连线) |
| 标注 | editElements |
Konva(矩形 / 箭头 / 文字) | 同上 |
| 画笔 | brush |
Konva 笔触层 | 同上 |
| 抠图 | cutout |
POST /api/canvas/generate |
同上 |
| 智能分层 | smartLayer |
同上(并行两次) | 新建主体层 + 背景层(源右侧竖向紧贴 + 各连线) |
| 扩图 | outpaint |
同上 | 同上 |
| 去水印 | removeWatermark |
同上 | 同上 |
| 下载 / 放大 | download / expand |
浏览器 | 不改节点 |
| 加入 Agent | joinAgent |
AI 输入框引用 | 打开 Agent |
3. Konva 交互编辑¶
3.1 交互形态¶
点击裁剪 / 标注 / 画笔 → 全屏遮罩弹层(非节点内嵌),避免与 xyflow 拖拽冲突。
- 组件目录:
src/components/canvas/image-editor/ - 会话状态:
useImageToolActions中的konvaEditor - 弹层挂载:
CanvasProvider内渲染ImageKonvaEditorModal
3.2 完成写回¶
- Stage / 离屏 Canvas 导出
dataURL - 在源节点右侧新建图片节点(处理中占位),并连线
源 → 结果 uploadDataUrlAsAsset→ OSS(直传失败可走 backend 代传)registerCanvasAsset+updateImageNodeWithSize填充结果节点- 关闭弹层;失败时删除占位结果节点并
alert
不修改源图片节点。
3.3 跨域读图¶
展示用 <img src> 不要求 CORS;Konva/Canvas 读像素需要可导出位图:
resolveEditableImageUrl:先 CORS 直载,失败则POST /api/canvas/assets/proxy-image得 data URL
4. AI 抠图 / 去水印 / 扩图¶
4.1 池与上游¶
画布默认模型统一来自多模态池(text_to_multimodal);三项工具仍走生图 API(输出图片),不是 chat/completions:
- API:
POST /api/canvas/generate(默认池text_to_multimodal) mode:single(单张参考图)imageUrls:[源图 URL]prompt: 固定中文提示词(utils/ai-image-tool-prompts.ts)- 上游仍为 Nonlinear 图生图;池内需配置可生图的多模态模型
4.2 前端流程¶
runImageToolAction
→ 右侧新建结果节点(isProcessing + processingLabel)+ 连线
→ ensureHttpImageUrl(blob/data 先上传)
→ runAiImageTool → requestImageGeneration
→ pickGeneratedImageUrl → updateImageNodeWithSize(结果节点)
→ 失败则删除占位结果节点
- 不修改源图片节点
- 不再回退本地 Canvas 演示效果
- RunningHub 占位接口可保留,但不参与这三项调度
4.3 提示词原则(产品侧)¶
| 工具 | 意图要点 |
|---|---|
| 抠图 | 保留主体边缘,去背景,勿加水印文字 |
| 去水印 | 去 Logo/角标,保持主体与光影,勿改构图 |
| 扩图 | 四周扩展并自然补全,风格一致 |
| 智能分层 · 主体 | 提取主体,去背景 |
| 智能分层 · 背景 | 去除主体并自然补全背景 |
具体文案以代码中常量为准,便于迭代而不改接口。
4.4 智能分层(双结果)¶
与抠图等同池生图,但一次操作并行两次 requestImageGeneration:
runImageToolAction(smartLayer)
→ 右侧新建「主体层」「背景层」占位节点 + 各连线
→ 竖向紧贴排布(主体在上)
→ runSmartLayerSplit(并行 subject / background 提示词)
→ 各自 persist + updateImageNodeWithSize
→ 尺寸回写后再竖向紧贴
→ 失败则删除两个占位节点
- 不修改源图片节点
smartLayer不计入AI_IMAGE_TOOL_ACTIONS(单结果列表)
5. 与「我的资产」边界¶
| 操作 | 是否进「我的资产」 |
|---|---|
| 资产弹窗「本地上传」 | 是(只入库,不建节点) |
| 画布上传建节点 / Konva 保存 / AI 结果 | 否(仅画布 canvasAssets / 节点 imageUrl) |
| 右键「存到我的资产」 | 是(手动) |
6. 关键文件¶
| 路径 | 职责 |
|---|---|
components/canvas/ImageNodeToolbar.tsx |
工具栏 UI |
context/canvas/hooks/useImageToolActions.ts |
调度 |
components/canvas/image-editor/* |
Konva 弹层与 Stage |
utils/ai-image-tool.ts / ai-image-tool-prompts.ts |
AI 调用与提示词 |
utils/image-tool-processor.ts |
CORS 安全读图 |
utils/image-generation-api.ts |
生图 HTTP |
backend/api/canvas/router.py |
generate / assets/proxy-image |
7. 测试要点与验收记录¶
7.1 自动化(单元)¶
| 用例 | 文件 | 结果 |
|---|---|---|
| AI 工具识别与提示词 | tests/unit/utils/ai-image-tool.test.ts |
通过 |
runAiImageTool mock 生图 / dataURL 先上传 |
同上 | 通过 |
runSmartLayerSplit 并行双层 |
同上 | 通过 |
resolveEditableImageUrl 本地地址 |
tests/unit/utils/image-tool-processor.test.ts |
通过 |
fitImageToStage 缩放 |
tests/unit/utils/fit-image-to-stage.test.ts |
通过 |
7.2 接口冒烟(本地 backend + storage)¶
| 接口 | 预期 | 结果 |
|---|---|---|
GET /api/canvas/config |
200 + 模型列表 | 通过 |
POST /api/canvas/upload |
200 + url/object_key | 通过 |
POST /api/canvas/assets/proxy-image |
200 + data_url | 通过 |
POST /api/canvas/generate(single + 参考图) |
200 返回生成图 | 前端已发起;本地直连探测约 90s 超时(上游耗时/配额需单独确认) |
7.3 浏览器功能验收(localhost:5174,JWT 注入)¶
| 步骤 | 预期 | 结果 |
|---|---|---|
登录后进入 /canvas |
进入画布 | 通过 |
| 图片节点上传 | 出现图片节点与工具栏 | 通过(OSS 直传 CORS 失败时回退 /upload) |
| 点击「裁剪」 | Konva 弹层(标题裁剪 / 取消 / 完成) | 通过 |
| 弹层加载原图 | 经 proxy-image 后出现 Stage canvas |
通过 |
| 点击「完成」 | 弹层关闭并写回节点 | 通过 |
| 点击「标注」「画笔」 | 对应弹层打开,可取消 | 通过 |
| 点击「抠图」 | 节点显示「抠图中…」并请求 /generate |
通过;当前测试账号配额为 0,最终 alert「配额不足」——链路与错误提示正确 |
说明:
- OSS Bucket 未配浏览器 CORS 时,控制台会出现直传
Failed to fetch;代传与proxy-image已覆盖编辑路径。 - AI 三项出图还依赖画布生图池上游与用户配额;无配额时应明确提示,而非卡在处理中(当前会弹出配额错误)。
8. 非目标(本阶段)¶
- 不新建专用「图片编辑」后端资源接口(可后续薄封装计费/审计)
- 不替换整个 xyflow 画布为 Konva
- 不实现专业级蒙版/图层系统(标注为轻量矢量叠加)