Enhance image editing tests and functionality

- Added parameterized tests for image edit replacement to ensure alpha mode preservation.
- Refactored existing tests to utilize new image editing methods and improve clarity.
- Introduced new tests for image target functionality, ensuring proper handling of shared textures and context.
- Updated various tests to validate alpha mode handling across different scenarios.
- Improved undo/redo functionality in image operators to maintain state consistency.
- Added support for texture node actions, enhancing integration with Blender's node system.
- Ensured that image properties are preserved during operations and that invalid contexts are handled gracefully.
This commit is contained in:
2026-09-10 00:00:13 +08:00
parent f48bbb3d05
commit 1622afa7a2
28 changed files with 1068 additions and 236 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-09

View File

@@ -0,0 +1,55 @@
## Context
现有菜单挂载于对象右键菜单,两个 AI 操作通过 Empty 取得 Image 和播放设置。`common/image.py` 已提供输入准备、结果打包、Image 内容快照和恢复;现有共享判定专用于 Empty。动机见 proposal.md。
## Goals / Non-Goals
本设计围绕材质 Shader Editor 的 Image Texture 节点完成图片输入、异步目标定位和原位提交;Empty 的现有行为作为回归基线。
## Decisions
### 菜单按编辑器和当前节点确定目标
在 `NODE_MT_context_menu` 注册回调,以材质 Shader Editor、当前编辑树、活动 Image Texture 节点及有效 Image 为显示条件。支持进入材质节点组和固定材质后的编辑上下文,节点编辑器中的无效目标直接判为不可用。新增 `AnyImageTextureNodeMenu`,包含两个图片操作及现有 AI 设置入口;Upscale 标签使用目标图片尺寸。注册与逆序注销对称。
### 在 common 中集中处理图片编辑目标
新增职责明确的 `common/image_target.py`,统一取得源 Image、ImageUser、目标校验与结果提交分派。复用两个现有 Operator 和服务端 Job;将结果加载中对 `source_object.data` 的依赖改为显式 Image 参数,并同步修改真实调用点。Empty 特有的显示对齐和共享规则仍由现有提交函数负责,节点提交复用 Image 内容事务函数。
```mermaid
flowchart TD
A[节点右键选择操作] --> B[解析并捕获节点和源 Image]
B --> C[复用输入准备与 AI Job]
C --> D[主线程验证原目标仍有效]
D --> E[加载并打包处理结果]
E --> F{源图有其他实际使用者}
F -->|有| G[当前节点绑定独立结果]
F -->|无| H[保留 Image 身份并更新内容]
G --> I[完成撤销记录和临时资源清理]
H --> I
```
### 捕获提交时的节点身份
在主线程捕获编辑树、节点与源 Image 的运行期身份,以及节点 ImageUser 播放参数。响应在主线程使用捕获目标,校验节点仍属于原树且仍绑定源图;名称只用于提示,防止删除后同名重建误命中。运行期引用仅保存在本地任务状态,Job 请求使用路径、帧参数等普通字典数据。切换活动节点不改变目标;目标删除、源绑定变化或变为只读时报告错误并清理结果。
### 原位替换保留节点结构并隔离共享图片
节点独占 Image 时复用内容快照与恢复,保留 Image 身份、名称和 Fake User;存在其他实际 Image 使用者时,仅当前节点绑定新结果,保留原图。共享判定覆盖其他节点树、Empty 和其他数据使用者,忽略 Fake User、编辑器显示和本次临时持有;在响应提交时计算。该规则仅用于节点目标。
保持节点位置、插值、投影、扩展方式和连线。结果继承源色彩空间并使用现有 alpha 配置;去背景输出透明图片,材质的 Alpha 连线和渲染设置由用户已有材质决定。动画输入沿用现有处理帧数约定,起始帧和播放设置从节点 ImageUser 读取,结果序列以同样时间位置播放。
### 失败恢复和撤销采用完整提交边界
节点提交覆盖 Image 内容、绑定和 ImageUser 设置的快照、恢复与清理。沿用两个操作现有撤销入口,验证异步成功仅产生一个有效图片编辑撤销步骤,重做恢复结果且无需再次推理。
## Risks / Trade-offs
- [节点组被多个材质实例使用] → 编辑共享节点树内的节点会作用于所有该组实例,遵循 Blender 节点树共享语义;图片隔离以节点身份为边界。
- [共享判定遗漏其他 Image 使用者] → 结合实际数据引用校验,测试跨材质、跨节点组、Empty 及 Fake User 情况。
- [异步完成时上下文已变化] → 使用捕获的运行期身份并在提交前验证;覆盖改名、删除和重新绑定图片。
- [Image 内容原位修改的撤销与打包行为] → 使用真实 Blender 测试验证撤销重做、保存重开、动画和失败恢复。
## Migration Plan
先集中目标解析与图片结果加载,再接入菜单和节点提交,最后完成注册、回归及 Blender 验证。无需数据迁移;回退代码后,已有处理结果继续作为普通 Image 使用。

View File

@@ -0,0 +1,24 @@
## Why
材质的 Image Texture 节点目前无法直接使用 AnyImage 去背景和放大。用户需要在节点右键菜单中完成处理,并像 Empty Image 一样在当前位置使用结果。
## What Changes
- 在材质 Shader Editor 的有效 Image Texture 节点右键菜单增加 AnyImage 菜单,提供 Remove Background 和 Upscale。
- 复用现有 AI 环境准备、模型配置、输入限制、任务进度和图片处理流程。
- 处理成功后原位更新目标节点图片,保留节点、连线及设置;单独使用的图片保留 Image 身份,共享图片仅替换当前节点的绑定。
- 为异步目标校验、失败恢复、撤销重做和菜单注册增加覆盖。
## Capabilities
### New Capabilities
- `texture-node-image-actions`: 材质 Image Texture 节点的 AI 图片操作入口及原位提交语义。
### Modified Capabilities
无。
## Impact
涉及 `src/anyimage/menu.py`、扩展注册入口、Remove Background / Upscale Operator、`common` 图片输入与提交逻辑及对应测试。服务端沿用现有 Job 协议,依赖和节点资产保持现状。

View File

@@ -0,0 +1,85 @@
## Purpose
为材质 Shader Editor 中的 Image Texture 节点提供直接去背景与放大的操作入口,让用户在现有节点位置使用处理结果,并明确共享图片、异步完成和撤销恢复的可见行为。
## ADDED Requirements
### Requirement: Material image texture context actions
系统 SHALL 在材质 Shader Editor 中为具有有效图片的活动 Image Texture 节点提供 AnyImage 右键菜单,包含 Remove Background 和 Upscale;一次操作 SHALL 处理当前节点。
#### Scenario: An image texture is active
- **WHEN** 用户在材质编辑上下文中对有图片的活动 Image Texture 节点打开右键菜单
- **THEN** 菜单提供两项操作,Upscale 显示预期 2× 输出尺寸
#### Scenario: The target is unavailable
- **WHEN** 当前上下文为 World、Compositor、Geometry Nodes,或活动节点不是 Image Texture、没有图片、不可编辑
- **THEN** 系统不提供可执行的节点图片操作,且不使用活动 Empty 作为替代目标
#### Scenario: A material or node group is being edited
- **WHEN** 用户固定材质或进入其节点组并对有效 Image Texture 发起操作
- **THEN** 系统处理该编辑树内的目标节点图片
### Requirement: Existing AI processing settings apply
系统 SHALL 沿用 Empty Image 操作的 AI 环境准备、模型选择、任务状态和输入限制;Upscale SHALL 使用当前模型输出 2× 结果。
#### Scenario: Environment preparation is needed
- **WHEN** 用户点击操作且 AI 环境或模型尚未准备好
- **THEN** 系统进入现有准备流程
#### Scenario: Upscale is unavailable
- **WHEN** 服务忙碌或图片长边达到当前最大 AI 输入尺寸
- **THEN** Upscale 不可执行;服务忙碌时 Remove Background 也不可执行
#### Scenario: An animated texture is processed
- **WHEN** 目标图片为现有流程支持的视频或序列
- **THEN** 系统依据节点播放设置和现有处理帧数约定取得输入,结果序列保留对应播放时间位置
### Requirement: Results replace the image at the target node
系统 SHALL 在成功后保留目标节点、位置、连线和纹理设置,并在该节点使用结果图片。源图独占时 SHALL 保留 Image 身份、名称与 Fake User;源图有其他实际使用者时 SHALL 仅替换当前节点图片绑定并保持其他使用者和原图不变。结果 SHALL 继承源色彩空间、正确保存透明信息并支持保存重开。
#### Scenario: A sole image is processed
- **WHEN** 目标节点独占源图并完成去背景或放大
- **THEN** 原 Image 内容及尺寸更新为结果,身份和名称保留,临时结果被释放
#### Scenario: Other users share the image
- **WHEN** 另一纹理节点或 Empty 等数据使用者仍引用源图
- **THEN** 当前节点使用独立处理结果,其他使用者继续使用未改变的原图
#### Scenario: Only a fake user is present
- **WHEN** 源图除当前节点外只有 Fake User 或编辑器显示引用
- **THEN** 系统保留源 Image 身份并更新内容
#### Scenario: Background removal succeeds
- **WHEN** 用户对节点执行 Remove Background 成功
- **THEN** 图片带有处理后的透明信息,材质原有连线和渲染设置保留
### Requirement: Asynchronous completion keeps the original target
系统 SHALL 将结果提交到发起任务时的节点,并在提交前验证原节点和图片绑定仍有效。
#### Scenario: Active selection changes
- **WHEN** 处理期间用户切换编辑器、材质或活动节点
- **THEN** 结果仍提交到原节点
#### Scenario: The target is renamed
- **WHEN** 原节点或所属材质在任务期间改名且绑定仍有效
- **THEN** 结果提交到同一原节点
#### Scenario: The original target is invalid
- **WHEN** 原节点被删除、同名重建、变为只读或改绑图片
- **THEN** 系统报告目标失效,保留现有节点和图片状态,并清理本次结果
### Requirement: Edits support failure recovery and undo
系统 SHALL 在失败或取消时保持或恢复原图片内容、节点绑定和播放设置,并清理临时资源。成功操作 SHALL 支持一次撤销还原及重做恢复。
#### Scenario: Commit fails
- **WHEN** 写入图片内容或绑定、配置播放设置期间发生错误
- **THEN** 节点绑定与原图完整恢复,其他使用者保持不变
#### Scenario: The user undoes and redoes an edit
- **WHEN** 用户撤销一次成功操作,然后重做
- **THEN** 撤销恢复原图、尺寸、绑定和播放设置,重做恢复处理结果且无需再次推理

View File

@@ -0,0 +1,20 @@
## 1. 图片编辑目标
- [x] 1.1 在 common 集中解析 Empty 与材质纹理节点目标,捕获源 Image、编辑树身份和播放参数;测试材质固定、节点组编辑、无效上下文和节点改名。
- [x] 1.2 将图片结果加载改为显式 Image 输入并更新真实调用点;通过现有 Empty 图片处理测试,检查旧调用签名无残留。
## 2. 原位提交与任务接入
- [x] 2.1 实现节点图片事务提交,复用内容快照、恢复与打包;测试独占 Image 身份、Fake User、共享节点/Empty 隔离、连线设置保留及失败回滚。
- [x] 2.2 接入现有 Remove Background 和 Upscale 的目标解析、输入准备和响应;测试模型配置、2× 尺寸、输入限制、动画帧参数及任务清理。
- [x] 2.3 在异步响应中校验原树、节点及源绑定;测试切换选择后仍命中原目标,删除、同名重建和改绑图片时安全退出。
## 3. 右键菜单
- [x] 3.1 添加纹理节点 AnyImage 菜单,复用两项操作及 AI 设置入口,显示目标图片的 Upscale 尺寸;测试可见条件、服务忙碌及环境准备入口。
- [x] 3.2 接入节点菜单回调与菜单类型注册、逆序注销;通过注册测试验证重复启用与禁用没有遗留回调。
## 4. 综合验证
- [x] 4.1 使用真实 Blender 测试验证两项异步操作的撤销重做、图片打包保存重开、共享节点组实例与动画播放,确认透明结果及原节点结构正确。
- [x] 4.2 运行 `uv run pytest` 全量测试并确认正常退出,检查最终差异与旧引用;保留既有未提交修改,不构建文档或产物。