@jax-data-science/sci-image-visualizer 0.1.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 (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +404 -0
  3. package/esm2022/index.mjs +52 -0
  4. package/esm2022/jax-data-science-sci-image-visualizer.mjs +5 -0
  5. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +398 -0
  6. package/esm2022/lib/contracts/capabilities.contract.mjs +32 -0
  7. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +12 -0
  8. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +14 -0
  9. package/esm2022/lib/contracts/colormap-lut.mjs +95 -0
  10. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +2 -0
  11. package/esm2022/lib/contracts/display-types.mjs +8 -0
  12. package/esm2022/lib/contracts/image.contract.mjs +11 -0
  13. package/esm2022/lib/contracts/intensity.mjs +28 -0
  14. package/esm2022/lib/contracts/plot-type.mjs +112 -0
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +3 -0
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +3 -0
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +3 -0
  18. package/esm2022/lib/contracts/ports/tile-access.port.mjs +3 -0
  19. package/esm2022/lib/contracts/region-editor-api.contract.mjs +4 -0
  20. package/esm2022/lib/contracts/region-overlay.contract.mjs +2 -0
  21. package/esm2022/lib/contracts/region-store.contract.mjs +2 -0
  22. package/esm2022/lib/contracts/sam.contract.mjs +12 -0
  23. package/esm2022/lib/contracts/toolbar-config.mjs +8 -0
  24. package/esm2022/lib/contracts/visualizer.contract.mjs +10 -0
  25. package/esm2022/lib/contracts/viz-config.mjs +3 -0
  26. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +260 -0
  27. package/esm2022/lib/implementations/base-store-visualizer.mjs +76 -0
  28. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +106 -0
  29. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +847 -0
  30. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +92 -0
  31. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2283 -0
  32. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +126 -0
  33. package/esm2022/lib/implementations/osd/display-pipeline.mjs +143 -0
  34. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +217 -0
  35. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +1780 -0
  36. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +25 -0
  37. package/esm2022/lib/implementations/osd/osd-coords.mjs +53 -0
  38. package/esm2022/lib/implementations/osd/osd-lib.mjs +20 -0
  39. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +1237 -0
  40. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +88 -0
  41. package/esm2022/lib/implementations/osd/slice-cache.mjs +488 -0
  42. package/esm2022/lib/implementations/osd/tile-client.mjs +29 -0
  43. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +37 -0
  44. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +31 -0
  45. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +183 -0
  46. package/esm2022/lib/implementations/plotly/plotly.service.mjs +2137 -0
  47. package/esm2022/lib/implementations/simple-slice-access.service.mjs +99 -0
  48. package/esm2022/lib/models/bezier.mjs +120 -0
  49. package/esm2022/lib/models/class-preset.mjs +46 -0
  50. package/esm2022/lib/models/geometry.mjs +198 -0
  51. package/esm2022/lib/models/region.mjs +166 -0
  52. package/esm2022/lib/models/shape.mjs +53 -0
  53. package/esm2022/lib/plot.utilities.mjs +693 -0
  54. package/esm2022/lib/processing/image-converter.service.mjs +90 -0
  55. package/esm2022/lib/processing/image-crop.mjs +62 -0
  56. package/esm2022/lib/processing/processing-image.mjs +50 -0
  57. package/esm2022/lib/provide-visualization.mjs +63 -0
  58. package/esm2022/lib/region-editor/mask-raster.mjs +95 -0
  59. package/esm2022/lib/region-editor/mask-worker.mjs +10 -0
  60. package/esm2022/lib/region-editor/region-editor.component.mjs +1190 -0
  61. package/esm2022/lib/region-ops.service.mjs +301 -0
  62. package/esm2022/lib/render-orchestrator.mjs +87 -0
  63. package/esm2022/lib/routing-visualizer.service.mjs +533 -0
  64. package/esm2022/lib/store/class-color.util.mjs +52 -0
  65. package/esm2022/lib/store/region-store.service.mjs +1029 -0
  66. package/esm2022/lib/store/visualizer-store.service.mjs +352 -0
  67. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +546 -0
  68. package/esm2022/lib/toolbar/crop/slide-crop.mjs +57 -0
  69. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +115 -0
  70. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +84 -0
  71. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +133 -0
  72. package/esm2022/lib/toolbar/segmentation/ort-runtime-config.mjs +31 -0
  73. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +108 -0
  74. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +159 -0
  75. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +255 -0
  76. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +94 -0
  77. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +188 -0
  78. package/esm2022/lib/toolbar/toolbar.component.mjs +311 -0
  79. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +234 -0
  80. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +499 -0
  81. package/esm2022/lib/toolbar/wand/wand.service.mjs +921 -0
  82. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +157 -0
  83. package/esm2022/lib/visualization.module.mjs +162 -0
  84. package/esm2022/lib/visualizer.component.mjs +1597 -0
  85. package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs +12 -0
  86. package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs.map +1 -0
  87. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs +327 -0
  88. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map +1 -0
  89. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21314 -0
  90. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -0
  91. package/fesm2022/mask.worker.js +989 -0
  92. package/fesm2022/onnx-sam.worker.js +202 -0
  93. package/index.d.ts +39 -0
  94. package/lib/channel-histogram/channel-histogram.component.d.ts +112 -0
  95. package/lib/contracts/capabilities.contract.d.ts +30 -0
  96. package/lib/contracts/cell-segmenter.contract.d.ts +40 -0
  97. package/lib/contracts/channel-histogram-api.contract.d.ts +98 -0
  98. package/lib/contracts/colormap-lut.d.ts +21 -0
  99. package/lib/contracts/coordinate-transform.contract.d.ts +43 -0
  100. package/lib/contracts/display-types.d.ts +41 -0
  101. package/lib/contracts/image.contract.d.ts +72 -0
  102. package/lib/contracts/intensity.d.ts +18 -0
  103. package/lib/contracts/plot-type.d.ts +108 -0
  104. package/lib/contracts/ports/image-state.port.d.ts +29 -0
  105. package/lib/contracts/ports/preferences.port.d.ts +19 -0
  106. package/lib/contracts/ports/region-io.port.d.ts +29 -0
  107. package/lib/contracts/ports/tile-access.port.d.ts +27 -0
  108. package/lib/contracts/region-editor-api.contract.d.ts +83 -0
  109. package/lib/contracts/region-overlay.contract.d.ts +47 -0
  110. package/lib/contracts/region-store.contract.d.ts +74 -0
  111. package/lib/contracts/sam.contract.d.ts +98 -0
  112. package/lib/contracts/toolbar-config.d.ts +24 -0
  113. package/lib/contracts/visualizer.contract.d.ts +346 -0
  114. package/lib/contracts/viz-config.d.ts +25 -0
  115. package/lib/hex-color-picker/hex-color-picker.component.d.ts +47 -0
  116. package/lib/implementations/base-store-visualizer.d.ts +71 -0
  117. package/lib/implementations/napari-js/napari-axes-labels.d.ts +47 -0
  118. package/lib/implementations/napari-js/napari-region-overlay.d.ts +115 -0
  119. package/lib/implementations/napari-js/napari-scale-bar.d.ts +31 -0
  120. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +455 -0
  121. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +46 -0
  122. package/lib/implementations/osd/display-pipeline.d.ts +47 -0
  123. package/lib/implementations/osd/histogram-sampler.d.ts +85 -0
  124. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +476 -0
  125. package/lib/implementations/osd/osd-coordinate-transform.d.ts +17 -0
  126. package/lib/implementations/osd/osd-coords.d.ts +16 -0
  127. package/lib/implementations/osd/osd-lib.d.ts +19 -0
  128. package/lib/implementations/osd/osd-region-overlay.d.ts +191 -0
  129. package/lib/implementations/osd/osd-scale-bar.d.ts +17 -0
  130. package/lib/implementations/osd/slice-cache.d.ts +161 -0
  131. package/lib/implementations/osd/tile-client.d.ts +32 -0
  132. package/lib/implementations/plotly/plotly-coordinate-transform.d.ts +19 -0
  133. package/lib/implementations/plotly/plotly-region-overlay.d.ts +23 -0
  134. package/lib/implementations/plotly/plotly-trace-builders.d.ts +60 -0
  135. package/lib/implementations/plotly/plotly.service.d.ts +594 -0
  136. package/lib/implementations/simple-slice-access.service.d.ts +64 -0
  137. package/lib/models/bezier.d.ts +59 -0
  138. package/lib/models/class-preset.d.ts +39 -0
  139. package/lib/models/geometry.d.ts +66 -0
  140. package/lib/models/region.d.ts +132 -0
  141. package/lib/models/shape.d.ts +44 -0
  142. package/lib/plot.utilities.d.ts +107 -0
  143. package/lib/processing/image-converter.service.d.ts +28 -0
  144. package/lib/processing/image-crop.d.ts +18 -0
  145. package/lib/processing/processing-image.d.ts +17 -0
  146. package/lib/provide-visualization.d.ts +34 -0
  147. package/lib/region-editor/mask-raster.d.ts +61 -0
  148. package/lib/region-editor/mask-worker.d.ts +7 -0
  149. package/lib/region-editor/region-editor.component.d.ts +305 -0
  150. package/lib/region-ops.service.d.ts +92 -0
  151. package/lib/render-orchestrator.d.ts +59 -0
  152. package/lib/routing-visualizer.service.d.ts +227 -0
  153. package/lib/store/class-color.util.d.ts +26 -0
  154. package/lib/store/region-store.service.d.ts +315 -0
  155. package/lib/store/visualizer-store.service.d.ts +123 -0
  156. package/lib/toolbar/brush/brush-tool.service.d.ts +143 -0
  157. package/lib/toolbar/crop/slide-crop.d.ts +30 -0
  158. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +32 -0
  159. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +39 -0
  160. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +25 -0
  161. package/lib/toolbar/segmentation/ort-runtime-config.d.ts +4 -0
  162. package/lib/toolbar/segmentation/sam-model-registry.d.ts +36 -0
  163. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +48 -0
  164. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +59 -0
  165. package/lib/toolbar/segmentation/sam-prompt.d.ts +34 -0
  166. package/lib/toolbar/segmentation/sam-tool.service.d.ts +50 -0
  167. package/lib/toolbar/toolbar.component.d.ts +167 -0
  168. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +64 -0
  169. package/lib/toolbar/wand/wand-tool.service.d.ts +149 -0
  170. package/lib/toolbar/wand/wand.service.d.ts +133 -0
  171. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +49 -0
  172. package/lib/visualization.module.d.ts +45 -0
  173. package/lib/visualizer.component.d.ts +378 -0
  174. package/package.json +73 -0
  175. package/src/lib/assets/3d-coordinates.svg +49 -0
  176. package/src/lib/assets/cells.svg +1 -0
  177. package/src/lib/assets/click.svg +1 -0
  178. package/src/lib/assets/colormap-luts.json +1 -0
  179. package/src/lib/assets/contour.svg +48 -0
  180. package/src/lib/assets/cube-3d.svg +1 -0
  181. package/src/lib/assets/edit-selection-white.svg +47 -0
  182. package/src/lib/assets/heatmap.svg +1 -0
  183. package/src/lib/assets/icons/colormap-Pastel1.png +0 -0
  184. package/src/lib/assets/icons/colormap-accent.png +0 -0
  185. package/src/lib/assets/icons/colormap-afmhot.png +0 -0
  186. package/src/lib/assets/icons/colormap-autumn.png +0 -0
  187. package/src/lib/assets/icons/colormap-berlin.png +0 -0
  188. package/src/lib/assets/icons/colormap-binary.png +0 -0
  189. package/src/lib/assets/icons/colormap-blackbody.png +0 -0
  190. package/src/lib/assets/icons/colormap-bluered.png +0 -0
  191. package/src/lib/assets/icons/colormap-blues.png +0 -0
  192. package/src/lib/assets/icons/colormap-bone.png +0 -0
  193. package/src/lib/assets/icons/colormap-brbg.png +0 -0
  194. package/src/lib/assets/icons/colormap-brg.png +0 -0
  195. package/src/lib/assets/icons/colormap-bugn.png +0 -0
  196. package/src/lib/assets/icons/colormap-bupu.png +0 -0
  197. package/src/lib/assets/icons/colormap-bwr.png +0 -0
  198. package/src/lib/assets/icons/colormap-cividis.png +0 -0
  199. package/src/lib/assets/icons/colormap-cmrmap.png +0 -0
  200. package/src/lib/assets/icons/colormap-cool.png +0 -0
  201. package/src/lib/assets/icons/colormap-coolwarm.png +0 -0
  202. package/src/lib/assets/icons/colormap-copper.png +0 -0
  203. package/src/lib/assets/icons/colormap-cubehelix.png +0 -0
  204. package/src/lib/assets/icons/colormap-dark2.png +0 -0
  205. package/src/lib/assets/icons/colormap-earth.png +0 -0
  206. package/src/lib/assets/icons/colormap-electric.png +0 -0
  207. package/src/lib/assets/icons/colormap-flag.png +0 -0
  208. package/src/lib/assets/icons/colormap-gist_earth.png +0 -0
  209. package/src/lib/assets/icons/colormap-gist_gray.png +0 -0
  210. package/src/lib/assets/icons/colormap-gist_heat.png +0 -0
  211. package/src/lib/assets/icons/colormap-gist_ncar.png +0 -0
  212. package/src/lib/assets/icons/colormap-gist_rainbow.png +0 -0
  213. package/src/lib/assets/icons/colormap-gist_stern.png +0 -0
  214. package/src/lib/assets/icons/colormap-gist_yarg.png +0 -0
  215. package/src/lib/assets/icons/colormap-gnbu.png +0 -0
  216. package/src/lib/assets/icons/colormap-gnuplot.png +0 -0
  217. package/src/lib/assets/icons/colormap-gnuplot2.png +0 -0
  218. package/src/lib/assets/icons/colormap-gray.png +0 -0
  219. package/src/lib/assets/icons/colormap-greens-inv.png +0 -0
  220. package/src/lib/assets/icons/colormap-greens.png +0 -0
  221. package/src/lib/assets/icons/colormap-greys-inv.png +0 -0
  222. package/src/lib/assets/icons/colormap-greys.png +0 -0
  223. package/src/lib/assets/icons/colormap-hot.png +0 -0
  224. package/src/lib/assets/icons/colormap-hsv.png +0 -0
  225. package/src/lib/assets/icons/colormap-inferno.png +0 -0
  226. package/src/lib/assets/icons/colormap-jet.png +0 -0
  227. package/src/lib/assets/icons/colormap-magma.png +0 -0
  228. package/src/lib/assets/icons/colormap-managua.png +0 -0
  229. package/src/lib/assets/icons/colormap-nipy_spectral.png +0 -0
  230. package/src/lib/assets/icons/colormap-ocean.png +0 -0
  231. package/src/lib/assets/icons/colormap-oranges.png +0 -0
  232. package/src/lib/assets/icons/colormap-orrd.png +0 -0
  233. package/src/lib/assets/icons/colormap-pastel2.png +0 -0
  234. package/src/lib/assets/icons/colormap-picnic.png +0 -0
  235. package/src/lib/assets/icons/colormap-pink.png +0 -0
  236. package/src/lib/assets/icons/colormap-piyg.png +0 -0
  237. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  238. package/src/lib/assets/icons/colormap-plasma.png +0 -0
  239. package/src/lib/assets/icons/colormap-portland.png +0 -0
  240. package/src/lib/assets/icons/colormap-prgn.png +0 -0
  241. package/src/lib/assets/icons/colormap-prism.png +0 -0
  242. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  243. package/src/lib/assets/icons/colormap-pubugn.png +0 -0
  244. package/src/lib/assets/icons/colormap-puor.png +0 -0
  245. package/src/lib/assets/icons/colormap-purd.png +0 -0
  246. package/src/lib/assets/icons/colormap-purples.png +0 -0
  247. package/src/lib/assets/icons/colormap-rainbow.png +0 -0
  248. package/src/lib/assets/icons/colormap-rdbu.png +0 -0
  249. package/src/lib/assets/icons/colormap-rdgy.png +0 -0
  250. package/src/lib/assets/icons/colormap-rdpu.png +0 -0
  251. package/src/lib/assets/icons/colormap-rdylbu.png +0 -0
  252. package/src/lib/assets/icons/colormap-rdylgn.png +0 -0
  253. package/src/lib/assets/icons/colormap-reds.png +0 -0
  254. package/src/lib/assets/icons/colormap-seismic.png +0 -0
  255. package/src/lib/assets/icons/colormap-set1.png +0 -0
  256. package/src/lib/assets/icons/colormap-set2.png +0 -0
  257. package/src/lib/assets/icons/colormap-set3.png +0 -0
  258. package/src/lib/assets/icons/colormap-spectral.png +0 -0
  259. package/src/lib/assets/icons/colormap-spring.png +0 -0
  260. package/src/lib/assets/icons/colormap-summer.png +0 -0
  261. package/src/lib/assets/icons/colormap-tab10.png +0 -0
  262. package/src/lib/assets/icons/colormap-tab20.png +0 -0
  263. package/src/lib/assets/icons/colormap-tab20b.png +0 -0
  264. package/src/lib/assets/icons/colormap-tab20c.png +0 -0
  265. package/src/lib/assets/icons/colormap-terrain.png +0 -0
  266. package/src/lib/assets/icons/colormap-turbo.png +0 -0
  267. package/src/lib/assets/icons/colormap-twilight.png +0 -0
  268. package/src/lib/assets/icons/colormap-twilight_shifted.png +0 -0
  269. package/src/lib/assets/icons/colormap-vanimo.png +0 -0
  270. package/src/lib/assets/icons/colormap-viridis.png +0 -0
  271. package/src/lib/assets/icons/colormap-winter.png +0 -0
  272. package/src/lib/assets/icons/colormap-wistia.png +0 -0
  273. package/src/lib/assets/icons/colormap-ylgn.png +0 -0
  274. package/src/lib/assets/icons/colormap-ylgnbu-inv.png +0 -0
  275. package/src/lib/assets/icons/colormap-ylgnbu.png +0 -0
  276. package/src/lib/assets/icons/colormap-ylorbr.png +0 -0
  277. package/src/lib/assets/icons/colormap-ylorrd-inv.png +0 -0
  278. package/src/lib/assets/icons/colormap-ylorrd.png +0 -0
  279. package/src/lib/assets/interactive-segmentation-cursor.svg +1 -0
  280. package/src/lib/assets/invert.svg +1 -0
  281. package/src/lib/assets/isosurface.svg +7 -0
  282. package/src/lib/assets/mask.svg +1 -0
  283. package/src/lib/assets/paintbrush.svg +1 -0
  284. package/src/lib/assets/picture-segmentation.svg +43 -0
  285. package/src/lib/assets/polygon-vertices.svg +13 -0
  286. package/src/lib/assets/polyline.svg +3 -0
  287. package/src/lib/assets/redo.svg +39 -0
  288. package/src/lib/assets/region-editor.svg +37 -0
  289. package/src/lib/assets/region-move.svg +7 -0
  290. package/src/lib/assets/smooth.svg +56 -0
  291. package/src/lib/assets/spline-chart.svg +7 -0
  292. package/src/lib/assets/surface.svg +37 -0
  293. package/src/lib/assets/test/download-379.svg +1 -0
  294. package/src/lib/assets/test/download-98.svg +1 -0
  295. package/src/lib/assets/test/json-1.svg +1 -0
  296. package/src/lib/assets/test/load-53.svg +1 -0
  297. package/src/lib/assets/test/mask-44.svg +1 -0
  298. package/src/lib/assets/test/mask-download-44.svg +15 -0
  299. package/src/lib/assets/test/mask-save-44.svg +11 -0
  300. package/src/lib/assets/test/overlay-1.svg +1 -0
  301. package/src/lib/assets/test/overlay-4.svg +1 -0
  302. package/src/lib/assets/test/region-26.svg +1 -0
  303. package/src/lib/assets/test/save-56.svg +1 -0
  304. package/src/lib/assets/test/upload-43.svg +1 -0
  305. package/src/lib/assets/to-bezier.svg +15 -0
  306. package/src/lib/assets/to-polygon.svg +11 -0
  307. package/src/lib/assets/undo.svg +38 -0
  308. package/src/lib/assets/vertex-add.svg +12 -0
  309. package/src/lib/assets/vertex-delete.svg +12 -0
  310. package/src/lib/assets/wand.svg +54 -0
  311. package/src/lib/assets/zoom-box.svg +10 -0
@@ -0,0 +1,202 @@
1
+ // src/lib/toolbar/segmentation/onnx-sam.worker.ts
2
+ import * as ort2 from "onnxruntime-web";
3
+
4
+ // src/lib/toolbar/segmentation/sam-onnx-core.ts
5
+ import * as ort from "onnxruntime-web";
6
+ var PIXEL_MEAN = [123.675, 116.28, 103.53];
7
+ var PIXEL_STD = [58.395, 57.12, 57.375];
8
+ var MODEL_CACHE = "sam-onnx";
9
+ async function fetchModel(url, onProgress) {
10
+ const cache = typeof caches !== "undefined" ? await caches.open(MODEL_CACHE).catch(() => null) : null;
11
+ const hit = cache ? await cache.match(url) : null;
12
+ if (hit) {
13
+ onProgress?.(1);
14
+ return await hit.arrayBuffer();
15
+ }
16
+ const resp = await fetch(url);
17
+ if (!resp.ok)
18
+ throw new Error(`fetch ${url} failed: HTTP ${resp.status}`);
19
+ const total = Number(resp.headers.get("content-length")) || 0;
20
+ if (!resp.body || !total) {
21
+ const buf = await resp.arrayBuffer();
22
+ onProgress?.(1);
23
+ if (cache)
24
+ await cache.put(url, new Response(buf)).catch(() => void 0);
25
+ return buf;
26
+ }
27
+ const reader = resp.body.getReader();
28
+ const chunks = [];
29
+ let received = 0;
30
+ for (; ; ) {
31
+ const { done, value } = await reader.read();
32
+ if (done)
33
+ break;
34
+ chunks.push(value);
35
+ received += value.length;
36
+ onProgress?.(received / total);
37
+ }
38
+ const out = new Uint8Array(received);
39
+ let off = 0;
40
+ for (const c of chunks) {
41
+ out.set(c, off);
42
+ off += c.length;
43
+ }
44
+ if (cache) {
45
+ await cache.put(url, new Response(out.slice(), { headers: { "content-length": String(received) } })).catch(() => void 0);
46
+ }
47
+ onProgress?.(1);
48
+ return out.buffer;
49
+ }
50
+ function preprocess(data, width, height, size, scale) {
51
+ const newW = Math.round(width * scale);
52
+ const newH = Math.round(height * scale);
53
+ const chw = new Float32Array(3 * size * size);
54
+ for (let y = 0; y < newH; y++) {
55
+ const sy = Math.min(height - 1, y / scale);
56
+ const y0 = Math.floor(sy);
57
+ const fy = sy - y0;
58
+ const y1 = Math.min(height - 1, y0 + 1);
59
+ for (let x = 0; x < newW; x++) {
60
+ const sx = Math.min(width - 1, x / scale);
61
+ const x0 = Math.floor(sx);
62
+ const fx = sx - x0;
63
+ const x1 = Math.min(width - 1, x0 + 1);
64
+ for (let c = 0; c < 3; c++) {
65
+ const p00 = data[(y0 * width + x0) * 4 + c];
66
+ const p01 = data[(y0 * width + x1) * 4 + c];
67
+ const p10 = data[(y1 * width + x0) * 4 + c];
68
+ const p11 = data[(y1 * width + x1) * 4 + c];
69
+ const top = p00 + (p01 - p00) * fx;
70
+ const bot = p10 + (p11 - p10) * fx;
71
+ const v = top + (bot - top) * fy;
72
+ chw[c * size * size + y * size + x] = (v - PIXEL_MEAN[c]) / PIXEL_STD[c];
73
+ }
74
+ }
75
+ }
76
+ return chw;
77
+ }
78
+ function buildDecoderPrompt(prompt, scale) {
79
+ const coords = [];
80
+ const labels = [];
81
+ for (const p of prompt.points ?? []) {
82
+ coords.push(p.x * scale, p.y * scale);
83
+ labels.push(p.label);
84
+ }
85
+ if (prompt.box) {
86
+ const b = prompt.box;
87
+ coords.push(b.x0 * scale, b.y0 * scale);
88
+ labels.push(2);
89
+ coords.push(b.x1 * scale, b.y1 * scale);
90
+ labels.push(3);
91
+ } else if (labels.length > 0) {
92
+ coords.push(0, 0);
93
+ labels.push(-1);
94
+ }
95
+ return {
96
+ pointCoords: Float32Array.from(coords),
97
+ pointLabels: Float32Array.from(labels),
98
+ numPoints: labels.length
99
+ };
100
+ }
101
+ function binarizeMask(logits, threshold = 0) {
102
+ const out = new Uint8Array(logits.length);
103
+ for (let i = 0; i < logits.length; i++)
104
+ out[i] = logits[i] > threshold ? 1 : 0;
105
+ return out;
106
+ }
107
+ function bestMaskIndex(iou) {
108
+ let best = 0;
109
+ for (let i = 1; i < iou.length; i++)
110
+ if (iou[i] > iou[best])
111
+ best = i;
112
+ return best;
113
+ }
114
+ async function runEncoder(encoder2, data, width, height, inputSize2) {
115
+ const scale = inputSize2 / Math.max(width, height);
116
+ const input = preprocess(data, width, height, inputSize2, scale);
117
+ const out = await encoder2.run({
118
+ [encoder2.inputNames[0]]: new ort.Tensor("float32", input, [1, 3, inputSize2, inputSize2])
119
+ });
120
+ const emb = out[encoder2.outputNames[0]];
121
+ return {
122
+ data: emb.data,
123
+ dims: emb.dims,
124
+ scale,
125
+ imageWidth: width,
126
+ imageHeight: height
127
+ };
128
+ }
129
+ async function runDecoder(decoder2, e, prompt) {
130
+ const { pointCoords, pointLabels, numPoints } = buildDecoderPrompt(prompt, e.scale);
131
+ const out = await decoder2.run({
132
+ image_embeddings: new ort.Tensor("float32", e.data, e.dims),
133
+ point_coords: new ort.Tensor("float32", pointCoords, [1, numPoints, 2]),
134
+ point_labels: new ort.Tensor("float32", pointLabels, [1, numPoints]),
135
+ mask_input: new ort.Tensor("float32", new Float32Array(256 * 256), [1, 1, 256, 256]),
136
+ has_mask_input: new ort.Tensor("float32", Float32Array.from([0]), [1]),
137
+ orig_im_size: new ort.Tensor("float32", Float32Array.from([e.imageHeight, e.imageWidth]), [2])
138
+ });
139
+ const masks = out["masks"] ?? out[decoder2.outputNames[0]];
140
+ const iou = out["iou_predictions"]?.data ?? Float32Array.from([1]);
141
+ const [, m, h, w] = masks.dims;
142
+ const idx = bestMaskIndex(iou.slice(0, m));
143
+ const logits = masks.data.subarray(idx * h * w, (idx + 1) * h * w);
144
+ return { mask: binarizeMask(logits), width: w, height: h, iou: iou[idx] ?? 1 };
145
+ }
146
+
147
+ // src/lib/toolbar/segmentation/onnx-sam.worker.ts
148
+ var encoder = null;
149
+ var decoder = null;
150
+ var inputSize = 1024;
151
+ var nextToken = 1;
152
+ var embeddings = /* @__PURE__ */ new Map();
153
+ function post(msg, transfer = []) {
154
+ self.postMessage(msg, transfer);
155
+ }
156
+ async function onLoad(msg) {
157
+ ort2.env.wasm.wasmPaths = msg.wasmPaths;
158
+ inputSize = msg.inputSize || 1024;
159
+ const hasGpu = typeof navigator !== "undefined" && "gpu" in navigator;
160
+ const eps = msg.encoderProviders && msg.encoderProviders.length ? msg.encoderProviders : hasGpu ? ["webgpu", "wasm"] : ["wasm"];
161
+ const encBuf = await fetchModel(msg.encoderUrl, (f) => post({ id: msg.id, type: "progress", fraction: f }));
162
+ const decBuf = await fetchModel(msg.decoderUrl);
163
+ encoder = await ort2.InferenceSession.create(encBuf, { executionProviders: eps });
164
+ decoder = await ort2.InferenceSession.create(decBuf, { executionProviders: ["wasm"] });
165
+ post({ id: msg.id, type: "loaded" });
166
+ }
167
+ async function onEmbed(msg) {
168
+ if (!encoder)
169
+ throw new Error("SAM encoder not loaded.");
170
+ const data = new Uint8ClampedArray(msg.buffer);
171
+ const e = await runEncoder(encoder, data, msg.width, msg.height, inputSize);
172
+ const token = nextToken++;
173
+ embeddings.set(token, e);
174
+ if (embeddings.size > 3)
175
+ embeddings.delete(embeddings.keys().next().value);
176
+ post({ id: msg.id, type: "embedded", token, scale: e.scale, imageWidth: e.imageWidth, imageHeight: e.imageHeight, dims: e.dims });
177
+ }
178
+ async function onDecode(msg) {
179
+ if (!decoder)
180
+ throw new Error("SAM decoder not loaded.");
181
+ const e = embeddings.get(msg.token);
182
+ if (!e)
183
+ throw new Error("SAM embedding expired; re-encode the image.");
184
+ const r = await runDecoder(decoder, e, msg.prompt);
185
+ post(
186
+ { id: msg.id, type: "decoded", width: r.width, height: r.height, iou: r.iou, buffer: r.mask.buffer },
187
+ [r.mask.buffer]
188
+ );
189
+ }
190
+ self.onmessage = async (ev) => {
191
+ const msg = ev.data;
192
+ try {
193
+ if (msg.type === "load")
194
+ await onLoad(msg);
195
+ else if (msg.type === "embed")
196
+ await onEmbed(msg);
197
+ else if (msg.type === "decode")
198
+ await onDecode(msg);
199
+ } catch (err) {
200
+ post({ id: msg.id, type: "error", error: err instanceof Error ? err.message : String(err) });
201
+ }
202
+ };
package/index.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Public API of the jax-image-visualization library. External consumers import
3
+ * ONLY from here (`@jax-data-science/sci-image-visualizer`); everything else under `lib/` is
4
+ * internal. The surface is contracts + tokens + neutral models + the Angular
5
+ * module, plus the routing service the host's composition root binds the tokens
6
+ * to (`useExisting`).
7
+ */
8
+ export * from './lib/contracts/visualizer.contract';
9
+ export * from './lib/contracts/region-editor-api.contract';
10
+ export * from './lib/contracts/ports/image-state.port';
11
+ export * from './lib/contracts/ports/tile-access.port';
12
+ export * from './lib/contracts/ports/region-io.port';
13
+ export * from './lib/contracts/ports/preferences.port';
14
+ export * from './lib/contracts/channel-histogram-api.contract';
15
+ export * from './lib/contracts/viz-config';
16
+ export * from './lib/contracts/image.contract';
17
+ export * from './lib/contracts/plot-type';
18
+ export * from './lib/contracts/toolbar-config';
19
+ export * from './lib/contracts/capabilities.contract';
20
+ export * from './lib/contracts/region-overlay.contract';
21
+ export * from './lib/contracts/display-types';
22
+ export * from './lib/contracts/sam.contract';
23
+ export * from './lib/contracts/cell-segmenter.contract';
24
+ export { CellposeSegmenterService } from './lib/toolbar/segmentation/cellpose-segmenter.service';
25
+ export { ProcessingImage } from './lib/processing/processing-image';
26
+ export { cropImage, CropImageOptions } from './lib/processing/image-crop';
27
+ export { ImageConverterService } from './lib/processing/image-converter.service';
28
+ export { SAM_MODELS, DEFAULT_SAM_MODEL_ID, getSamModel, isSamModelReady, setSamModelUrls, setDefaultSamModel, getDefaultSamModelId, } from './lib/toolbar/segmentation/sam-model-registry';
29
+ export { setOrtWasmBase, getOrtWasmBase } from './lib/toolbar/segmentation/ort-runtime-config';
30
+ export * from './lib/models/region';
31
+ export * from './lib/models/class-preset';
32
+ export { ShapeSelection } from './lib/models/shape';
33
+ export { VisualizationModule } from './lib/visualization.module';
34
+ export { RoutingVisualizerService } from './lib/routing-visualizer.service';
35
+ export { provideVisualization } from './lib/provide-visualization';
36
+ export { VisualizerComponent } from './lib/visualizer.component';
37
+ export { RegionEditorComponent } from './lib/region-editor/region-editor.component';
38
+ export { HexColorPickerComponent } from './lib/hex-color-picker/hex-color-picker.component';
39
+ export { ChannelHistogramComponent } from './lib/channel-histogram/channel-histogram.component';
@@ -0,0 +1,112 @@
1
+ import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
+ import { TreeNode } from 'primeng/api';
3
+ import { IChannelHistogramApi, IChannelState, IHistogram } from '../contracts/channel-histogram-api.contract';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Channels & Histogram pane: a non-modal, resizable, draggable dialog for
7
+ * brightness/contrast (per-channel display window), gamma, channel
8
+ * visibility/colour, the intensity histogram, and the colormap/reverse/invert
9
+ * controls (moved here from the toolbar). Every edit flows through
10
+ * {@link CHANNEL_HISTOGRAM_API} into the shared store, and both rendering
11
+ * backends recolor the displayed image live. The pane depends only on the
12
+ * contract, never the concrete visualizer.
13
+ */
14
+ export declare class ChannelHistogramComponent implements OnInit, OnDestroy {
15
+ private api;
16
+ /** Dialog visibility, two-way bound so the host (toolbar button) can open it. */
17
+ visible: boolean;
18
+ visibleChange: EventEmitter<boolean>;
19
+ readonly histogramDiv = "channel-histogram-plot";
20
+ readonly lutColors: readonly {
21
+ name: string;
22
+ color: string;
23
+ }[];
24
+ channels: IChannelState[];
25
+ selected: IChannelState | null;
26
+ invert: boolean;
27
+ logScale: boolean;
28
+ /** Bounded retries while the (async) histogram sampling resolves. */
29
+ private histRetries;
30
+ /** The selected channel's current histogram. Native bit depth (with
31
+ * observed/range fields) for >8-bit images, else the 8-bit client histogram.
32
+ * Drives the plot, the native window labels, and the export-button gate. */
33
+ hist: IHistogram | null;
34
+ private histSub?;
35
+ /** Which window control is being adjusted right now — drives a small
36
+ * non-blocking activity spinner next to that slider, since the image recolor
37
+ * isn't instant on large stacks. Cleared a short moment after movement stops
38
+ * (the recolor isn't directly observable, so this is a trailing heuristic). */
39
+ activeAdjust: 'min' | 'max' | 'gamma' | null;
40
+ private adjustTimer?;
41
+ colormapOptions: any;
42
+ selectedColormap: any;
43
+ private subs;
44
+ /** Keeps the Plotly histogram sized to the (resizable) dialog body. */
45
+ private resizeObserver?;
46
+ constructor(api: IChannelHistogramApi);
47
+ /** Per-channel pseudo-colour only applies when there's more than one channel
48
+ * (RGB / fluorescence). A single grayscale channel uses the colormap instead. */
49
+ get multichannel(): boolean;
50
+ ngOnInit(): void;
51
+ ngOnDestroy(): void;
52
+ onVisibleChange(v: boolean): void;
53
+ /** p-dialog (onShow): the plot div now exists, so draw the histogram and keep
54
+ * it sized to the dialog (which is resizable) via a ResizeObserver. */
55
+ onShow(): void;
56
+ private teardownResize;
57
+ selectChannel(ch: IChannelState): void;
58
+ onMinChange(value: any): void;
59
+ onMaxChange(value: any): void;
60
+ onGammaChange(value: any): void;
61
+ /** Flag a control as actively adjusting so its spinner shows; auto-clears a
62
+ * short moment after the last change (kept alive while the user keeps
63
+ * dragging, since each change resets the timer). */
64
+ private markBusy;
65
+ onVisibleToggle(ch: IChannelState, value: boolean): void;
66
+ onColorChange(ch: IChannelState, color: string): void;
67
+ onColormap(node: TreeNode): void;
68
+ onInvert(value: boolean): void;
69
+ toggleLog(value: boolean): void;
70
+ /** Quick-assign a preset LUT colour to a channel (Fiji palette). */
71
+ setPreset(ch: IChannelState, color: string): void;
72
+ /** Export the displayed composite as a publication-ready PNG (8-bit figure). */
73
+ exportComposite(): void;
74
+ /** Export the underlying data as a true-16-bit multi-band TIFF (server-side). */
75
+ exportData(): void;
76
+ /** True when the current channel histogram is native >8-bit (16-bit etc.):
77
+ * gates the native slider labelling and the 16-bit TIFF export button. */
78
+ get is16bit(): boolean;
79
+ /** The native value range the 8-bit display window maps onto — the observed
80
+ * pixel extremes for a native histogram, else plain 0..255 (so 8-bit images
81
+ * pass through unchanged). The 8-bit tile is server-stretched across this
82
+ * range, so it's the best client-side native↔display mapping. */
83
+ private obsRange;
84
+ /** 8-bit display value (0..255) → native units. */
85
+ private toNative;
86
+ /** Native units → clamped 8-bit display value (0..255). */
87
+ private toDisp;
88
+ /** Selected channel window endpoints in native units (for the sliders). */
89
+ get minNative(): number;
90
+ get maxNative(): number;
91
+ /** Native slider bounds + step (256 display steps across the native range). */
92
+ get sliderMin(): number;
93
+ get sliderMax(): number;
94
+ get sliderStep(): number;
95
+ auto(): void;
96
+ reset(): void;
97
+ /** Saturation-based auto-window over a (native or 8-bit) histogram: pick
98
+ * [min,max] so ~`saturation` of pixels clip at each end, dropping a dominant
99
+ * first/last bin (background/padding). Returns native bin values. */
100
+ private autoWindow;
101
+ /** Fetch the selected channel's histogram (native for 16-bit, else 8-bit) and
102
+ * (re)draw it. Async — the native path hits the server; the 8-bit path may be
103
+ * null until tile sampling resolves, so we retry a few times. */
104
+ private loadHistogram;
105
+ private renderHistogram;
106
+ /** Move only the min/max marker lines (cheap) without recomputing counts. */
107
+ private updateMarkers;
108
+ private markerShapes;
109
+ private histogramLayout;
110
+ static ɵfac: i0.ɵɵFactoryDeclaration<ChannelHistogramComponent, never>;
111
+ static ɵcmp: i0.ɵɵComponentDeclaration<ChannelHistogramComponent, "channel-histogram", never, { "visible": { "alias": "visible"; "required": false; }; }, { "visibleChange": "visibleChange"; }, never, never, false, never>;
112
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Optional features a viewer backend may or may not support. Consumers query
3
+ * `IImageViewer.capabilities` and degrade gracefully (hide a toolbar item,
4
+ * skip a render path) rather than calling a method that no-ops.
5
+ *
6
+ * The Plotly backend supports the scientific/data features; the OpenSeadragon
7
+ * backend supports `ImageDisplay` (large zoomable image) but not the
8
+ * scalar-data features. The eventual router picks a backend per plot type.
9
+ */
10
+ export declare enum ViewerFeature {
11
+ /** Display a raster/tiled image (HEATMAP/RGB image, OSD's strength). */
12
+ ImageDisplay = "imageDisplay",
13
+ /** 3D scene rendering (SURFACE, SCATTER3D, ISOSURFACE). */
14
+ Surface3D = "surface3d",
15
+ /** Live colormap/LUT applied to a raw scalar matrix. */
16
+ ScalarColormap = "scalarColormap",
17
+ /** Read back the displayed pixel matrix (getDisplayedPixelData). */
18
+ PixelReadback = "pixelReadback",
19
+ /** Server re-fetch of a higher-res crop on zoom (vs native tiling). */
20
+ HighDefZoom = "highDefZoom",
21
+ /** Per-z-plane slider over an image stack. */
22
+ StackSlider = "stackSlider",
23
+ /** Live isosurface intensity bounds (isomin/isomax) — see IIsosurfaceControls. */
24
+ Isosurface = "isosurface"
25
+ }
26
+ export interface ViewerCapabilities {
27
+ has(feature: ViewerFeature): boolean;
28
+ }
29
+ /** Build a `ViewerCapabilities` from a fixed feature set. */
30
+ export declare function capabilitiesOf(features: Iterable<ViewerFeature>): ViewerCapabilities;
@@ -0,0 +1,40 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ /**
3
+ * Result of an automatic cell segmenter: a per-pixel instance label map for the
4
+ * input image (0 = background, 1..count = instances), row-major.
5
+ */
6
+ export interface CellSegmentation {
7
+ labels: Uint32Array;
8
+ width: number;
9
+ height: number;
10
+ count: number;
11
+ }
12
+ /**
13
+ * Port for an automatic (prompt-free) cell segmenter — e.g. cellpose-SAM. The
14
+ * library calls this on a client slide-crop of a drawn box. By default the
15
+ * {@link CELL_SEGMENTER} token resolves to the library's own cellpose-js-backed
16
+ * {@link CellposeSegmenterService} (so the toolbar Cellpose tool works out of the
17
+ * box), but a host can override the token to supply a different implementation
18
+ * (e.g. a server-side segmenter) (jit-ui#90).
19
+ */
20
+ /** Progress/status callbacks for a segmentation run (all optional). */
21
+ export interface CellSegmentProgress {
22
+ /** Model-download progress, 0..1 (first run only). */
23
+ onProgress?: (fraction: number) => void;
24
+ /** Human-readable phase, e.g. 'Running inference (tile 3/8)…'. */
25
+ onStatus?: (status: string) => void;
26
+ }
27
+ export interface ICellSegmenter {
28
+ /** Segment all cells in an RGBA image into an instance label map. */
29
+ segmentCells(image: {
30
+ data: Uint8ClampedArray;
31
+ width: number;
32
+ height: number;
33
+ }, progress?: CellSegmentProgress): Promise<CellSegmentation>;
34
+ }
35
+ /**
36
+ * DI token for the automatic cell segmenter. Defaults to the in-library
37
+ * {@link CellposeSegmenterService} (cellpose-js, lazy-loaded); override it in the
38
+ * host to swap implementations.
39
+ */
40
+ export declare const CELL_SEGMENTER: InjectionToken<ICellSegmenter>;
@@ -0,0 +1,98 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import { IImageMetadata } from './image.contract';
4
+ import { ColormapNode } from './display-types';
5
+ /**
6
+ * Display state for one image channel in the Channels & Histogram pane.
7
+ * `min`/`max` are the display window (contrast/brightness) in raw 0..255 space;
8
+ * `gamma` shapes the transfer curve; `color` is the channel's display tint
9
+ * (used when compositing multiple channels); `visible` toggles it on/off.
10
+ */
11
+ export interface IChannelState {
12
+ index: number;
13
+ name: string;
14
+ /** Display tint as `#rrggbb`. */
15
+ color: string;
16
+ min: number;
17
+ max: number;
18
+ gamma: number;
19
+ visible: boolean;
20
+ }
21
+ /** The standard LUT pseudo-colours (mirrors Fiji's Merge Channels palette) for
22
+ * quick per-channel assignment. */
23
+ export declare const LUT_COLORS: ReadonlyArray<{
24
+ name: string;
25
+ color: string;
26
+ }>;
27
+ /** A binned intensity histogram for one channel.
28
+ *
29
+ * The 8-bit client path (RGB / 8-bit grayscale, sampled from displayed tiles)
30
+ * leaves the native fields undefined and `bins` span 0..255. The native path
31
+ * (>8-bit images, from the server `/histogram` endpoint) fills `bitDepth`,
32
+ * `rangeMin`/`rangeMax` (the pixel-type span the bins cover) and
33
+ * `observedMin`/`observedMax` (the actual extremes seen), so the dialog can
34
+ * label the window/axis in native units. */
35
+ export interface IHistogram {
36
+ /** Left edge of each bin (0..255 for the 8-bit path, native units otherwise). */
37
+ bins: number[];
38
+ /** Pixel count per bin, length = bin count. */
39
+ counts: number[];
40
+ /** Largest bin count, for y-axis scaling. */
41
+ max: number;
42
+ /** Native bit depth (8, 16, …) — present only on the native server path. */
43
+ bitDepth?: number;
44
+ /** Pixel-type range the bins span (e.g. 0..65535), native path only. */
45
+ rangeMin?: number;
46
+ rangeMax?: number;
47
+ /** Actual min/max pixel observed (auto-contrast seed), native path only. */
48
+ observedMin?: number;
49
+ observedMax?: number;
50
+ }
51
+ /**
52
+ * Public, implementation-agnostic surface the Channels & Histogram pane (an
53
+ * external consumer of the visualization package) depends on. It exposes the
54
+ * per-channel display window/gamma/visibility, an intensity histogram computed
55
+ * from the currently-displayed pixels, and the LUT/colormap controls that used
56
+ * to live in the toolbar. The pane injects this via {@link CHANNEL_HISTOGRAM_API}
57
+ * (bound to the concrete `RoutingVisualizerService` with `useExisting`) so it
58
+ * never reaches the implementation. Every setter live-updates whichever backend
59
+ * (Plotly or OpenSeadragon) is on screen.
60
+ */
61
+ export interface IChannelHistogramApi {
62
+ /** The channels of the current image (1 for grayscale, 3 for RGB). */
63
+ getChannels$(): Observable<IChannelState[]>;
64
+ /** Patch one channel's state (window/gamma/visibility/color); live-updates. */
65
+ setChannelState(index: number, partial: Partial<IChannelState>): void;
66
+ /** Auto-window the given channels by saturating `saturation` (0..1) of pixels
67
+ * at each end of their histogram. */
68
+ autoContrast(indices: number[], saturation: number): void;
69
+ /** Reset the given channels to their derived defaults: full display range
70
+ * (0..255), gamma 1, and the channel's default tint colour. */
71
+ resetContrast(indices: number[]): void;
72
+ /** Binned histogram for a channel from the displayed pixels, or null when no
73
+ * image/pixels are available. Synchronous 8-bit path (used by auto-contrast). */
74
+ getHistogram(channelIndex: number, bins: number): IHistogram | null;
75
+ /** Histogram for a channel as an async stream: emits the **native** bit-depth
76
+ * histogram (from the server) for >8-bit images, else the 8-bit client
77
+ * histogram. The dialog uses this so 16-bit stacks get a true distribution. */
78
+ getHistogram$(channelIndex: number, bins: number): Observable<IHistogram | null>;
79
+ getColormap(): Observable<ColormapNode | null>;
80
+ setColormap(colormap: ColormapNode): void;
81
+ getColormapOptions(): ColormapNode[];
82
+ getReverseScale(): Observable<boolean>;
83
+ setReverseScale(reverse: boolean): void;
84
+ getGrayscale$(): Observable<boolean>;
85
+ setGrayscale(on: boolean): void;
86
+ getInvert$(): Observable<boolean>;
87
+ setInvert(on: boolean): void;
88
+ getImageMeta(): Observable<IImageMetadata[]>;
89
+ /** Export the displayed image — composited with the current per-channel
90
+ * pseudo-colours / window / colormap — as a publication-ready PNG download. */
91
+ exportComposite(): void;
92
+ /** Export the underlying image data — all (or the visible) channels at native
93
+ * bit depth — as a data-preserving multi-band TIFF download. Server-side, so
94
+ * it keeps true 16-bit values (the PNG composite is an 8-bit figure). Only
95
+ * meaningful for >8-bit images; a no-op on backends that can't provide it. */
96
+ exportData(): void;
97
+ }
98
+ export declare const CHANNEL_HISTOGRAM_API: InjectionToken<IChannelHistogramApi>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Colormap → RGB lookup-table builder.
3
+ *
4
+ * Lets a non-Plotly backend (OpenSeadragon) recolor grayscale pixels with the
5
+ * exact same colormaps the Plotly heatmap uses. The input is a colormap value
6
+ * straight from `COLORMAP_OPTIONS` (see plot.utilities) — the same value handed
7
+ * to Plotly's `colorscale` — so the two surfaces stay in lock-step.
8
+ *
9
+ * A colormap value is either:
10
+ * - an array of `[stop, color]` pairs (the matplotlib `*_LUT` constants), or
11
+ * - a Plotly built-in scale *name* string (e.g. 'Viridis', 'Reds').
12
+ * `color` may be `'rgb(r, g, b)'` or `'#rrggbb'`/`'#rgb'`.
13
+ */
14
+ export type Rgb = [number, number, number];
15
+ /**
16
+ * Build a 256-entry RGB lookup table from a `COLORMAP_OPTIONS` value, indexed by
17
+ * grayscale value 0–255. Returns null if the value can't be resolved to a scale.
18
+ * @param value array of `[stop, color]` pairs, or a Plotly built-in name string
19
+ * @param reverse mirror the scale (matches Plotly's `reversescale`)
20
+ */
21
+ export declare function buildColormapLut(value: unknown, reverse?: boolean): Rgb[] | null;
@@ -0,0 +1,43 @@
1
+ import { Region } from '../models/region';
2
+ /**
3
+ * The viewport math the on-canvas tools (wand, vertex eraser) need, abstracted
4
+ * away from any specific backend. Plotly implements it over its axis objects
5
+ * (`_fullLayout.xaxis/yaxis`), OpenSeadragon over its viewport API. This is what
6
+ * lets the tools run on either backend.
7
+ *
8
+ * "Data coordinates" are the backend's shape coordinate space: Plotly data
9
+ * coords for Plotly, image-pixel coords for OpenSeadragon. The tools convert
10
+ * data -> image-matrix using the per-image ratio they already get from the host
11
+ * (`getCachedImageData().ratios` / `getCachedImageRatio()`), so that division
12
+ * stays in the tool and the transform stays purely screen<->data.
13
+ */
14
+ export interface ICoordinateTransform {
15
+ /** Client (mouse event) pixel -> data coordinates. */
16
+ clientToData(clientX: number, clientY: number): {
17
+ x: number;
18
+ y: number;
19
+ };
20
+ /** A length in data coordinates -> length in screen pixels. */
21
+ dataLengthToScreen(dataLength: number): number;
22
+ /** True once the viewport is laid out and conversions are valid. */
23
+ isReady(): boolean;
24
+ }
25
+ /** What a backend supplies so the tools can attach + convert coordinates. */
26
+ export interface IViewportHost {
27
+ /** The element the tool's canvas overlay attaches to (fills the plot area). */
28
+ getOverlayContainer(): HTMLElement | null;
29
+ /** Live coordinate transform for the current viewport state. */
30
+ getCoordinateTransform(): ICoordinateTransform;
31
+ }
32
+ /**
33
+ * Region read/write access for the on-canvas tools, in the backend-neutral
34
+ * {@link Region} model — so the wand and vertex eraser operate on regions, not
35
+ * a backend's own shape representation. Both backends implement this by
36
+ * delegating to the shared RegionStore.
37
+ */
38
+ export interface IRegionDataHost {
39
+ /** Current regions (neutral model). */
40
+ getRegions(): Region[];
41
+ /** Commit the (possibly mutated) region set; the backend renders + emits. */
42
+ setRegions(regions: Region[]): void;
43
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Publication-critical types that were `any` on the public contracts
3
+ * (refactoring plan, Step 6). Deliberately permissive — every field optional —
4
+ * so existing hosts (which pass PrimeNG `TreeNode`s and plain option objects)
5
+ * keep compiling unchanged while consumers finally get named shapes.
6
+ */
7
+ /** A colormap value as Plotly understands it: a built-in scale name (e.g.
8
+ * 'Viridis') or an inline array of `[stop, color]` pairs. */
9
+ export type ColormapValue = string | Array<[number, string]>;
10
+ /** One node of the colormap selector tree (structurally compatible with the
11
+ * PrimeNG `TreeNode`s the host passes): group nodes carry `children`, leaf
12
+ * nodes carry the scale in `data.value` (+ a preview image in `data.src`). */
13
+ export interface ColormapNode {
14
+ label?: string;
15
+ data?: {
16
+ value?: ColormapValue;
17
+ src?: string;
18
+ };
19
+ children?: ColormapNode[];
20
+ }
21
+ /** Magic-wand pixel-comparison space. */
22
+ export type WandType = 'GRAY' | 'RGB' | 'LAB_DISTANCE';
23
+ /** Options for the magic-wand tool (QuPath-style). */
24
+ export interface IWandOptions {
25
+ type?: WandType;
26
+ /** Gaussian sigma applied to the patch before thresholding. */
27
+ sigma?: number;
28
+ /** Higher = stricter (smaller selection) for GRAY/RGB; higher = looser for
29
+ * LAB_DISTANCE — matches QuPath. */
30
+ sensitivity?: number;
31
+ /** Square patch size in pixels (must be odd). */
32
+ patchSize?: number;
33
+ /** When true, skip blur/threshold and flood-fill at exact-match
34
+ * (Cmd/Ctrl-click in QuPath). */
35
+ simpleMode?: boolean;
36
+ }
37
+ /** Options for the brush region tool (QuPath-style). */
38
+ export interface IBrushOptions {
39
+ /** Brush diameter in matrix (image) pixels. */
40
+ size?: number;
41
+ }