🌙 Image 组件与控制器工作原理
本文汇总 Image 对象标签与其控制器(RectangleLabels、PolygonLabels 等)在 Label Studio 前端中的实现方式,并提供扩展新增控制器的操作指南。
🌙 1. Image 组件定位
- 模型组合:
ImageModel定义于web/libs/editor/src/tags/object/Image/Image.js,由TagAttrs、ObjectBase、MultiItemObjectBase(多图模式)、AnnotationMixin、IsReadyWithDepsMixin、ImageEntityMixin、核心Model以及坐标换算 mixin 组合而成。它负责:- 解析 XML 中的
value/valueList,通过parseValue()与任务数据绑定。 - 维护
regions数组(联合RectRegionModel、PolygonRegionModel、BrushRegionModel等),并和annotation.regionStore同步。 - 管理缩放、旋转、亮度/对比度、网格、十字准线等显示状态。
- 通过
ImageEntityMixin管理多张图片的下载、预加载、自然尺寸、缩放因子等。
- 解析 XML 中的
- 视图绑定:
HtxImage仅注入store并渲染ImageView(web/libs/editor/src/components/ImageView/Image.jsx),该视图在onLoad时回调updateImageSize,并根据imageTransform应用缩放/旋转 CSS。
🌙 2. 渲染与数据流
- XML 配置解析后,
Image标签会在Registry中被映射到ImageModel,创建 MST 实例时会初始化imageEntities并根据valueList支持多页图片。 afterAttach()会根据属性(如zoomControl,rotateControl)将 Move/Zoom/Brightness/Contrast/Rotate 等内置工具注册到ToolsManager,并创建图像实体列表。ImageView渲染过程中根据实体下载状态显示进度或错误,通过ImageRenderer处理跨域与缩放样式;所有交互事件最终回流至ImageModel.event(),由工具管理器派发给当前选中的工具。
🌙 3. 控制器与工具链
- 控制器映射:
ImageModel.states()会从annotation.toNames里检索所有toName=image的控制标签,并在activeStates()中筛选当前选中的labels控件。controlButton()/controlButtonType用于确定工具栏上应展示的控制器图标。 - ToolManager 管理:
- 对象侧:
ImageModel.afterAttach()根据配置将通用工具注册到ToolsManager,getToolsManager()在其他动作中复用同一实例。 - 控制器侧:如
RectangleLabels,其模型由ControlBase+LabelsModel+RectangleModel等组合,并包含toolNames列表。ToolManagerMixin会在afterAttach()中把控制器声明的工具(Rect、Brush等)实例注册到与Image共用的ToolsManager。
- 对象侧:
- 受控对象限制:控制器通过
Types.unionTag(["Image"])声明仅能绑定Image对象,确保toName检查在模型层执行。
🌙 4. 区域模型与结果序列化
ImageModel.createDrawingRegion()在开始绘制时临时生成区域草稿,addShape()则在提交后把region推入regions并与annotation对齐。createSerializedResult()会读取当前图片的原始尺寸、旋转、item_index等信息写入结果,未加载完成时则降级到_rawResult,保证多图场景下一致性。- 所有缩放与坐标换算通过
CoordsCalculations(或AbsoluteCoordsCalculations)封装,canvasToInternalX/Y负责在不同工具之间统一坐标系,实现像素吸附 (snapPointToPixel) 与视口变换。
🌙 5. 新增 Image 控制器指南
目标:让自定义控制器能够针对
Image生成新的区域类型或交互工具。
- 定义控制器 Model
- 在
web/libs/editor/src/tags/control/下创建新文件(例如MyShapeLabels.jsx),使用ControlBase、AnnotationMixin、LabelMixin等组合出 MST 模型。 - 通过
Types.unionTag(["Image"])(或更细粒度的受控对象列表)限制toName。 - 若需要工具栏入口,设置
toolNames = ["MyShapeTool"]并确保在web/libs/editor/src/tools下实现对应工具类。
- 在
- 准备区域模型
- 若新控制器重用现有区域(如
RectRegionModel),直接在控制器模型中 compose。 - 如果需要全新区域(例如
StarRegionModel),需在web/libs/editor/src/regions/下实现该模型,并把它加入ImageModel.regions的types.union(...)中,否则结果树不会接受该区域。
- 若新控制器重用现有区域(如
- 注册工具与视图
- 在控制器文件中调用
Registry.addTag("myshapelabels", MyShapeLabelsModel, HtxMyShapeLabels)。 - 视图层可复用
HtxLabels或自定义 React 组件,确保使用observer包裹并通过itemprop 获取 MST 实例。
- 在控制器文件中调用
- 处理绘制/序列化
- 工具层调用
control.createResult()时会落到ImageModel.createDrawingRegion(),因此新区域需要实现updateImageSize、serialize()等方法以兼容缩放与结果导出。 - 如果控制器需要特定的吸附策略,可在
Tool内调用control.getSnappedPoint()并设置snapMode。
- 工具层调用
- 更新配置与测试
- 在 XML 配置中添加
<MyShapeLabels name="labels" toName="image">...</MyShapeLabels>并关联<Image name="image" .../>。 - 运行
cd web && yarn lsf:serve验证交互;如涉及多图/分辨率缩放,需检查createSerializedResult()输出。
- 在 XML 配置中添加
🌙 6. 调试与排障建议
- 使用
annotation.history快照定位缩放后区域错位的问题;ImageModel._updateRegionsSizes()会在缩放或容器尺寸变化时批量更新区域坐标,必要时在该函数内添加日志。 - 开启
FF_DEV_3793时,注意坐标系切换为绝对像素,工具需读取zoomedPixelSize以避免点击漂移。 - 利用
ImageModel.suggestions/supportSuggestions可以在控制器中实现模型预标注的自定义呈现,调试时可通过浏览器控制台查看annotation.regionStore.suggestions。
通过以上结构化信息,可以快速定位 Image 组件与控制器之间的协作关系,并在保证现有工具链一致性的前提下扩展新的图像标注能力。