Files
AnyImage/docs/internals/common.md
nan 1994d38ccd Add comprehensive tests for image processing and mask functionalities
- Introduced tests for color image handling, ensuring source preservation and premultiplied alpha usage.
- Implemented tests for brush stroke operations, validating segment boundaries and brush anti-aliasing.
- Added tests for frame anti-aliasing, confirming correct rendering behavior with various alpha values and depth settings.
- Created tests for frame projection, ensuring accurate overlap calculations and half-plane clipping.
- Developed tests for image premultiplied retention, verifying behavior during loading and packing processes.
- Added undo functionality tests for mask operations, ensuring single transaction behavior during edits.
2026-09-05 21:33:11 +08:00

127 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Common 公共函数
`src/anyimage/common/` 按 AI、Image、Selection、Viewport、Depth、Material、Object 和 Node 八个业务模块提供 Blender 侧复用能力。调用方直接从对应模块导入函数。
## Image 数据块
`image.py` 处理 Blender `Image` 数据块及其在 Image Empty 上的完整生命周期,包括像素读取、动画帧、Job 输入、结果 Image 创建和 Empty 引用替换。
| 函数 | 职责 |
| --- | --- |
| `image.is_image_empty()` | 判断对象是否为带有效 Image 数据的 Empty。 |
| `image.require_image_empty()` | 按名称取得 Image Empty;对象已失效时抛错。 |
| `image.image_pixels()` | 以 Blender 原始顺序读取一维 float32 像素。 |
| `image.image_rgba()` | 读取为 Top-down RGBA float32 数组。 |
| `image.homography_from_points()` | 求解四点之间的 Homography。 |
| `image.projective_output_size()` | 按源像素密度、目标宽高比和资源上限计算投影输出尺寸。 |
| `image.premultiplied_rgba()` | 将 Blender 顺序像素转换为 Top-down 预乘 Alpha RGBA。 |
| `image.sample_premultiplied_rgba()` | 在图片边界坐标中双线性采样预乘 Alpha RGBA,范围外返回透明。 |
| `image.straight_rgba()` | 转换为 straight RGBA,并把相邻可见 RGB 扩展到一圈透明边缘。 |
| `image.warp_projective_pixels()` | 将源 Quad 重采样为矩形 Blender Image 像素。 |
| `image.video_total_frames()` | 返回 Movie 或 Sequence 总帧数,静态图返回 1。 |
| `image.image_user_settings()` | 读取 Image Empty 的帧起点、偏移、时长和循环设置。 |
| `image.default_extract_frames()` | 取得当前 Empty 默认应处理的帧数。 |
| `image.source_start_frame()` | 从源 Image Empty 取得 Job 应处理的起始帧。 |
| `image.prepare_image_input()` | 将 Packed、Dirty、Sequence 等输入准备为 Job 可读路径,并返回临时标记。 |
| `image.prepare_image_bounds_input()` | 复用调用方已读取的 RGBA,按几何 bounds 写出保留原始 Alpha 的矩形 Job 输入。 |
| `image.cleanup_image_input()` | 清理由图片输入 helper 创建的临时文件或目录。 |
| `image.image_base_name()` | 去除图片或视频扩展名和 Blender 数字后缀,得到数据块基础名。 |
| `image.depth_data_name()` | 生成 Depth 结果数据块文件名。 |
| `image.color_data_name()` | 生成 Color 结果数据块文件名。 |
| `image.load_image_edit_result()` | 加载、Pack 并配置直接编辑源 Image 的 Job 结果,以源 Image 完整名称请求新数据块名称。 |
| `image.load_color_result_image()` | 加载、命名、Pack 并配置材质 Color 或 Sequence 结果;不修改 Empty。 |
| `image.load_normal_result_image()` | 加载、命名、设为 Non-Color 并 Pack Normal Map。 |
| `image.load_packed_rgba_image()` | 加载已有 RGBA 文件,继承源图颜色空间和 Alpha mode,命名并 Pack。 |
| `image.create_image_edit_result()` | 从本地编辑后的 RGBA 像素创建 Packed Image,以源 Image 完整名称请求新数据块名称;不修改 Empty。 |
| `image.replace_empty_image()` | 执行 Image Empty 结果替换、共享引用分流、旧数据清理、帧设置继承和可选画布对齐。 |
| `image.image_empty_bounds()` | 计算 Image Empty 在对象局部坐标中的实际显示边界。 |
Remove Background、Upscale、Frame、Mask 与 Rectify 都属于直接 Image 编辑,结果保留 active 或源 Image 数据块的完整名称,包括名称中的 `.png` 等格式文字。源数据仍被其他对象引用时,重名结果由 Blender 自动追加数字后缀;源数据可清理时,替换入口让结果恢复准确原名。`color_data_name()`、`depth_data_name()`、`normal_data_name()` 仅用于 Plane 与 Cutout 等材质派生贴图。
## Image Selection 与视图交互
这组公共能力使用固定术语:
- Selection 是用户在图片空间圈定的业务范围;`SelectionPath` 只保存路径点,并提供 JSON 编解码。
- `SelectionMask` 是 Selection 的纯几何栅格化结果,只包含局部像素权重 `values` 和源图几何 `bounds`。
- Mask 表示二维像素权重或 Alpha 运算。
`viewport.py` 处理 View3D 中的点击、坐标投影、`ImageGesture` 和 Overlay 绘制;它为 Lasso、Brush 与 Polyline 提供对应状态机,Brush 拖动阶段只维护简化后的屏幕路径及 Overlay、提交共用的圆形印记和连接条。`selection.py` 负责图片空间 Selection 的值、栅格化和 Alpha 修整;`SelectionPath → SelectionMask` 只在图片编辑或 Shape 生成阶段执行。Frame 在自身业务模块中组合冻结的 Viewport 投影矩阵与对象世界矩阵,把屏幕像素映射到 Image Empty 局部平面;正交视图接受任意有限深度,透视视图只采样观察方向前方的有效交点。
Viewport 对象命中继续由 Blender 原生点选决定。Mask、Rectify 与 Cutout 点到另一对象时只保留原生选择结果;没有命中对象时保留当前 active Image Empty,并把透明区域或 Viewport 空白作为图片操作起点。Frame 的普通空白点击继续清空选择。手势是否与图片范围或可见内容有效相交,由各业务在提交阶段判断。
所有 Path 使用 non-zero winding 填充,同方向重复绕行的重叠区域保持选中。栅格器按路径边与像素中心扫描行的交点累计 winding,只建立 Path Bounds 的局部画布,抗锯齿时增加 2 px 边缘。栅格阶段不接收图片 Alpha 或颜色,Mask 与 Cutout 在各自业务层组合几何 Mask 和图片 Alpha。
### Viewport 交互
| 函数 | 职责 |
| --- | --- |
| `viewport.report_image_edit_exception()` | 将可预期的 Selection 警告和异常映射为 Operator Report。 |
| `viewport.image_edit_poll()` | 判断当前上下文是否允许启动图片编辑工具。 |
| `viewport.resolve_image_edit_click()` | 执行原生点选;点到另一对象时只保留选择结果,空命中时保留 active Image Empty 并开始点选型编辑。 |
| `viewport.active_image_edit_source()` | 要求并取得当前 Selection 内的 active Image Empty。 |
| `viewport.image_edit_selection_keymap()` | 创建普通点击和 Shift 点击的对象选择 keymap,并配置普通点击的空命中策略。 |
| `viewport.image_edit_drag_keymap()` | 创建拖动图片手势及对象点选 keymap。 |
| `viewport.image_edit_point_keymap()` | 创建点选型图片手势及 Shift 追加选择 keymap。 |
| `viewport.active_view3d_tool_id()` | 取得当前 View3D Workspace Tool ID。 |
| `viewport.draw_dashed_line()` | 绘制手势或透视框虚线。 |
| `viewport.draw_polygon_fill()` | 绘制手势或透视框填充预览。 |
| `viewport.ImageGesture` | 复用 Lasso、Brush 与 Polyline 的 Modal 生命周期、源图解析和 Overlay 绘制。 |
| `viewport.brush_footprint_polygons()` | 生成 Brush Overlay 与释放提交共用的圆形印记和连接条。 |
| `viewport.preview_union_geometry()` | 在 screen-space scanline bands 中融合 Brush Primitive,并返回一次填充与外轮廓虚线。 |
| `viewport.preview_fill_geometry()` | 三角化 Lasso、Polyline 的 non-zero winding 填充与外轮廓。 |
| `viewport.rectangle_screen_path()` | 将两个屏幕点规范为 Frame 使用的矩形四角。 |
| `viewport.screen_path_to_image_pixels()` | 将屏幕路径投影为 Image Empty 像素坐标。 |
| `viewport.serialize_matrix()` | 将 4×4 Matrix 序列化为 Operator 可保存的字符串。 |
| `viewport.deserialize_matrix()` | 恢复已序列化的 4×4 Matrix。 |
| `viewport.drawing_in_region()` | 判断 Modal 绘制是否仍位于启动时的 Area 和 Region。 |
### Selection 栅格化
| 函数 | 职责 |
| --- | --- |
| `selection.selection_path_bounds()` | 校验 Selection Path 并返回整数像素包围框。 |
| `selection.rasterize_selection_path()` | 以局部 non-zero scanline 把 `SelectionPath` 栅格化为纯几何 `SelectionMask`。 |
| `selection.trim_pixels_to_alpha()` | 按 Alpha 非零区域修整 RGBA 像素。 |
## Depth 产物
`depth.py` 负责 Blender 侧共享的 Depth 文件加载和相机尺度换算,直接加载 Server 写出的 EXR。
| 函数 | 职责 |
| --- | --- |
| `depth.load_depth_metadata()` | 读取并校验 `depth.json` 中的图片尺寸、相机内参与参考深度。 |
| `depth.load_depth_result_image()` | 直接加载、命名、设为 Non-Color 并 Pack `vector-depth.exr` 或 `z-depth.exr`。 |
| `depth.camera_depth_values()` | 从已加载 Depth Image 读取用于本地标定的 Z 与有效区。 |
| `depth.depth_uniform_scale()` | 根据相机内参、参考深度和 Image Empty 范围计算统一尺度。 |
## Object 构建
`material.py` 构建 Image 材质;`object.py` 处理 Object 与 Geometry Nodes Modifier;`node.py` 加载节点资产。
| 函数 | 职责 |
| --- | --- |
| `node.load_node_group()` | 从随扩展分发的 Blend 资产加载指定 Node Group。 |
| `material.create_image_material()` | 从 Image Empty 创建包含颜色、位移、Normal Map、Alpha 和动画设置的完整材质;非 Shadeless 材质由 Color 直接驱动 Principled IOR Level。 |
| `object.modifier_input_identifier()` | 按接口名称解析 Geometry Nodes Modifier 输入 Identifier。 |
| `object.set_modifier_input()` | 跨受支持 Blender RNA 形式设置 Modifier 输入。 |
| `object.finalize_object_result()` | 激活结果对象,并按需替换或保留源 Empty。 |
## AI 准备
`ai.py` 统一处理 AI 功能的 Environment、模型、Device、输入校验、Job 参数和公共 UI。
| 函数 | 职责 |
| --- | --- |
| `ai.draw_ai_setup()` | 绘制 AI 未就绪时的安装入口,并返回当前状态。 |
| `ai.draw_ai_property()` | 按 AI 就绪状态绘制并启用业务属性。 |
| `ai.require_input_path()` | 解析 Blender 路径并要求其为现存文件或目录。 |
| `ai.require_background_input_path()` | 在通用路径校验之外限制 BEN2 支持的媒体类型。 |
| `ai.production_device()` | 读取正式任务使用的计算设备。 |
| `ai.require_environment()` | 要求 AnyImage AI Environment 已就绪。 |
| `ai.invoke_ai_setup_if_needed()` | Environment 未就绪时启动安装交互。 |
| `ai.require_model()` | 校验模型标识和下载状态,并返回模型记录。 |
| `ai.da3_parameters()` | 组装 `debug-da3` 参数。 |
| `ai.moge2_parameters()` | 组装 MoGe-2 正式任务与 Debug 共用参数。 |