- README: 移除开发中标记,更新功能列表 - CHANGELOG: 添加 v1.4.0 版本记录 - HANDOFF: 更新版本历史 - gitignore: 添加 *.bak 排除临时备份 - 代码注释: 掏窟窿 -> 透明区域 RGB 数据丢失
581 lines
21 KiB
Markdown
581 lines
21 KiB
Markdown
# InpaintRegionEditor 项目交接文档
|
||
|
||
> 版本:1.4 | 日期:2026-03-03
|
||
> 交接对象:开发团队
|
||
> 交接人:项目经理 Agent
|
||
|
||
---
|
||
|
||
## 一、项目概述
|
||
|
||
### 1.1 项目定位
|
||
|
||
**InpaintRegionEditor** 是一个 ComfyUI 自定义节点,用于解决局部重绘(inpaint)工作流中的两个核心问题:
|
||
|
||
1. **图像编辑**:ComfyUI 自身没有图像编辑功能,需要集成 Photopea 实现液化、仿制图章等 PS 级功能
|
||
2. **蒙版编辑**:支持羽化效果的蒙版编辑,使用 Photopea 双图层模式
|
||
3. **选区调整**:原有的扩散选区功能无法手动调整位置,导致边缘参考区域错误
|
||
|
||
### 1.2 核心价值
|
||
|
||
```
|
||
原工作流痛点:
|
||
├─ 蒙版编辑:ComfyUI 自带工具功能有限,无法处理复杂蒙版(羽化、透明度等)
|
||
├─ 图像编辑:完全没有,需要外部 PS 处理后再上传
|
||
└─ 选区调整:只能中心扩散,无法手动移动位置
|
||
|
||
本节点解决方案:
|
||
├─ 集成 Photopea:完整的 Photoshop 功能,浏览器内完成编辑
|
||
├─ 双模式编辑:编辑图像 / 编辑蒙版(分离操作)
|
||
├─ 羽化支持:半透明蒙版自动转换为羽化效果
|
||
├─ 可拖动选区:手动调整参考区域位置,确保参考内容准确
|
||
└─ 一体化流程:上传 → 编辑 → 选区调整 → 执行,无需切换工具
|
||
```
|
||
|
||
### 1.3 节点功能
|
||
|
||
```
|
||
输入:
|
||
- image: 从 ComfyUI input 目录选择(支持上传、Ctrl+V 粘贴)
|
||
- padding: 扩散像素数(默认 64,范围 0-512)
|
||
|
||
自动处理:
|
||
1. 读取图像 Alpha 通道作为 MASK
|
||
2. 没有 Alpha → 报错 "请先创建蒙版"
|
||
3. 有 Alpha → 计算蒙版边界框(alpha < 255 都计入)
|
||
4. 选区 = 蒙版边界 + padding
|
||
5. 在图像预览上绘制遮罩 + 选区框(可拖动、可调整大小)
|
||
|
||
用户操作:
|
||
- 右键 → "编辑图像(Photopea)":编辑图像本身
|
||
- 右键 → "编辑蒙版(Photopea)":双图层蒙版编辑(参考图像 + 蒙版层)
|
||
- 右键 → "Open in MaskEditor":使用 ComfyUI 自带蒙版编辑器
|
||
- 拖动选区框:手动调整参考区域位置
|
||
- 调整选区边缘:拖动边缘/角落调整选区大小
|
||
- 调整 padding 值:改变扩散像素数
|
||
- Ctrl+V:粘贴图片
|
||
|
||
输出:
|
||
- IMAGE: RGB 图像(不含 Alpha)
|
||
- MASK: 从 Alpha 通道提取
|
||
- region_top, region_left, region_width, region_height: 选区坐标
|
||
```
|
||
|
||
---
|
||
|
||
## 二、核心需求确认
|
||
|
||
### 2.1 蒙版来源(三种)
|
||
|
||
1. **用户上传**:带 Alpha 通道的 PNG 文件
|
||
2. **Photopea 编辑**:在 Photopea 里绘制蒙版后保存
|
||
3. **系统工具**:使用 ComfyUI 自带蒙版工具绘制后保存
|
||
|
||
### 2.2 核心逻辑
|
||
|
||
```python
|
||
if 没有蒙版(Alpha 通道):
|
||
执行时报错:"请先创建蒙版(局部重绘需要蒙版)"
|
||
else:
|
||
自动计算选区 = 蒙版边界 + padding
|
||
在预览上绘制遮罩(半透明红)+ 选区框(橙色虚线)
|
||
用户可以拖动选区框位置
|
||
输出 region_* 坐标
|
||
```
|
||
|
||
### 2.3 选区概念
|
||
|
||
| 概念 | 定义 | 作用 |
|
||
|------|------|------|
|
||
| **遮罩 (Mask)** | 需要重绘的区域(可能是不规则形状) | AI 在这个区域内生成新内容 |
|
||
| **选区 (Region)** | 参考区域(矩形框) | AI 参考这个区域内的原图内容进行重绘 |
|
||
|
||
**约束**:选区必须 >= 遮罩(选区要完全包含遮罩)
|
||
|
||
**选区计算逻辑**:
|
||
```
|
||
选区边界 = 遮罩边界框 + padding(向四周扩散)
|
||
用户可拖动选区位置,但选区必须始终框住遮罩
|
||
```
|
||
|
||
---
|
||
|
||
## 三、技术架构
|
||
|
||
### 3.1 文件结构
|
||
|
||
```
|
||
ComfyUI-InpaintRegionEditor/
|
||
├── __init__.py # 节点注册
|
||
├── nodes.py # 后端节点逻辑
|
||
├── requirements.txt # 无额外依赖
|
||
│
|
||
├── web/
|
||
│ ├── extension.js # 扩展入口 + 右键菜单
|
||
│ ├── photopea-bridge.js # Photopea 通信桥接
|
||
│ ├── photopea-modal.js # Photopea 全屏对话框
|
||
│ ├── region-box-editor.js # 选区框编辑器(Canvas + 拖动)
|
||
│ └── style.css # 样式
|
||
│
|
||
└── docs/
|
||
├── technical-validation.md # 技术验证清单
|
||
├── implementation-plan.md # 详细实现方案
|
||
└── HANDOFF.md # 本文档
|
||
```
|
||
|
||
### 3.2 整体架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ ComfyUI 前端 │
|
||
├─────────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌───────────────────────────────────────────────────────────────┐ │
|
||
│ │ InpaintRegionEditor 节点 │ │
|
||
│ │ │ │
|
||
│ │ ┌───────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ 图像预览区域 │ │ │
|
||
│ │ │ ┌───────────────────────────────────────────────┐ │ │ │
|
||
│ │ │ │ [图像] │ │ │ │
|
||
│ │ │ │ ┌──────────────┐ │ │ │ │
|
||
│ │ │ │ │ ████████████ │ ← 遮罩(半透明红) │ │ │ │
|
||
│ │ │ │ │ │ │ │ │ │ │ │
|
||
│ │ │ │ │ │ 虚线框 │ │ ← 选区(橙色虚线,可拖动) │ │ │ │
|
||
│ │ │ │ │ │ │ │ │ │ │ │
|
||
│ │ │ │ │ ████████████ │ │ │ │ │
|
||
│ │ │ │ └──────────────┘ │ │ │ │
|
||
│ │ │ └───────────────────────────────────────────────┘ │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ 控件: │ │ │
|
||
│ │ │ - 图像:[image.png ▼] [上传] │ │ │
|
||
│ │ │ - 扩散像素:[64] ▼ │ │ │
|
||
│ │ │ - [🎨 打开 Photopea 编辑] │ │ │
|
||
│ │ └───────────────────────────────────────────────────────┘ │ │
|
||
│ └───────────────────────────────────────────────────────────────┘ │
|
||
│ ↕ │
|
||
│ 隐藏 widget: region_coords (JSON) │
|
||
│ ↕ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
↕
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ ComfyUI 后端 │
|
||
├─────────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ nodes.py: InpaintRegionEditor.process() │
|
||
│ 1. 加载图像(从 input 目录) │
|
||
│ 2. 提取 Alpha 通道 → MASK │
|
||
│ 3. 计算遮罩边界框 │
|
||
│ 4. 计算选区 = 遮罩边界 + padding │
|
||
│ 5. 验证:选区 >= 遮罩 │
|
||
│ 6. 输出:IMAGE, MASK, region_* │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
↕
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Photopea │
|
||
├─────────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ - 通过 iframe 嵌入(全屏模态框) │
|
||
│ - postMessage API 通信 │
|
||
│ - 功能:图像编辑 + 蒙版绘制 │
|
||
│ - 导出:PNG 图像 + 黑白蒙版图 │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.3 数据流
|
||
|
||
```
|
||
1. 用户上传图像
|
||
└─▶ POST /upload/image → input/image.png
|
||
|
||
2. 节点加载图像
|
||
└─▶ 读取 Alpha 通道 → MASK
|
||
└─▶ 计算遮罩边界 → 选区
|
||
└─▶ 前端绘制:遮罩 + 选区框
|
||
|
||
3. 用户编辑(可选)
|
||
└─▶ 右键 → 打开 Photopea
|
||
└─▶ 编辑图像/蒙版
|
||
└─▶ 保存 → 上传新文件
|
||
└─▶ 更新节点 widget.value
|
||
|
||
4. 用户调整选区(可选)
|
||
└─▶ 拖动选区框
|
||
└─▶ 更新 region_coords (hidden widget)
|
||
|
||
5. 执行工作流
|
||
└─▶ 后端读取图像 + region_coords
|
||
└─▶ 输出:IMAGE, MASK, region_*
|
||
```
|
||
|
||
---
|
||
|
||
## 四、关键技术点
|
||
|
||
### 4.1 蒙版处理
|
||
|
||
**提取逻辑**(nodes.py):
|
||
```python
|
||
if 'A' in img.getbands():
|
||
mask = np.array(img.getchannel('A')).astype(np.float32) / 255.0
|
||
mask = 1.0 - mask # ComfyUI 约定:1=遮罩区域,0=背景
|
||
else:
|
||
raise ValueError("请先创建蒙版")
|
||
```
|
||
|
||
**格式约定**:
|
||
- PNG Alpha = 0(透明) → mask = 1.0(遮罩区域)
|
||
- PNG Alpha = 255(不透明) → mask = 0.0(背景)
|
||
|
||
### 4.2 选区计算
|
||
|
||
```python
|
||
def _calculate_region_rect(mask_bounds, padding):
|
||
"""根据遮罩边界 + padding 计算选区"""
|
||
return {
|
||
'x': mask_bounds['x'] - padding,
|
||
'y': mask_bounds['y'] - padding,
|
||
'width': mask_bounds['width'] + padding * 2,
|
||
'height': mask_bounds['height'] + padding * 2
|
||
}
|
||
```
|
||
|
||
**约束验证**:
|
||
```python
|
||
if (region_rect['width'] < mask_bounds['width'] or
|
||
region_rect['height'] < mask_bounds['height']):
|
||
raise ValueError("选区必须 >= 遮罩")
|
||
```
|
||
|
||
### 4.3 Photopea 集成
|
||
|
||
**通信机制**:
|
||
```javascript
|
||
// 发送消息到 Photopea
|
||
photopeaWindow.postMessage('app.activeDocument.saveToOE("png");', "*");
|
||
|
||
// 接收响应(验证 origin)
|
||
window.addEventListener("message", (event) => {
|
||
if (event.origin !== "https://www.photopea.com") return;
|
||
// 处理响应...
|
||
});
|
||
```
|
||
|
||
**待验证功能**:
|
||
1. 能否单独导出蒙版?(`layer.mask` 已知返回 null)
|
||
2. 能否同时加载原图 + 蒙版?
|
||
3. 能否检测用户是否画了蒙版?
|
||
|
||
**参考 workaround**(DEVLOG 中提到):
|
||
```javascript
|
||
// 虽然 layer.mask 返回 null,但这行代码可能工作
|
||
doc.activeChannel = layer.mask;
|
||
doc.selection.selectAll();
|
||
doc.selection.copy();
|
||
```
|
||
|
||
### 4.4 选区框绘制
|
||
|
||
**参考实现**:`ComfyUI-Impact-Pack/js/mask-rect-area.js`
|
||
|
||
**核心功能**:
|
||
- 自定义 Canvas Widget
|
||
- 绘制遮罩(半透明红)
|
||
- 绘制选区框(橙色虚线)
|
||
- 鼠标拖动交互
|
||
- 同步坐标到 widget
|
||
|
||
---
|
||
|
||
## 五、待验证技术点
|
||
|
||
### 5.1 高优先级(决定方案可行性)
|
||
|
||
| 编号 | 测试项 | 目的 | 状态 |
|
||
|------|-------|------|------|
|
||
| P1 | Photopea 同时加载原图 + 蒙版 | 确定工作流 | ❓ 待测试 |
|
||
| P2 | Photopea 单独导出蒙版 | 确定保存逻辑 | ❓ 待测试 |
|
||
| P3 | Photopea 检测是否有蒙版 | 确定错误提示 | ❓ 待测试 |
|
||
|
||
### 5.2 中优先级(影响用户体验)
|
||
|
||
| 编号 | 测试项 | 目的 | 状态 |
|
||
|------|-------|------|------|
|
||
| M1 | Canvas 选区框绘制 | 参考 Impact-Pack | ✅ 有参考代码 |
|
||
| M2 | 拖动交互实现 | 鼠标事件监听 | ✅ 有参考代码 |
|
||
| M3 | 坐标同步机制 | hidden widget | ✅ 已验证 |
|
||
|
||
### 5.3 低优先级(可迭代优化)
|
||
|
||
| 编号 | 测试项 | 目的 | 状态 |
|
||
|------|-------|------|------|
|
||
| L1 | 两次导出上传 | 图像 + 蒙版分开保存 | ❓ 待测试 |
|
||
| L2 | 后端合成 PNG | 两张图合成带 Alpha 的 PNG | ✅ 简单 |
|
||
| L3 | UI 样式优化 | 美观度提升 | - 后期 |
|
||
|
||
---
|
||
|
||
## 六、实现路线图
|
||
|
||
### Phase 1:后端基础(1 天)
|
||
|
||
**任务**:
|
||
- [ ] 更新 `nodes.py` 实现核心逻辑
|
||
- [ ] 测试蒙版提取(从 Alpha 通道)
|
||
- [ ] 测试选区计算(遮罩边界 + padding)
|
||
- [ ] 测试错误提示(没有蒙版时报错)
|
||
|
||
**交付物**:
|
||
- 可运行的后端节点
|
||
- 单元测试脚本
|
||
|
||
### Phase 2:选区 UI(2 天)
|
||
|
||
**任务**:
|
||
- [ ] 实现 `region-box-editor.js`
|
||
- [ ] 在节点上绘制遮罩预览
|
||
- [ ] 在节点上绘制选区框(虚线)
|
||
- [ ] 实现拖动交互
|
||
- [ ] 约束验证(选区 >= 遮罩)
|
||
|
||
**参考**:`ComfyUI-Impact-Pack/js/mask-rect-area.js`
|
||
|
||
**交付物**:
|
||
- 可在节点上显示并拖动选区框
|
||
|
||
### Phase 3:Photopea 集成(2-3 天)
|
||
|
||
**任务**:
|
||
- [ ] 实现 `photopea-modal.js`
|
||
- [ ] 实现 `photopea-bridge.js`
|
||
- [ ] 测试图像加载(`&channel=rgb` 参数)
|
||
- [ ] 测试图像导出
|
||
- [ ] **测试蒙版导出**(关键!)
|
||
- [ ] 上传回 ComfyUI
|
||
|
||
**交付物**:
|
||
- 可打开 Photopea 编辑
|
||
- 可保存回节点
|
||
|
||
### Phase 4:集成测试(1 天)
|
||
|
||
**任务**:
|
||
- [ ] 完整工作流测试
|
||
- [ ] 修复 bug
|
||
- [ ] 编写 README
|
||
|
||
**交付物**:
|
||
- 可发布的完整版本
|
||
|
||
---
|
||
|
||
## 七、已知风险与备选方案
|
||
|
||
### 7.1 Photopea API 限制
|
||
|
||
**问题**:`layer.mask` 总是返回 `null`(官方已知,Issue #7341)
|
||
|
||
**影响**:无法通过脚本访问图层蒙版
|
||
|
||
**备选方案**:
|
||
1. 用 workaround 尝试导出(`doc.activeChannel = layer.mask`)
|
||
2. 如果不行,用户只能用其他方式创建蒙版(系统工具/上传)
|
||
3. 或者在 Photopea 里手动合成到 Alpha 通道后导出
|
||
|
||
### 7.2 蒙版语义差异
|
||
|
||
**问题**:
|
||
- Photopea 蒙版:白色 = 显示(非遮罩),黑色 = 隐藏(遮罩)
|
||
- ComfyUI Mask:白色 = 遮罩区域,黑色 = 背景
|
||
|
||
**解决**:导出时反转
|
||
|
||
### 7.3 性能问题
|
||
|
||
**问题**:大图片(>2048x2048)可能导致 Photopea 卡顿
|
||
|
||
**解决**:
|
||
- 提示用户使用合适尺寸
|
||
- 可选:前端缩放后编辑
|
||
|
||
---
|
||
|
||
## 八、参考资源
|
||
|
||
### 8.1 代码参考
|
||
|
||
| 文件 | 位置 | 用途 |
|
||
|------|------|------|
|
||
| `mask-rect-area.js` | `E:\ComfyUI\custom_nodes\ComfyUI-Impact-Pack\js\` | 选区框绘制参考 |
|
||
| `nodes.py` (LoadImage) | `E:\ComfyUI\nodes.py` (line 1702) | 图像加载参考 |
|
||
| `server.py` | `E:\ComfyUI\server.py` | 上传 API 参考 |
|
||
|
||
### 8.2 文档参考
|
||
|
||
| 文档 | 说明 |
|
||
|------|------|
|
||
| [Photopea API](https://www.photopea.com/api/) | 官方 API 文档 |
|
||
| [technical-validation.md](./technical-validation.md) | 技术验证清单 |
|
||
| [implementation-plan.md](./implementation-plan.md) | 详细实现方案 |
|
||
| [DEVLOG.md](../DEVLOG.md) | 开发日志(包含历史问题记录) |
|
||
|
||
### 8.3 外部参考
|
||
|
||
| 项目 | 说明 |
|
||
|------|------|
|
||
| [sd-webui-photopea-embed](https://github.com/yankooliveira/sd-webui-photopea-embed) | Stable Diffusion WebUI 的 Photopea 集成 |
|
||
| [ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack) | 选区框实现参考 |
|
||
|
||
---
|
||
|
||
## 九、团队协作建议
|
||
|
||
### 9.1 分工建议
|
||
|
||
**后端开发**(1 人):
|
||
- `nodes.py` 实现
|
||
- 蒙版提取逻辑
|
||
- 选区计算逻辑
|
||
|
||
**前端开发**(1 人):
|
||
- Canvas 选区框绘制
|
||
- 拖动交互实现
|
||
- Photopea 集成
|
||
|
||
**测试**(1 人):
|
||
- Photopea 功能验证
|
||
- 完整工作流测试
|
||
- Bug 报告
|
||
|
||
### 9.2 沟通要点
|
||
|
||
1. **Photopea 验证结果** 决定技术路线
|
||
- 如果能单独导出蒙版 → 方案 A
|
||
- 如果不能 → 方案 B(用户手动合成到 Alpha)
|
||
|
||
2. **选区 UI 复杂度** 可能被低估
|
||
- 建议先用 Impact-Pack 代码验证可行性
|
||
- 再考虑自定义需求
|
||
|
||
3. **错误提示要友好**
|
||
- 没有蒙版时告诉用户三种创建方式
|
||
- 选区太小时提示最小尺寸
|
||
|
||
---
|
||
|
||
## 十、验收标准
|
||
|
||
### 10.1 功能验收
|
||
|
||
- [ ] 用户上传带 Alpha 的 PNG → 正确显示遮罩 + 选区
|
||
- [ ] 用户上传不带 Alpha 的 PNG → 执行时报错(友好提示)
|
||
- [ ] 拖动选区框 → 坐标实时更新
|
||
- [ ] 调整 padding → 选区自动重算
|
||
- [ ] 打开 Photopea → 可以编辑图像
|
||
- [ ] Photopea 保存 → 图像同步到节点
|
||
- [ ] 输出 region_* → 下游节点可用
|
||
|
||
### 10.2 性能验收
|
||
|
||
- [ ] 加载 1024x1024 图像 < 2 秒
|
||
- [ ] 拖动选区框流畅(60fps)
|
||
- [ ] Photopea 打开 < 5 秒(首次加载缓存后)
|
||
|
||
### 10.3 兼容性验收
|
||
|
||
- [ ] Windows / Linux / macOS
|
||
- [ ] Chrome / Firefox / Edge
|
||
- [ ] ComfyUI 最新版本
|
||
|
||
---
|
||
|
||
## 十一、联系与反馈
|
||
|
||
### 11.1 问题记录
|
||
|
||
开发过程中遇到的任何问题,请记录到:
|
||
- `docs/DEVLOG.md`(开发日志)
|
||
- GitHub Issues(如果有仓库)
|
||
|
||
### 11.2 关键决策记录
|
||
|
||
任何偏离本方案的技术决策,请记录:
|
||
- 决策内容
|
||
- 决策原因
|
||
- 决策日期
|
||
|
||
---
|
||
|
||
## 十二、附录
|
||
|
||
### 12.1 术语表
|
||
|
||
| 术语 | 定义 |
|
||
|------|------|
|
||
| **Mask(遮罩)** | 定义重绘区域,AI 在这个区域内生成新内容 |
|
||
| **Region(选区)** | 定义参考区域,AI 参考这个区域内的原图内容 |
|
||
| **Padding(扩散)** | 选区相对于遮罩边界的扩散像素数 |
|
||
| **Alpha 通道** | PNG 的透明度通道,用于存储蒙版 |
|
||
| **羽化** | 蒙版边缘的半透明过渡效果(alpha = 1-254) |
|
||
|
||
### 12.2 版本历史
|
||
|
||
| 版本 | 日期 | 说明 |
|
||
|------|------|------|
|
||
| 0.1 | 2026-02-27 | 初始版本(简化版,仅 Photopea 集成) |
|
||
| 1.0 | 2026-03-02 | 需求最终确认,编写 handoff 文档 |
|
||
| 1.1 | 2026-03-03 | Photopea 蒙版编辑功能,修复透明区域 RGB 数据丢失问题 |
|
||
| 1.2 | 2026-03-03 | 选区调整大小、光标变化、Ctrl+V 粘贴、MaskEditor 集成 |
|
||
| 1.3 | 2026-03-03 | MaskEditor clipspace 支持、选区坐标同步、羽化效果 |
|
||
| 1.4 | 2026-03-03 | 多语言支持(中英文)、修复编辑图像透明区域 RGB 数据丢失、修复选区坐标自动更新 |
|
||
|
||
---
|
||
|
||
## 十三、关键技术实现
|
||
|
||
### 13.1 Canvas Premultiplied Alpha 问题
|
||
|
||
**问题描述**:
|
||
当 Canvas 通过 `drawImage()` 绘制带有 Alpha < 255 的 PNG 图像时,浏览器会应用 **premultiplied alpha**,导致 Alpha = 0 的像素 RGB 数据丢失。
|
||
|
||
**解决方案**:
|
||
1. **加载时**:使用 ComfyUI `/view` API 的 `channel=rgb` 和 `channel=a` 参数分别获取 RGB 和 Alpha 数据
|
||
2. **保存时**:使用 UPNG.js 库直接编码 RGBA 数据,绑过 Canvas 的 premultiplied alpha
|
||
|
||
### 13.2 Photopea 蒙版编辑流程
|
||
|
||
```
|
||
1. 加载图像
|
||
├─ 获取 RGB 数据(channel=rgb)→ 完整 RGB,无窟窿
|
||
└─ 获取 Alpha 数据(channel=a)→ 用于创建蒙版层
|
||
|
||
2. 创建双图层文档
|
||
├─ 底层:参考图像(完整 RGB)
|
||
└─ 顶层:蒙版层(用户在此绘制黑色 = 遮罩)
|
||
|
||
3. 保存蒙版
|
||
├─ 隐藏参考图像层
|
||
├─ 只导出蒙版层
|
||
├─ 获取原图 RGB(channel=rgb)
|
||
└─ 合并蒙版到 Alpha 通道(UPNG.js 编码)
|
||
```
|
||
|
||
### 13.3 羽化逻辑
|
||
|
||
```
|
||
蒙版层(用户绘制):
|
||
- 黑色不透明(alpha=255)→ 遮罩 → 最终 alpha=0
|
||
- 黑色半透明(alpha=128)→ 羽化 → 最终 alpha=128
|
||
- 完全透明(alpha=0)→ 不遮罩 → 最终 alpha=255
|
||
|
||
公式:最终 alpha = 255 - 蒙版层alpha
|
||
```
|
||
|
||
---
|
||
|
||
*文档创建时间:2026-03-02*
|
||
*最后更新时间:2026-03-03*
|
||
*基于与用户的多次讨论整理*
|
||
*交接完成标志:开发团队确认收到并理解本文档*
|