@jax-data-science/sci-image-visualizer 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -1,916 +1,37 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __decorateClass = (decorators, target, key, kind) => {
4
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
- if (decorator = decorators[i])
7
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result)
9
- __defProp(target, key, result);
10
- return result;
11
- };
12
-
13
1
  // src/lib/region-editor/mask.worker.ts
14
2
  import { encode as encodePng } from "fast-png";
15
3
 
16
- // src/lib/toolbar/wand/wand.service.ts
17
- import { Injectable } from "@angular/core";
18
-
19
- // src/lib/models/region.ts
20
- var Polygon = class {
21
- constructor() {
22
- this.npoints = 0;
23
- this.xpoints = [];
24
- this.ypoints = [];
25
- this.coordinates = [];
26
- /** false for open polylines; true (default) for closed polygons */
27
- this.closed = true;
28
- /**
29
- * When true the vertices are treated as bezier-spline **anchors** and the
30
- * region is rendered/exported as a smooth curve through them. The vertices
31
- * stay the editable anchors — toggling this flag is the toBezier
32
- * (`true`) / toPolygon (`false`), which only add/remove the curve, never move
33
- * the anchors. GeoJSON keeps the flattened curve as the geometry (so QuPath
34
- * renders it) plus the anchors + handles + flag in properties (so JIT
35
- * round-trips the editable bezier).
36
- */
37
- this.bezier = false;
38
- }
39
- };
40
-
41
- // src/lib/toolbar/wand/wand.service.ts
42
- var DEFAULT_PATCH_SIZE = 149;
43
- var DEFAULT_SIGMA = 4;
44
- var DEFAULT_SENSITIVITY = 2;
45
- var WandService = class {
46
- /**
47
- * @param image full-image pixel matrix (already in memory).
48
- * @param cx click x in image-pixel coordinates.
49
- * @param cy click y in image-pixel coordinates.
50
- * @param options wand parameters; missing fields fall back to defaults.
51
- * @returns a Polygon in image-pixel coordinates, or null if no region grew.
52
- */
53
- computeRegion(image, cx, cy, options = {}) {
54
- const patch = this.computePatchMask(image, cx, cy, options);
55
- if (!patch)
56
- return null;
57
- return this.maskToPolygon(
58
- patch.mask,
59
- patch.size,
60
- patch.size,
61
- image.width,
62
- image.height,
63
- Math.round(cx) - (patch.size - 1) / 2,
64
- Math.round(cy) - (patch.size - 1) / 2
65
- );
66
- }
67
- /**
68
- * Compute the wand's per-click flood-fill mask in patch-local coordinates.
69
- * Same algorithm as `computeRegion` but stops before contour tracing — useful
70
- * for accumulating per-tick masks across a brush-style stroke.
71
- *
72
- * @returns mask of size W*W (0/1) plus W, or null if patchSize is invalid.
73
- */
74
- computePatchMask(image, cx, cy, options = {}) {
75
- const W = options.patchSize ?? DEFAULT_PATCH_SIZE;
76
- if (W % 2 === 0) {
77
- throw new Error(`patchSize must be odd, got ${W}`);
78
- }
79
- const sigma = options.sigma ?? DEFAULT_SIGMA;
80
- const sensitivity = options.sensitivity ?? DEFAULT_SENSITIVITY;
81
- const isGrayscale = image.isGrayscale;
82
- const type = options.type ?? (isGrayscale ? "GRAY" : "RGB");
83
- const simple = !!options.simpleMode;
84
- const inputChannels = type === "GRAY" ? 1 : 3;
85
- let buf = this.extractPatch(image, cx, cy, W, type);
86
- let floodChannels;
87
- let threshold;
88
- if (simple) {
89
- floodChannels = inputChannels;
90
- threshold = new Array(floodChannels).fill(0);
91
- } else {
92
- const blurSigma = Math.max(0.5, sigma);
93
- buf = this.gaussianBlur(buf, W, inputChannels, blurSigma);
94
- if (type === "LAB_DISTANCE") {
95
- const distance = this.labDistanceMap(buf, W);
96
- const max = distance.max > 0 ? distance.max : 1;
97
- const scaled = new Float32Array(W * W);
98
- for (let i = 0; i < scaled.length; i++)
99
- scaled[i] = distance.values[i] * 255 / max;
100
- buf = scaled;
101
- floodChannels = 1;
102
- threshold = [distance.mean * sensitivity * 255 / max];
103
- } else {
104
- floodChannels = inputChannels;
105
- threshold = this.perChannelThreshold(buf, W, inputChannels, sensitivity);
106
- }
107
- }
108
- const mask = this.floodFill(buf, W, floodChannels, threshold);
109
- const closed = simple ? mask : this.morphClose(mask, W, 5);
110
- return { mask: closed, size: W };
111
- }
112
- /**
113
- * Standard ray-cast point-in-polygon test. (px, py) and the polygon
114
- * vertices must be in the same coordinate system.
115
- */
116
- pointInPolygon(px, py, xpoints, ypoints) {
117
- const n = xpoints.length;
118
- if (n < 3)
119
- return false;
120
- let inside = false;
121
- for (let i = 0, j = n - 1; i < n; j = i++) {
122
- const yi = ypoints[i], yj = ypoints[j];
123
- const xi = xpoints[i], xj = xpoints[j];
124
- const intersect = yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi;
125
- if (intersect)
126
- inside = !inside;
127
- }
128
- return inside;
129
- }
130
- /**
131
- * Drop every vertex whose Euclidean distance to (cx, cy) is less than
132
- * `radius`. Returns trimmed parallel arrays plus how many vertices were
133
- * removed (so the caller can detect a no-op tick and skip the relayout).
134
- */
135
- dropVerticesWithinRadius(xpoints, ypoints, cx, cy, radius) {
136
- const r2 = radius * radius;
137
- const xs = [];
138
- const ys = [];
139
- let removed = 0;
140
- for (let i = 0; i < xpoints.length; i++) {
141
- const dx = xpoints[i] - cx;
142
- const dy = ypoints[i] - cy;
143
- if (dx * dx + dy * dy < r2) {
144
- removed++;
145
- continue;
146
- }
147
- xs.push(xpoints[i]);
148
- ys.push(ypoints[i]);
149
- }
150
- return { xpoints: xs, ypoints: ys, removed };
151
- }
152
- /**
153
- * Rasterize a closed polygon into a bbox-relative mask suitable as a
154
- * starting point for a wand stroke accumulator.
155
- *
156
- * Returns the bbox origin (clamped to the image) plus the filled mask, or
157
- * null if the polygon is degenerate or fully outside the image.
158
- */
159
- rasterizePolygon(xpoints, ypoints, imageWidth, imageHeight, holes) {
160
- const n = xpoints.length;
161
- if (n < 3)
162
- return null;
163
- let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
164
- for (let i = 0; i < n; i++) {
165
- if (xpoints[i] < minX)
166
- minX = xpoints[i];
167
- if (xpoints[i] > maxX)
168
- maxX = xpoints[i];
169
- if (ypoints[i] < minY)
170
- minY = ypoints[i];
171
- if (ypoints[i] > maxY)
172
- maxY = ypoints[i];
173
- }
174
- let bx = Math.floor(minX);
175
- let by = Math.floor(minY);
176
- let bx1 = Math.ceil(maxX) + 1;
177
- let by1 = Math.ceil(maxY) + 1;
178
- if ((bx1 - bx) * (by1 - by) > 4096 * 4096) {
179
- bx = Math.max(0, bx);
180
- by = Math.max(0, by);
181
- bx1 = Math.min(imageWidth, bx1);
182
- by1 = Math.min(imageHeight, by1);
183
- }
184
- const bw = bx1 - bx;
185
- const bh = by1 - by;
186
- if (bw <= 0 || bh <= 0)
187
- return null;
188
- const mask = new Uint8Array(bw * bh);
189
- const fillRing = (rx, ry, value) => {
190
- const m = rx.length;
191
- if (m < 3)
192
- return;
193
- for (let py = 0; py < bh; py++) {
194
- const y = by + py + 0.5;
195
- const xs = [];
196
- for (let i = 0, j = m - 1; i < m; j = i++) {
197
- const yi = ry[i], yj = ry[j];
198
- if (yi <= y && yj > y || yj <= y && yi > y) {
199
- const t = (y - yi) / (yj - yi);
200
- xs.push(rx[i] + t * (rx[j] - rx[i]));
201
- }
202
- }
203
- xs.sort((a, b) => a - b);
204
- for (let k = 0; k + 1 < xs.length; k += 2) {
205
- const xStart = Math.max(0, Math.ceil(xs[k] - bx));
206
- const xEnd = Math.min(bw - 1, Math.floor(xs[k + 1] - bx));
207
- for (let x = xStart; x <= xEnd; x++)
208
- mask[py * bw + x] = value;
209
- }
210
- }
211
- };
212
- fillRing(xpoints, ypoints, 1);
213
- if (holes) {
214
- for (const ring of holes) {
215
- fillRing(ring.map((p) => p[0]), ring.map((p) => p[1]), 0);
216
- }
217
- }
218
- return { bx, by, bw, bh, mask };
219
- }
220
- /**
221
- * Point-in-region test that honours interior rings (holes): inside the
222
- * exterior AND outside every hole (even-odd). Coordinates must share the
223
- * polygon's frame. With no holes this is exactly {@link pointInPolygon}.
224
- */
225
- pointInPolygonWithHoles(px, py, xpoints, ypoints, holes) {
226
- if (!this.pointInPolygon(px, py, xpoints, ypoints))
227
- return false;
228
- if (holes) {
229
- for (const ring of holes) {
230
- if (this.pointInPolygon(px, py, ring.map((p) => p[0]), ring.map((p) => p[1])))
231
- return false;
232
- }
233
- }
234
- return true;
235
- }
236
- /**
237
- * Trace the largest 4-connected blob in `mask` (sized w*h) and return a
238
- * Polygon translated into image-pixel coordinates via (originX, originY).
239
- * The traced vertices are NOT clamped to the image bounds: a region drawn while
240
- * panned/zoomed keeps its true coordinates even where they fall outside the visible
241
- * window (jit-ui#102). `imageWidth`/`imageHeight` are kept for signature compatibility
242
- * but no longer used.
243
- */
244
- maskToPolygon(mask, w, h, _imageWidth, _imageHeight, originX, originY) {
245
- const verticesLocal = this.traceContour(mask, w, h);
246
- if (!verticesLocal || verticesLocal.length < 3)
247
- return null;
248
- const xpoints = [];
249
- const ypoints = [];
250
- const coordinates = [];
251
- for (const v of verticesLocal) {
252
- const ix = Math.round(originX + v.x);
253
- const iy = Math.round(originY + v.y);
254
- xpoints.push(ix);
255
- ypoints.push(iy);
256
- coordinates.push([ix, iy]);
257
- }
258
- const poly = new Polygon();
259
- poly.npoints = xpoints.length;
260
- poly.xpoints = xpoints;
261
- poly.ypoints = ypoints;
262
- poly.coordinates = coordinates;
263
- return poly;
264
- }
265
- /**
266
- * Trace EVERY 4-connected blob in `mask` (sized w*h) whose area is at least
267
- * `minSize` pixels, returning one Polygon per blob in image-pixel coordinates
268
- * (translated via originX/originY, clamped to imageWidth/imageHeight), ordered
269
- * largest-first. Unlike {@link maskToPolygon} (largest blob only), this lets
270
- * the brush eraser split a region in two when a stroke cuts through it rather
271
- * than discarding the smaller piece.
272
- */
273
- maskToPolygons(mask, w, h, imageWidth, imageHeight, originX, originY, minSize = 4, minHoleSize = minSize) {
274
- const labels = new Int32Array(w * h);
275
- const sizes = [0];
276
- let nextLabel = 0;
277
- const queue = [];
278
- for (let y = 0; y < h; y++) {
279
- for (let x = 0; x < w; x++) {
280
- const idx = y * w + x;
281
- if (!mask[idx] || labels[idx])
282
- continue;
283
- nextLabel++;
284
- labels[idx] = nextLabel;
285
- let size = 0;
286
- queue.push(idx);
287
- while (queue.length) {
288
- const i = queue.pop();
289
- size++;
290
- const px = i % w;
291
- const py = (i - px) / w;
292
- if (px > 0) {
293
- const j = i - 1;
294
- if (mask[j] && !labels[j]) {
295
- labels[j] = nextLabel;
296
- queue.push(j);
297
- }
298
- }
299
- if (px < w - 1) {
300
- const j = i + 1;
301
- if (mask[j] && !labels[j]) {
302
- labels[j] = nextLabel;
303
- queue.push(j);
304
- }
305
- }
306
- if (py > 0) {
307
- const j = i - w;
308
- if (mask[j] && !labels[j]) {
309
- labels[j] = nextLabel;
310
- queue.push(j);
311
- }
312
- }
313
- if (py < h - 1) {
314
- const j = i + w;
315
- if (mask[j] && !labels[j]) {
316
- labels[j] = nextLabel;
317
- queue.push(j);
318
- }
319
- }
320
- }
321
- sizes[nextLabel] = size;
322
- }
323
- }
324
- const wanted = [];
325
- for (let lbl = 1; lbl <= nextLabel; lbl++) {
326
- if (sizes[lbl] >= minSize)
327
- wanted.push(lbl);
328
- }
329
- wanted.sort((a, b) => sizes[b] - sizes[a]);
330
- const holesByLabel = this.detectHoles(
331
- mask,
332
- labels,
333
- w,
334
- h,
335
- originX,
336
- originY,
337
- imageWidth,
338
- imageHeight,
339
- minHoleSize
340
- );
341
- const polys = [];
342
- const comp = new Uint8Array(w * h);
343
- for (const lbl of wanted) {
344
- comp.fill(0);
345
- for (let i = 0; i < comp.length; i++)
346
- comp[i] = labels[i] === lbl ? 1 : 0;
347
- const verts = this.mooreBoundary(comp, w, h);
348
- if (!verts || verts.length < 3)
349
- continue;
350
- const xpoints = [];
351
- const ypoints = [];
352
- const coordinates = [];
353
- for (const v of verts) {
354
- const ix = Math.round(originX + v.x);
355
- const iy = Math.round(originY + v.y);
356
- xpoints.push(ix);
357
- ypoints.push(iy);
358
- coordinates.push([ix, iy]);
359
- }
360
- const poly = new Polygon();
361
- poly.npoints = xpoints.length;
362
- poly.xpoints = xpoints;
363
- poly.ypoints = ypoints;
364
- poly.coordinates = coordinates;
365
- const holes = holesByLabel.get(lbl);
366
- if (holes && holes.length)
367
- poly.holes = holes;
368
- polys.push(poly);
369
- }
370
- return polys;
371
- }
372
- /**
373
- * Find interior rings (holes) of each foreground component in `mask`: a
374
- * 4-connected run of background (0) pixels that is fully enclosed — i.e. not
375
- * reachable from the grid border through background — is a hole, attributed to
376
- * the foreground component that borders it most. Returns `fgLabel → rings`,
377
- * each ring a list of `[x, y]` image-pixel pairs (same convention as a
378
- * polygon's `coordinates`). Holes smaller than `minHoleSize` are dropped.
379
- */
380
- detectHoles(mask, fgLabels, w, h, originX, originY, imageWidth, imageHeight, minHoleSize) {
381
- const result = /* @__PURE__ */ new Map();
382
- const outside = new Uint8Array(w * h);
383
- const stack = [];
384
- const seed = (idx) => {
385
- if (!mask[idx] && !outside[idx]) {
386
- outside[idx] = 1;
387
- stack.push(idx);
388
- }
389
- };
390
- for (let x = 0; x < w; x++) {
391
- seed(x);
392
- seed((h - 1) * w + x);
393
- }
394
- for (let y = 0; y < h; y++) {
395
- seed(y * w);
396
- seed(y * w + w - 1);
397
- }
398
- while (stack.length) {
399
- const i = stack.pop();
400
- const px = i % w, py = (i - px) / w;
401
- if (px > 0)
402
- seed(i - 1);
403
- if (px < w - 1)
404
- seed(i + 1);
405
- if (py > 0)
406
- seed(i - w);
407
- if (py < h - 1)
408
- seed(i + w);
409
- }
410
- const visited = new Uint8Array(w * h);
411
- const holeMask = new Uint8Array(w * h);
412
- const queue = [];
413
- for (let start = 0; start < mask.length; start++) {
414
- if (mask[start] || outside[start] || visited[start])
415
- continue;
416
- let size = 0;
417
- const owners = /* @__PURE__ */ new Map();
418
- const pixels = [];
419
- visited[start] = 1;
420
- queue.length = 0;
421
- queue.push(start);
422
- while (queue.length) {
423
- const i = queue.pop();
424
- size++;
425
- pixels.push(i);
426
- const px = i % w, py = (i - px) / w;
427
- const visit = (j) => {
428
- if (mask[j]) {
429
- const lbl = fgLabels[j];
430
- if (lbl)
431
- owners.set(lbl, (owners.get(lbl) ?? 0) + 1);
432
- } else if (!outside[j] && !visited[j]) {
433
- visited[j] = 1;
434
- queue.push(j);
435
- }
436
- };
437
- if (px > 0)
438
- visit(i - 1);
439
- if (px < w - 1)
440
- visit(i + 1);
441
- if (py > 0)
442
- visit(i - w);
443
- if (py < h - 1)
444
- visit(i + w);
445
- }
446
- if (size < minHoleSize || owners.size === 0)
447
- continue;
448
- let owner = 0, best = -1;
449
- owners.forEach((cnt, lbl) => {
450
- if (cnt > best) {
451
- best = cnt;
452
- owner = lbl;
453
- }
454
- });
455
- holeMask.fill(0);
456
- for (const i of pixels)
457
- holeMask[i] = 1;
458
- const verts = this.mooreBoundary(holeMask, w, h);
459
- if (!verts || verts.length < 3)
460
- continue;
461
- const ring = [];
462
- for (const v of verts) {
463
- const ix = Math.max(0, Math.min(imageWidth - 1, Math.round(originX + v.x)));
464
- const iy = Math.max(0, Math.min(imageHeight - 1, Math.round(originY + v.y)));
465
- ring.push([ix, iy]);
466
- }
467
- const list = result.get(owner) ?? [];
468
- list.push(ring);
469
- result.set(owner, list);
470
- }
471
- return result;
472
- }
473
- /**
474
- * Trace each instance in an integer label map (0 = background) into a Polygon
475
- * — used to turn a cellpose-style segmentation into region outlines. Labels
476
- * with area below `minSize` are skipped. Coords are translated via
477
- * originX/originY and clamped to imageWidth/imageHeight.
478
- */
479
- labelsToPolygons(labels, w, h, imageWidth, imageHeight, originX, originY, minSize = 10) {
480
- let maxLabel = 0;
481
- for (let i = 0; i < labels.length; i++)
482
- if (labels[i] > maxLabel)
483
- maxLabel = labels[i];
484
- const out = [];
485
- const bin = new Uint8Array(w * h);
486
- for (let lbl = 1; lbl <= maxLabel; lbl++) {
487
- let any = false;
488
- for (let i = 0; i < labels.length; i++) {
489
- const on = labels[i] === lbl;
490
- bin[i] = on ? 1 : 0;
491
- if (on)
492
- any = true;
493
- }
494
- if (!any)
495
- continue;
496
- for (const p of this.maskToPolygons(bin, w, h, imageWidth, imageHeight, originX, originY, minSize)) {
497
- out.push(p);
498
- }
499
- }
500
- return out;
501
- }
502
- // ── Patch extraction ────────────────────────────────────────────────
503
- extractPatch(image, cx, cy, W, type) {
504
- const channels = type === "GRAY" ? 1 : 3;
505
- const half = (W - 1) / 2;
506
- const x0 = Math.round(cx) - half;
507
- const y0 = Math.round(cy) - half;
508
- const buf = new Float32Array(W * W * channels);
509
- for (let py = 0; py < W; py++) {
510
- const iy = y0 + py;
511
- if (iy < 0 || iy >= image.height)
512
- continue;
513
- const row = image.data[iy];
514
- if (!row)
515
- continue;
516
- for (let px = 0; px < W; px++) {
517
- const ix = x0 + px;
518
- if (ix < 0 || ix >= image.width)
519
- continue;
520
- const dst = (py * W + px) * channels;
521
- if (image.isGrayscale) {
522
- const v = row[ix];
523
- if (channels === 1) {
524
- buf[dst] = v;
525
- } else {
526
- buf[dst] = v;
527
- buf[dst + 1] = v;
528
- buf[dst + 2] = v;
529
- }
530
- } else {
531
- const tuple = row[ix];
532
- if (channels === 1) {
533
- buf[dst] = 0.299 * tuple[0] + 0.587 * tuple[1] + 0.114 * tuple[2];
534
- } else {
535
- buf[dst] = tuple[0];
536
- buf[dst + 1] = tuple[1];
537
- buf[dst + 2] = tuple[2];
538
- }
539
- }
540
- }
541
- }
542
- return buf;
543
- }
544
- // ── Gaussian blur (separable) ───────────────────────────────────────
545
- gaussianBlur(buf, W, channels, sigma) {
546
- const radius = Math.max(1, Math.ceil(sigma * 2));
547
- const size = radius * 2 + 1;
548
- const kernel = new Float32Array(size);
549
- let sum = 0;
550
- const inv2s2 = 1 / (2 * sigma * sigma);
551
- for (let i = 0; i < size; i++) {
552
- const x = i - radius;
553
- kernel[i] = Math.exp(-x * x * inv2s2);
554
- sum += kernel[i];
555
- }
556
- for (let i = 0; i < size; i++)
557
- kernel[i] /= sum;
558
- const horiz = new Float32Array(buf.length);
559
- for (let y = 0; y < W; y++) {
560
- for (let x = 0; x < W; x++) {
561
- for (let c = 0; c < channels; c++) {
562
- let acc = 0;
563
- for (let k = 0; k < size; k++) {
564
- let xx = x + k - radius;
565
- if (xx < 0)
566
- xx = 0;
567
- else if (xx >= W)
568
- xx = W - 1;
569
- acc += kernel[k] * buf[(y * W + xx) * channels + c];
570
- }
571
- horiz[(y * W + x) * channels + c] = acc;
572
- }
573
- }
574
- }
575
- const out = new Float32Array(buf.length);
576
- for (let y = 0; y < W; y++) {
577
- for (let x = 0; x < W; x++) {
578
- for (let c = 0; c < channels; c++) {
579
- let acc = 0;
580
- for (let k = 0; k < size; k++) {
581
- let yy = y + k - radius;
582
- if (yy < 0)
583
- yy = 0;
584
- else if (yy >= W)
585
- yy = W - 1;
586
- acc += kernel[k] * horiz[(yy * W + x) * channels + c];
587
- }
588
- out[(y * W + x) * channels + c] = acc;
589
- }
590
- }
591
- }
592
- return out;
593
- }
594
- // ── Threshold computation ───────────────────────────────────────────
595
- perChannelThreshold(buf, W, channels, sensitivity) {
596
- const n = W * W;
597
- const sums = new Array(channels).fill(0);
598
- const sqs = new Array(channels).fill(0);
599
- for (let i = 0; i < n; i++) {
600
- for (let c = 0; c < channels; c++) {
601
- const v = buf[i * channels + c];
602
- sums[c] += v;
603
- sqs[c] += v * v;
604
- }
605
- }
606
- const scale = sensitivity > 0 ? 1 / sensitivity : 100;
607
- const threshold = new Array(channels);
608
- for (let c = 0; c < channels; c++) {
609
- const mean = sums[c] / n;
610
- const variance = Math.max(0, sqs[c] / n - mean * mean);
611
- const stddev = Math.sqrt(variance);
612
- threshold[c] = stddev * scale;
613
- }
614
- return threshold;
615
- }
616
- labDistanceMap(buf, W) {
617
- const n = W * W;
618
- const lab = new Float32Array(n * 3);
619
- for (let i = 0; i < n; i++) {
620
- const r = buf[i * 3] / 255;
621
- const g = buf[i * 3 + 1] / 255;
622
- const b = buf[i * 3 + 2] / 255;
623
- const [L, A, B] = srgbToLab(r, g, b);
624
- lab[i * 3] = L;
625
- lab[i * 3 + 1] = A;
626
- lab[i * 3 + 2] = B;
627
- }
628
- const mid = Math.floor(n / 2);
629
- const cL = lab[mid * 3];
630
- const cA = lab[mid * 3 + 1];
631
- const cB = lab[mid * 3 + 2];
632
- const values = new Float32Array(n);
633
- let max = 0;
634
- let sum = 0;
635
- for (let i = 0; i < n; i++) {
636
- const dL = lab[i * 3] - cL;
637
- const dA = lab[i * 3 + 1] - cA;
638
- const dB = lab[i * 3 + 2] - cB;
639
- const d = Math.sqrt(dL * dL + dA * dA + dB * dB);
640
- values[i] = d;
641
- if (d > max)
642
- max = d;
643
- sum += d;
644
- }
645
- return { values, mean: sum / n, max };
646
- }
647
- // ── Flood fill ──────────────────────────────────────────────────────
648
- /**
649
- * Fixed-range scanline flood fill from the patch centre. A neighbour is
650
- * accepted iff for every channel `|p[c] - seed[c]| <= threshold[c]`.
651
- */
652
- floodFill(buf, W, channels, threshold) {
653
- const mask = new Uint8Array(W * W);
654
- const seedX = (W - 1) / 2;
655
- const seedY = (W - 1) / 2;
656
- const seedIdx = (seedY * W + seedX) * channels;
657
- const seed = new Array(channels);
658
- for (let c = 0; c < channels; c++)
659
- seed[c] = buf[seedIdx + c];
660
- const accept = (x, y) => {
661
- const idx = (y * W + x) * channels;
662
- for (let c = 0; c < channels; c++) {
663
- const diff = Math.abs(buf[idx + c] - seed[c]);
664
- if (diff > threshold[c])
665
- return false;
666
- }
667
- return true;
668
- };
669
- const stack = [seedX, seedY];
670
- while (stack.length) {
671
- const y = stack.pop();
672
- const x = stack.pop();
673
- if (x < 0 || x >= W || y < 0 || y >= W)
674
- continue;
675
- if (mask[y * W + x])
676
- continue;
677
- if (!accept(x, y))
678
- continue;
679
- let xl = x;
680
- while (xl > 0 && !mask[y * W + (xl - 1)] && accept(xl - 1, y))
681
- xl--;
682
- let xr = x;
683
- while (xr < W - 1 && !mask[y * W + (xr + 1)] && accept(xr + 1, y))
684
- xr++;
685
- for (let xi = xl; xi <= xr; xi++) {
686
- mask[y * W + xi] = 1;
687
- }
688
- if (y > 0) {
689
- for (let xi = xl; xi <= xr; xi++) {
690
- if (!mask[(y - 1) * W + xi]) {
691
- stack.push(xi, y - 1);
692
- }
693
- }
694
- }
695
- if (y < W - 1) {
696
- for (let xi = xl; xi <= xr; xi++) {
697
- if (!mask[(y + 1) * W + xi]) {
698
- stack.push(xi, y + 1);
699
- }
700
- }
701
- }
702
- }
703
- return mask;
704
- }
705
- // ── Morphological close (dilate then erode) ─────────────────────────
706
- morphClose(mask, W, kernelSize) {
707
- const r = (kernelSize - 1) / 2;
708
- const dil = this.dilate(mask, W, r);
709
- return this.erode(dil, W, r);
710
- }
711
- dilate(mask, W, r) {
712
- const out = new Uint8Array(W * W);
713
- for (let y = 0; y < W; y++) {
714
- for (let x = 0; x < W; x++) {
715
- let hit = 0;
716
- for (let dy = -r; dy <= r && !hit; dy++) {
717
- const yy = y + dy;
718
- if (yy < 0 || yy >= W)
719
- continue;
720
- for (let dx = -r; dx <= r; dx++) {
721
- const xx = x + dx;
722
- if (xx < 0 || xx >= W)
723
- continue;
724
- if (mask[yy * W + xx]) {
725
- hit = 1;
726
- break;
727
- }
728
- }
729
- }
730
- out[y * W + x] = hit;
731
- }
732
- }
733
- return out;
734
- }
735
- erode(mask, W, r) {
736
- const out = new Uint8Array(W * W);
737
- for (let y = 0; y < W; y++) {
738
- for (let x = 0; x < W; x++) {
739
- let all = 1;
740
- for (let dy = -r; dy <= r && all; dy++) {
741
- const yy = y + dy;
742
- if (yy < 0 || yy >= W) {
743
- all = 0;
744
- break;
745
- }
746
- for (let dx = -r; dx <= r; dx++) {
747
- const xx = x + dx;
748
- if (xx < 0 || xx >= W) {
749
- all = 0;
750
- break;
751
- }
752
- if (!mask[yy * W + xx]) {
753
- all = 0;
754
- break;
755
- }
756
- }
757
- }
758
- out[y * W + x] = all;
759
- }
760
- }
761
- return out;
762
- }
763
- // ── Contour tracing (Moore-neighbour boundary follow) ───────────────
764
- /**
765
- * Returns the outer boundary of the largest 4-connected blob in the mask
766
- * sized w*h.
767
- */
768
- traceContour(mask, w, h) {
769
- const labels = new Int32Array(w * h);
770
- let bestLabel = 0;
771
- let bestSize = 0;
772
- let nextLabel = 0;
773
- const queue = [];
774
- for (let y = 0; y < h; y++) {
775
- for (let x = 0; x < w; x++) {
776
- const idx = y * w + x;
777
- if (!mask[idx] || labels[idx])
778
- continue;
779
- nextLabel++;
780
- labels[idx] = nextLabel;
781
- let size = 0;
782
- queue.push(idx);
783
- while (queue.length) {
784
- const i = queue.pop();
785
- size++;
786
- const px = i % w;
787
- const py = (i - px) / w;
788
- if (px > 0) {
789
- const j = i - 1;
790
- if (mask[j] && !labels[j]) {
791
- labels[j] = nextLabel;
792
- queue.push(j);
793
- }
794
- }
795
- if (px < w - 1) {
796
- const j = i + 1;
797
- if (mask[j] && !labels[j]) {
798
- labels[j] = nextLabel;
799
- queue.push(j);
800
- }
801
- }
802
- if (py > 0) {
803
- const j = i - w;
804
- if (mask[j] && !labels[j]) {
805
- labels[j] = nextLabel;
806
- queue.push(j);
807
- }
808
- }
809
- if (py < h - 1) {
810
- const j = i + w;
811
- if (mask[j] && !labels[j]) {
812
- labels[j] = nextLabel;
813
- queue.push(j);
814
- }
815
- }
816
- }
817
- if (size > bestSize) {
818
- bestSize = size;
819
- bestLabel = nextLabel;
820
- }
821
- }
822
- }
823
- if (bestSize === 0)
824
- return null;
825
- const comp = new Uint8Array(w * h);
826
- for (let i = 0; i < comp.length; i++)
827
- comp[i] = labels[i] === bestLabel ? 1 : 0;
828
- return this.mooreBoundary(comp, w, h);
829
- }
830
- mooreBoundary(mask, w, h) {
831
- let startIdx = -1;
832
- for (let i = 0; i < mask.length; i++) {
833
- if (mask[i]) {
834
- startIdx = i;
835
- break;
836
- }
837
- }
838
- if (startIdx < 0)
839
- return [];
840
- const sx = startIdx % w;
841
- const sy = (startIdx - sx) / w;
842
- const points = [{ x: sx, y: sy }];
843
- const singleton = (idx) => {
844
- const x = idx % w;
845
- const y = (idx - x) / w;
846
- const at = (xx, yy) => xx >= 0 && xx < w && yy >= 0 && yy < h && mask[yy * w + xx];
847
- return !(at(x - 1, y) || at(x + 1, y) || at(x, y - 1) || at(x, y + 1));
848
- };
849
- if (singleton(startIdx)) {
850
- return [
851
- { x: sx, y: sy },
852
- { x: sx + 1, y: sy },
853
- { x: sx + 1, y: sy + 1 },
854
- { x: sx, y: sy + 1 }
855
- ];
856
- }
857
- const dx = [-1, -1, 0, 1, 1, 1, 0, -1];
858
- const dy = [0, -1, -1, -1, 0, 1, 1, 1];
859
- let cx = sx, cy = sy;
860
- let prevDir = 0;
861
- const maxSteps = w * h * 8;
862
- for (let step = 0; step < maxSteps; step++) {
863
- let found = false;
864
- for (let k = 1; k <= 8; k++) {
865
- const dir = prevDir + k & 7;
866
- const nx = cx + dx[dir];
867
- const ny = cy + dy[dir];
868
- if (nx < 0 || nx >= w || ny < 0 || ny >= h)
869
- continue;
870
- if (mask[ny * w + nx]) {
871
- prevDir = dir + 4 & 7;
872
- cx = nx;
873
- cy = ny;
874
- points.push({ x: cx, y: cy });
875
- found = true;
876
- break;
877
- }
878
- }
879
- if (!found)
880
- break;
881
- if (cx === sx && cy === sy && points.length > 1) {
882
- points.pop();
883
- break;
884
- }
885
- }
886
- return points;
887
- }
888
- };
889
- WandService = __decorateClass([
890
- Injectable({ providedIn: "root" })
891
- ], WandService);
892
- function srgbToLinear(c) {
893
- return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
894
- }
895
- function srgbToLab(r, g, b) {
896
- const R = srgbToLinear(r);
897
- const G = srgbToLinear(g);
898
- const B = srgbToLinear(b);
899
- const X = R * 0.4124564 + G * 0.3575761 + B * 0.1804375;
900
- const Y = R * 0.2126729 + G * 0.7151522 + B * 0.072175;
901
- const Z = R * 0.0193339 + G * 0.119192 + B * 0.9503041;
902
- const Xn = 0.95047, Yn = 1, Zn = 1.08883;
903
- const fx = labF(X / Xn);
904
- const fy = labF(Y / Yn);
905
- const fz = labF(Z / Zn);
906
- const L = 116 * fy - 16;
907
- const A = 500 * (fx - fy);
908
- const Bv = 200 * (fy - fz);
909
- return [L, A, Bv];
4
+ // src/lib/geometry/raster.ts
5
+ import { rasterizePolygon as rasterizeRing } from "napari-js/geometry";
6
+ var MAX_RASTER_PIXELS = 4096 * 4096;
7
+ function flatRing(xs, ys) {
8
+ const out = new Array(xs.length * 2);
9
+ for (let i = 0; i < xs.length; i++) {
10
+ out[i * 2] = xs[i];
11
+ out[i * 2 + 1] = ys[i];
12
+ }
13
+ return out;
910
14
  }
911
- function labF(t) {
912
- const d = 6 / 29;
913
- return t > d * d * d ? Math.cbrt(t) : t / (3 * d * d) + 4 / 29;
15
+ function rasterizePolygon(xpoints, ypoints, imageWidth, imageHeight, holes) {
16
+ if (xpoints.length < 3)
17
+ return null;
18
+ const outer = flatRing(xpoints, ypoints);
19
+ const inner = holes?.map(
20
+ (ring) => flatRing(
21
+ ring.map((p) => p[0]),
22
+ ring.map((p) => p[1])
23
+ )
24
+ );
25
+ const bounds = { x: 0, y: 0, width: imageWidth, height: imageHeight };
26
+ let m;
27
+ try {
28
+ m = rasterizeRing(outer, inner, { bounds, maxPixels: MAX_RASTER_PIXELS });
29
+ } catch (err) {
30
+ if (!(err instanceof RangeError))
31
+ throw err;
32
+ m = rasterizeRing(outer, inner, { bounds, clip: true, maxPixels: Infinity });
33
+ }
34
+ return m && { bx: m.x, by: m.y, bw: m.width, bh: m.height, mask: m.data };
914
35
  }
915
36
 
916
37
  // src/lib/region-editor/mask-raster.ts
@@ -931,10 +52,12 @@ function regionsToMask(regions, imageWidth, imageHeight, mode, rasterize, onProg
931
52
  if (!m)
932
53
  continue;
933
54
  painted = true;
934
- for (let y = 0; y < m.bh; y++) {
55
+ const x0 = Math.max(0, -m.bx), x1 = Math.min(m.bw, W - m.bx);
56
+ const y0 = Math.max(0, -m.by), y1 = Math.min(m.bh, H - m.by);
57
+ for (let y = y0; y < y1; y++) {
935
58
  const srcRow = y * m.bw;
936
59
  const dstRow = (m.by + y) * W + m.bx;
937
- for (let x = 0; x < m.bw; x++) {
60
+ for (let x = x0; x < x1; x++) {
938
61
  if (m.mask[srcRow + x])
939
62
  out[dstRow + x] = value;
940
63
  }
@@ -946,7 +69,6 @@ function regionsToMask(regions, imageWidth, imageHeight, mode, rasterize, onProg
946
69
  }
947
70
 
948
71
  // src/lib/region-editor/mask.worker.ts
949
- var wand = new WandService();
950
72
  addEventListener("message", ({ data }) => {
951
73
  try {
952
74
  const { width, height, originalWidth, originalHeight, scale, mode, sourceName, regions } = data;
@@ -955,7 +77,7 @@ addEventListener("message", ({ data }) => {
955
77
  width,
956
78
  height,
957
79
  mode,
958
- (xs, ys, w, h, holes) => wand.rasterizePolygon(xs, ys, w, h, holes),
80
+ rasterizePolygon,
959
81
  (done, total) => postMessage({ type: "progress", done, total })
960
82
  );
961
83
  if (!mask) {
@@ -979,10 +101,7 @@ addEventListener("message", ({ data }) => {
979
101
  depth: mask.bitDepth,
980
102
  text
981
103
  });
982
- postMessage(
983
- { type: "done", png },
984
- [png.buffer]
985
- );
104
+ postMessage({ type: "done", png }, [png.buffer]);
986
105
  } catch (err) {
987
106
  postMessage({ type: "error", error: err?.message ?? String(err) });
988
107
  }