@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,108 @@
1
+ /**
2
+ * Registry of promptable SAM models for the browser segment tool.
3
+ *
4
+ * micro-sam (microscopy-finetuned, promptable) and patho-sam (histopathology-
5
+ * finetuned) are entries; SAM3 slots in here once its quantized ONNX export and
6
+ * a `variant: 'sam3'` decoder path are published. The
7
+ * automatic cellpose-SAM model is intentionally NOT here — it's not promptable
8
+ * and lives in the processing-pipeline's cellpose engine as the automatic tool.
9
+ *
10
+ * `encoderUrl` / `decoderUrl` point at the public HF-hosted ONNX pairs by
11
+ * default, so the segment tools work out of the box in any host (mirroring the
12
+ * cellpose default). A host can repoint them at its own hosting (e.g. a GCS
13
+ * bucket) at runtime via {@link setSamModelUrls}; an empty URL disables a model
14
+ * (the session throws a clear "not configured" error). Export/quantization
15
+ * tooling: the sibling `browser-onnx-tools` project; see docs/sam-segmentation-design.md.
16
+ */
17
+ export const SAM_MODELS = [
18
+ {
19
+ id: 'microsam-vit-t-lm',
20
+ label: 'micro-sam ViT-T',
21
+ encoderUrl: 'https://huggingface.co/Ballon999/microsam-vit-t-lm-onnx/resolve/main/encoder.fp16.onnx',
22
+ decoderUrl: 'https://huggingface.co/Ballon999/microsam-vit-t-lm-onnx/resolve/main/decoder.onnx',
23
+ variant: 'sam1',
24
+ inputSize: 1024,
25
+ microscopy: true,
26
+ // TinyViT's fp16 attention overflows on the onnxruntime-web WebGPU EP and
27
+ // returns an empty mask ("No masks found"); it's numerically correct on
28
+ // WASM, and the encoder is tiny (~14 MB) so WASM is plenty fast.
29
+ encoderProviders: ['wasm'],
30
+ // Small enough to run in-process on the main thread — avoids the Web
31
+ // Worker's spawn / second-ORT-runtime / round-trip overhead, which made it
32
+ // noticeably slower to load and segment.
33
+ inProcess: true,
34
+ },
35
+ {
36
+ id: 'microsam-vit-b-lm',
37
+ label: 'micro-sam ViT-B',
38
+ encoderUrl: 'https://huggingface.co/Ballon999/microsam-vit-b-lm-onnx/resolve/main/encoder.fp16.onnx',
39
+ decoderUrl: 'https://huggingface.co/Ballon999/microsam-vit-b-lm-onnx/resolve/main/decoder.onnx',
40
+ variant: 'sam1',
41
+ inputSize: 1024,
42
+ microscopy: true,
43
+ },
44
+ {
45
+ id: 'patho-sam-vit-b',
46
+ label: 'patho-sam ViT-B',
47
+ encoderUrl: 'https://huggingface.co/Ballon999/patho-sam-vit-b-onnx/resolve/main/encoder.fp16.onnx',
48
+ decoderUrl: 'https://huggingface.co/Ballon999/patho-sam-vit-b-onnx/resolve/main/decoder.onnx',
49
+ variant: 'sam1',
50
+ inputSize: 1024,
51
+ microscopy: true,
52
+ },
53
+ {
54
+ id: 'patho-sam-vit-b-int8',
55
+ label: 'patho-sam ViT-B (int8)',
56
+ encoderUrl: 'https://huggingface.co/Ballon999/patho-sam-vit-b-onnx/resolve/main/encoder.int8.onnx',
57
+ decoderUrl: 'https://huggingface.co/Ballon999/patho-sam-vit-b-onnx/resolve/main/decoder.onnx',
58
+ variant: 'sam1',
59
+ inputSize: 1024,
60
+ microscopy: true,
61
+ // int8 dynamic-quantized encoder (~100 MB vs ~180 MB fp16, IoU ~0.99 on the
62
+ // sanity test). onnxruntime-web's WebGPU EP doesn't support int8 matmul, so
63
+ // it runs on WASM — smaller download, slower encode than the fp16 entry.
64
+ encoderProviders: ['wasm'],
65
+ },
66
+ ];
67
+ /** Initial default model id (overridden at runtime once the host configures a
68
+ * hosted model via {@link setSamModelUrls}). */
69
+ export const DEFAULT_SAM_MODEL_ID = SAM_MODELS[0].id;
70
+ /** The active default — updated when the host configures a model's ONNX URLs,
71
+ * so the tool uses the model that's actually hosted (not just the first entry). */
72
+ let activeDefaultId = DEFAULT_SAM_MODEL_ID;
73
+ /** Look up a model by id; falls back to the active default when id is
74
+ * unknown/absent. */
75
+ export function getSamModel(id) {
76
+ const wanted = id ?? activeDefaultId;
77
+ return SAM_MODELS.find((m) => m.id === wanted) ?? SAM_MODELS[0];
78
+ }
79
+ /** The active default model id (what the tools/picker use when unset). */
80
+ export function getDefaultSamModelId() {
81
+ return activeDefaultId;
82
+ }
83
+ /** Set the active default model id (must be a registered model). */
84
+ export function setDefaultSamModel(id) {
85
+ if (SAM_MODELS.some((m) => m.id === id))
86
+ activeDefaultId = id;
87
+ }
88
+ /** True when a model has both ONNX URLs configured (i.e. it can actually run). */
89
+ export function isSamModelReady(model) {
90
+ return !!model.encoderUrl && !!model.decoderUrl;
91
+ }
92
+ /**
93
+ * Point a registered model at its hosted ONNX pair (HF / GCS). Called by the
94
+ * host's composition root once hosting is decided, keeping deployment URLs out
95
+ * of the library.
96
+ */
97
+ export function setSamModelUrls(id, encoderUrl, decoderUrl) {
98
+ const m = SAM_MODELS.find((x) => x.id === id);
99
+ if (m) {
100
+ m.encoderUrl = encoderUrl;
101
+ m.decoderUrl = decoderUrl;
102
+ // The configured (hosted) model becomes the active default, so the tools
103
+ // use it rather than the first registry entry (which may be unhosted).
104
+ if (encoderUrl && decoderUrl)
105
+ activeDefaultId = id;
106
+ }
107
+ }
108
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLW1vZGVsLXJlZ2lzdHJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi90b29sYmFyL3NlZ21lbnRhdGlvbi9zYW0tbW9kZWwtcmVnaXN0cnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFrQjtJQUN2QztRQUNFLEVBQUUsRUFBRSxtQkFBbUI7UUFDdkIsS0FBSyxFQUFFLGlCQUFpQjtRQUN4QixVQUFVLEVBQUUsd0ZBQXdGO1FBQ3BHLFVBQVUsRUFBRSxtRkFBbUY7UUFDL0YsT0FBTyxFQUFFLE1BQU07UUFDZixTQUFTLEVBQUUsSUFBSTtRQUNmLFVBQVUsRUFBRSxJQUFJO1FBQ2hCLDBFQUEwRTtRQUMxRSx3RUFBd0U7UUFDeEUsaUVBQWlFO1FBQ2pFLGdCQUFnQixFQUFFLENBQUMsTUFBTSxDQUFDO1FBQzFCLHFFQUFxRTtRQUNyRSwyRUFBMkU7UUFDM0UseUNBQXlDO1FBQ3pDLFNBQVMsRUFBRSxJQUFJO0tBQ2hCO0lBQ0Q7UUFDRSxFQUFFLEVBQUUsbUJBQW1CO1FBQ3ZCLEtBQUssRUFBRSxpQkFBaUI7UUFDeEIsVUFBVSxFQUFFLHdGQUF3RjtRQUNwRyxVQUFVLEVBQUUsbUZBQW1GO1FBQy9GLE9BQU8sRUFBRSxNQUFNO1FBQ2YsU0FBUyxFQUFFLElBQUk7UUFDZixVQUFVLEVBQUUsSUFBSTtLQUNqQjtJQUNEO1FBQ0UsRUFBRSxFQUFFLGlCQUFpQjtRQUNyQixLQUFLLEVBQUUsaUJBQWlCO1FBQ3hCLFVBQVUsRUFBRSxzRkFBc0Y7UUFDbEcsVUFBVSxFQUFFLGlGQUFpRjtRQUM3RixPQUFPLEVBQUUsTUFBTTtRQUNmLFNBQVMsRUFBRSxJQUFJO1FBQ2YsVUFBVSxFQUFFLElBQUk7S0FDakI7SUFDRDtRQUNFLEVBQUUsRUFBRSxzQkFBc0I7UUFDMUIsS0FBSyxFQUFFLHdCQUF3QjtRQUMvQixVQUFVLEVBQUUsc0ZBQXNGO1FBQ2xHLFVBQVUsRUFBRSxpRkFBaUY7UUFDN0YsT0FBTyxFQUFFLE1BQU07UUFDZixTQUFTLEVBQUUsSUFBSTtRQUNmLFVBQVUsRUFBRSxJQUFJO1FBQ2hCLDRFQUE0RTtRQUM1RSw0RUFBNEU7UUFDNUUseUVBQXlFO1FBQ3pFLGdCQUFnQixFQUFFLENBQUMsTUFBTSxDQUFDO0tBQzNCO0NBQ0YsQ0FBQztBQUVGO2lEQUNpRDtBQUNqRCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0FBRXJEO29GQUNvRjtBQUNwRixJQUFJLGVBQWUsR0FBRyxvQkFBb0IsQ0FBQztBQUUzQztzQkFDc0I7QUFDdEIsTUFBTSxVQUFVLFdBQVcsQ0FBQyxFQUFXO0lBQ3JDLE1BQU0sTUFBTSxHQUFHLEVBQUUsSUFBSSxlQUFlLENBQUM7SUFDckMsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLE1BQU0sQ0FBQyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBRUQsMEVBQTBFO0FBQzFFLE1BQU0sVUFBVSxvQkFBb0I7SUFDbEMsT0FBTyxlQUFlLENBQUM7QUFDekIsQ0FBQztBQUVELG9FQUFvRTtBQUNwRSxNQUFNLFVBQVUsa0JBQWtCLENBQUMsRUFBVTtJQUMzQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQUUsZUFBZSxHQUFHLEVBQUUsQ0FBQztBQUNoRSxDQUFDO0FBRUQsa0ZBQWtGO0FBQ2xGLE1BQU0sVUFBVSxlQUFlLENBQUMsS0FBa0I7SUFDaEQsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQztBQUNsRCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsRUFBVSxFQUFFLFVBQWtCLEVBQUUsVUFBa0I7SUFDaEYsTUFBTSxDQUFDLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUM5QyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ04sQ0FBQyxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDMUIsQ0FBQyxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDMUIseUVBQXlFO1FBQ3pFLHVFQUF1RTtRQUN2RSxJQUFJLFVBQVUsSUFBSSxVQUFVO1lBQUUsZUFBZSxHQUFHLEVBQUUsQ0FBQztJQUNyRCxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFNhbU1vZGVsRGVmIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NhbS5jb250cmFjdCc7XG5cbi8qKlxuICogUmVnaXN0cnkgb2YgcHJvbXB0YWJsZSBTQU0gbW9kZWxzIGZvciB0aGUgYnJvd3NlciBzZWdtZW50IHRvb2wuXG4gKlxuICogbWljcm8tc2FtIChtaWNyb3Njb3B5LWZpbmV0dW5lZCwgcHJvbXB0YWJsZSkgYW5kIHBhdGhvLXNhbSAoaGlzdG9wYXRob2xvZ3ktXG4gKiBmaW5ldHVuZWQpIGFyZSBlbnRyaWVzOyBTQU0zIHNsb3RzIGluIGhlcmUgb25jZSBpdHMgcXVhbnRpemVkIE9OTlggZXhwb3J0IGFuZFxuICogYSBgdmFyaWFudDogJ3NhbTMnYCBkZWNvZGVyIHBhdGggYXJlIHB1Ymxpc2hlZC4gVGhlXG4gKiBhdXRvbWF0aWMgY2VsbHBvc2UtU0FNIG1vZGVsIGlzIGludGVudGlvbmFsbHkgTk9UIGhlcmUg4oCUIGl0J3Mgbm90IHByb21wdGFibGVcbiAqIGFuZCBsaXZlcyBpbiB0aGUgcHJvY2Vzc2luZy1waXBlbGluZSdzIGNlbGxwb3NlIGVuZ2luZSBhcyB0aGUgYXV0b21hdGljIHRvb2wuXG4gKlxuICogYGVuY29kZXJVcmxgIC8gYGRlY29kZXJVcmxgIHBvaW50IGF0IHRoZSBwdWJsaWMgSEYtaG9zdGVkIE9OTlggcGFpcnMgYnlcbiAqIGRlZmF1bHQsIHNvIHRoZSBzZWdtZW50IHRvb2xzIHdvcmsgb3V0IG9mIHRoZSBib3ggaW4gYW55IGhvc3QgKG1pcnJvcmluZyB0aGVcbiAqIGNlbGxwb3NlIGRlZmF1bHQpLiBBIGhvc3QgY2FuIHJlcG9pbnQgdGhlbSBhdCBpdHMgb3duIGhvc3RpbmcgKGUuZy4gYSBHQ1NcbiAqIGJ1Y2tldCkgYXQgcnVudGltZSB2aWEge0BsaW5rIHNldFNhbU1vZGVsVXJsc307IGFuIGVtcHR5IFVSTCBkaXNhYmxlcyBhIG1vZGVsXG4gKiAodGhlIHNlc3Npb24gdGhyb3dzIGEgY2xlYXIgXCJub3QgY29uZmlndXJlZFwiIGVycm9yKS4gRXhwb3J0L3F1YW50aXphdGlvblxuICogdG9vbGluZzogdGhlIHNpYmxpbmcgYGJyb3dzZXItb25ueC10b29sc2AgcHJvamVjdDsgc2VlIGRvY3Mvc2FtLXNlZ21lbnRhdGlvbi1kZXNpZ24ubWQuXG4gKi9cbmV4cG9ydCBjb25zdCBTQU1fTU9ERUxTOiBTYW1Nb2RlbERlZltdID0gW1xuICB7XG4gICAgaWQ6ICdtaWNyb3NhbS12aXQtdC1sbScsXG4gICAgbGFiZWw6ICdtaWNyby1zYW0gVmlULVQnLFxuICAgIGVuY29kZXJVcmw6ICdodHRwczovL2h1Z2dpbmdmYWNlLmNvL0JhbGxvbjk5OS9taWNyb3NhbS12aXQtdC1sbS1vbm54L3Jlc29sdmUvbWFpbi9lbmNvZGVyLmZwMTYub25ueCcsXG4gICAgZGVjb2RlclVybDogJ2h0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vQmFsbG9uOTk5L21pY3Jvc2FtLXZpdC10LWxtLW9ubngvcmVzb2x2ZS9tYWluL2RlY29kZXIub25ueCcsXG4gICAgdmFyaWFudDogJ3NhbTEnLFxuICAgIGlucHV0U2l6ZTogMTAyNCxcbiAgICBtaWNyb3Njb3B5OiB0cnVlLFxuICAgIC8vIFRpbnlWaVQncyBmcDE2IGF0dGVudGlvbiBvdmVyZmxvd3Mgb24gdGhlIG9ubnhydW50aW1lLXdlYiBXZWJHUFUgRVAgYW5kXG4gICAgLy8gcmV0dXJucyBhbiBlbXB0eSBtYXNrIChcIk5vIG1hc2tzIGZvdW5kXCIpOyBpdCdzIG51bWVyaWNhbGx5IGNvcnJlY3Qgb25cbiAgICAvLyBXQVNNLCBhbmQgdGhlIGVuY29kZXIgaXMgdGlueSAofjE0IE1CKSBzbyBXQVNNIGlzIHBsZW50eSBmYXN0LlxuICAgIGVuY29kZXJQcm92aWRlcnM6IFsnd2FzbSddLFxuICAgIC8vIFNtYWxsIGVub3VnaCB0byBydW4gaW4tcHJvY2VzcyBvbiB0aGUgbWFpbiB0aHJlYWQg4oCUIGF2b2lkcyB0aGUgV2ViXG4gICAgLy8gV29ya2VyJ3Mgc3Bhd24gLyBzZWNvbmQtT1JULXJ1bnRpbWUgLyByb3VuZC10cmlwIG92ZXJoZWFkLCB3aGljaCBtYWRlIGl0XG4gICAgLy8gbm90aWNlYWJseSBzbG93ZXIgdG8gbG9hZCBhbmQgc2VnbWVudC5cbiAgICBpblByb2Nlc3M6IHRydWUsXG4gIH0sXG4gIHtcbiAgICBpZDogJ21pY3Jvc2FtLXZpdC1iLWxtJyxcbiAgICBsYWJlbDogJ21pY3JvLXNhbSBWaVQtQicsXG4gICAgZW5jb2RlclVybDogJ2h0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vQmFsbG9uOTk5L21pY3Jvc2FtLXZpdC1iLWxtLW9ubngvcmVzb2x2ZS9tYWluL2VuY29kZXIuZnAxNi5vbm54JyxcbiAgICBkZWNvZGVyVXJsOiAnaHR0cHM6Ly9odWdnaW5nZmFjZS5jby9CYWxsb245OTkvbWljcm9zYW0tdml0LWItbG0tb25ueC9yZXNvbHZlL21haW4vZGVjb2Rlci5vbm54JyxcbiAgICB2YXJpYW50OiAnc2FtMScsXG4gICAgaW5wdXRTaXplOiAxMDI0LFxuICAgIG1pY3Jvc2NvcHk6IHRydWUsXG4gIH0sXG4gIHtcbiAgICBpZDogJ3BhdGhvLXNhbS12aXQtYicsXG4gICAgbGFiZWw6ICdwYXRoby1zYW0gVmlULUInLFxuICAgIGVuY29kZXJVcmw6ICdodHRwczovL2h1Z2dpbmdmYWNlLmNvL0JhbGxvbjk5OS9wYXRoby1zYW0tdml0LWItb25ueC9yZXNvbHZlL21haW4vZW5jb2Rlci5mcDE2Lm9ubngnLFxuICAgIGRlY29kZXJVcmw6ICdodHRwczovL2h1Z2dpbmdmYWNlLmNvL0JhbGxvbjk5OS9wYXRoby1zYW0tdml0LWItb25ueC9yZXNvbHZlL21haW4vZGVjb2Rlci5vbm54JyxcbiAgICB2YXJpYW50OiAnc2FtMScsXG4gICAgaW5wdXRTaXplOiAxMDI0LFxuICAgIG1pY3Jvc2NvcHk6IHRydWUsXG4gIH0sXG4gIHtcbiAgICBpZDogJ3BhdGhvLXNhbS12aXQtYi1pbnQ4JyxcbiAgICBsYWJlbDogJ3BhdGhvLXNhbSBWaVQtQiAoaW50OCknLFxuICAgIGVuY29kZXJVcmw6ICdodHRwczovL2h1Z2dpbmdmYWNlLmNvL0JhbGxvbjk5OS9wYXRoby1zYW0tdml0LWItb25ueC9yZXNvbHZlL21haW4vZW5jb2Rlci5pbnQ4Lm9ubngnLFxuICAgIGRlY29kZXJVcmw6ICdodHRwczovL2h1Z2dpbmdmYWNlLmNvL0JhbGxvbjk5OS9wYXRoby1zYW0tdml0LWItb25ueC9yZXNvbHZlL21haW4vZGVjb2Rlci5vbm54JyxcbiAgICB2YXJpYW50OiAnc2FtMScsXG4gICAgaW5wdXRTaXplOiAxMDI0LFxuICAgIG1pY3Jvc2NvcHk6IHRydWUsXG4gICAgLy8gaW50OCBkeW5hbWljLXF1YW50aXplZCBlbmNvZGVyICh+MTAwIE1CIHZzIH4xODAgTUIgZnAxNiwgSW9VIH4wLjk5IG9uIHRoZVxuICAgIC8vIHNhbml0eSB0ZXN0KS4gb25ueHJ1bnRpbWUtd2ViJ3MgV2ViR1BVIEVQIGRvZXNuJ3Qgc3VwcG9ydCBpbnQ4IG1hdG11bCwgc29cbiAgICAvLyBpdCBydW5zIG9uIFdBU00g4oCUIHNtYWxsZXIgZG93bmxvYWQsIHNsb3dlciBlbmNvZGUgdGhhbiB0aGUgZnAxNiBlbnRyeS5cbiAgICBlbmNvZGVyUHJvdmlkZXJzOiBbJ3dhc20nXSxcbiAgfSxcbl07XG5cbi8qKiBJbml0aWFsIGRlZmF1bHQgbW9kZWwgaWQgKG92ZXJyaWRkZW4gYXQgcnVudGltZSBvbmNlIHRoZSBob3N0IGNvbmZpZ3VyZXMgYVxuICogIGhvc3RlZCBtb2RlbCB2aWEge0BsaW5rIHNldFNhbU1vZGVsVXJsc30pLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfU0FNX01PREVMX0lEID0gU0FNX01PREVMU1swXS5pZDtcblxuLyoqIFRoZSBhY3RpdmUgZGVmYXVsdCDigJQgdXBkYXRlZCB3aGVuIHRoZSBob3N0IGNvbmZpZ3VyZXMgYSBtb2RlbCdzIE9OTlggVVJMcyxcbiAqICBzbyB0aGUgdG9vbCB1c2VzIHRoZSBtb2RlbCB0aGF0J3MgYWN0dWFsbHkgaG9zdGVkIChub3QganVzdCB0aGUgZmlyc3QgZW50cnkpLiAqL1xubGV0IGFjdGl2ZURlZmF1bHRJZCA9IERFRkFVTFRfU0FNX01PREVMX0lEO1xuXG4vKiogTG9vayB1cCBhIG1vZGVsIGJ5IGlkOyBmYWxscyBiYWNrIHRvIHRoZSBhY3RpdmUgZGVmYXVsdCB3aGVuIGlkIGlzXG4gKiAgdW5rbm93bi9hYnNlbnQuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2FtTW9kZWwoaWQ/OiBzdHJpbmcpOiBTYW1Nb2RlbERlZiB7XG4gIGNvbnN0IHdhbnRlZCA9IGlkID8/IGFjdGl2ZURlZmF1bHRJZDtcbiAgcmV0dXJuIFNBTV9NT0RFTFMuZmluZCgobSkgPT4gbS5pZCA9PT0gd2FudGVkKSA/PyBTQU1fTU9ERUxTWzBdO1xufVxuXG4vKiogVGhlIGFjdGl2ZSBkZWZhdWx0IG1vZGVsIGlkICh3aGF0IHRoZSB0b29scy9waWNrZXIgdXNlIHdoZW4gdW5zZXQpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldERlZmF1bHRTYW1Nb2RlbElkKCk6IHN0cmluZyB7XG4gIHJldHVybiBhY3RpdmVEZWZhdWx0SWQ7XG59XG5cbi8qKiBTZXQgdGhlIGFjdGl2ZSBkZWZhdWx0IG1vZGVsIGlkIChtdXN0IGJlIGEgcmVnaXN0ZXJlZCBtb2RlbCkuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0RGVmYXVsdFNhbU1vZGVsKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKFNBTV9NT0RFTFMuc29tZSgobSkgPT4gbS5pZCA9PT0gaWQpKSBhY3RpdmVEZWZhdWx0SWQgPSBpZDtcbn1cblxuLyoqIFRydWUgd2hlbiBhIG1vZGVsIGhhcyBib3RoIE9OTlggVVJMcyBjb25maWd1cmVkIChpLmUuIGl0IGNhbiBhY3R1YWxseSBydW4pLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2FtTW9kZWxSZWFkeShtb2RlbDogU2FtTW9kZWxEZWYpOiBib29sZWFuIHtcbiAgcmV0dXJuICEhbW9kZWwuZW5jb2RlclVybCAmJiAhIW1vZGVsLmRlY29kZXJVcmw7XG59XG5cbi8qKlxuICogUG9pbnQgYSByZWdpc3RlcmVkIG1vZGVsIGF0IGl0cyBob3N0ZWQgT05OWCBwYWlyIChIRiAvIEdDUykuIENhbGxlZCBieSB0aGVcbiAqIGhvc3QncyBjb21wb3NpdGlvbiByb290IG9uY2UgaG9zdGluZyBpcyBkZWNpZGVkLCBrZWVwaW5nIGRlcGxveW1lbnQgVVJMcyBvdXRcbiAqIG9mIHRoZSBsaWJyYXJ5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0U2FtTW9kZWxVcmxzKGlkOiBzdHJpbmcsIGVuY29kZXJVcmw6IHN0cmluZywgZGVjb2RlclVybDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IG0gPSBTQU1fTU9ERUxTLmZpbmQoKHgpID0+IHguaWQgPT09IGlkKTtcbiAgaWYgKG0pIHtcbiAgICBtLmVuY29kZXJVcmwgPSBlbmNvZGVyVXJsO1xuICAgIG0uZGVjb2RlclVybCA9IGRlY29kZXJVcmw7XG4gICAgLy8gVGhlIGNvbmZpZ3VyZWQgKGhvc3RlZCkgbW9kZWwgYmVjb21lcyB0aGUgYWN0aXZlIGRlZmF1bHQsIHNvIHRoZSB0b29sc1xuICAgIC8vIHVzZSBpdCByYXRoZXIgdGhhbiB0aGUgZmlyc3QgcmVnaXN0cnkgZW50cnkgKHdoaWNoIG1heSBiZSB1bmhvc3RlZCkuXG4gICAgaWYgKGVuY29kZXJVcmwgJiYgZGVjb2RlclVybCkgYWN0aXZlRGVmYXVsdElkID0gaWQ7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,159 @@
1
+ import * as ort from 'onnxruntime-web';
2
+ /**
3
+ * Shared, DOM-free SAM inference primitives used by BOTH inference backends:
4
+ * the in-process session (`OnnxSamSession`, main thread) and the dedicated
5
+ * Web Worker (`onnx-sam.worker`). Keeping these here avoids duplicating the
6
+ * preprocessing / decoder-prompt math and keeps the worker DOM-free (it can't
7
+ * import sam-prompt.ts, which pulls in DOM types).
8
+ */
9
+ export const PIXEL_MEAN = [123.675, 116.28, 103.53];
10
+ export const PIXEL_STD = [58.395, 57.12, 57.375];
11
+ const MODEL_CACHE = 'sam-onnx';
12
+ /** Fetch a model as an ArrayBuffer, streaming progress and caching in the Cache
13
+ * API (so it isn't re-downloaded). Cache hit → progress jumps to 1. Works on
14
+ * the main thread and in a worker (both have `fetch` + `caches`). */
15
+ export async function fetchModel(url, onProgress) {
16
+ const cache = typeof caches !== 'undefined' ? await caches.open(MODEL_CACHE).catch(() => null) : null;
17
+ const hit = cache ? await cache.match(url) : null;
18
+ if (hit) {
19
+ onProgress?.(1);
20
+ return await hit.arrayBuffer();
21
+ }
22
+ const resp = await fetch(url);
23
+ if (!resp.ok)
24
+ throw new Error(`fetch ${url} failed: HTTP ${resp.status}`);
25
+ const total = Number(resp.headers.get('content-length')) || 0;
26
+ if (!resp.body || !total) {
27
+ const buf = await resp.arrayBuffer();
28
+ onProgress?.(1);
29
+ if (cache)
30
+ await cache.put(url, new Response(buf)).catch(() => undefined);
31
+ return buf;
32
+ }
33
+ const reader = resp.body.getReader();
34
+ const chunks = [];
35
+ let received = 0;
36
+ for (;;) {
37
+ const { done, value } = await reader.read();
38
+ if (done)
39
+ break;
40
+ chunks.push(value);
41
+ received += value.length;
42
+ onProgress?.(received / total);
43
+ }
44
+ const out = new Uint8Array(received);
45
+ let off = 0;
46
+ for (const c of chunks) {
47
+ out.set(c, off);
48
+ off += c.length;
49
+ }
50
+ if (cache) {
51
+ await cache.put(url, new Response(out.slice(), { headers: { 'content-length': String(received) } }))
52
+ .catch(() => undefined);
53
+ }
54
+ onProgress?.(1);
55
+ return out.buffer;
56
+ }
57
+ /** Resize (long side → size, bilinear), pad to size×size, SAM-normalize → CHW float32. */
58
+ export function preprocess(data, width, height, size, scale) {
59
+ const newW = Math.round(width * scale);
60
+ const newH = Math.round(height * scale);
61
+ const chw = new Float32Array(3 * size * size); // zero-padded
62
+ for (let y = 0; y < newH; y++) {
63
+ const sy = Math.min(height - 1, y / scale);
64
+ const y0 = Math.floor(sy);
65
+ const fy = sy - y0;
66
+ const y1 = Math.min(height - 1, y0 + 1);
67
+ for (let x = 0; x < newW; x++) {
68
+ const sx = Math.min(width - 1, x / scale);
69
+ const x0 = Math.floor(sx);
70
+ const fx = sx - x0;
71
+ const x1 = Math.min(width - 1, x0 + 1);
72
+ for (let c = 0; c < 3; c++) {
73
+ const p00 = data[(y0 * width + x0) * 4 + c];
74
+ const p01 = data[(y0 * width + x1) * 4 + c];
75
+ const p10 = data[(y1 * width + x0) * 4 + c];
76
+ const p11 = data[(y1 * width + x1) * 4 + c];
77
+ const top = p00 + (p01 - p00) * fx;
78
+ const bot = p10 + (p11 - p10) * fx;
79
+ const v = top + (bot - top) * fy;
80
+ chw[c * size * size + y * size + x] = (v - PIXEL_MEAN[c]) / PIXEL_STD[c];
81
+ }
82
+ }
83
+ }
84
+ return chw;
85
+ }
86
+ /** Assemble decoder `point_coords`/`point_labels` from a prompt, in encoder
87
+ * (resized) space. Box = two points labelled 2/3; points use 1/0; a points-only
88
+ * prompt pads the absent box slot with `[0,0]` labelled -1. */
89
+ export function buildDecoderPrompt(prompt, scale) {
90
+ const coords = [];
91
+ const labels = [];
92
+ for (const p of prompt.points ?? []) {
93
+ coords.push(p.x * scale, p.y * scale);
94
+ labels.push(p.label);
95
+ }
96
+ if (prompt.box) {
97
+ const b = prompt.box;
98
+ coords.push(b.x0 * scale, b.y0 * scale);
99
+ labels.push(2);
100
+ coords.push(b.x1 * scale, b.y1 * scale);
101
+ labels.push(3);
102
+ }
103
+ else if (labels.length > 0) {
104
+ coords.push(0, 0);
105
+ labels.push(-1);
106
+ }
107
+ return {
108
+ pointCoords: Float32Array.from(coords),
109
+ pointLabels: Float32Array.from(labels),
110
+ numPoints: labels.length,
111
+ };
112
+ }
113
+ /** Binarize mask logits (`> threshold`) into a 0/1 mask. */
114
+ export function binarizeMask(logits, threshold = 0) {
115
+ const out = new Uint8Array(logits.length);
116
+ for (let i = 0; i < logits.length; i++)
117
+ out[i] = logits[i] > threshold ? 1 : 0;
118
+ return out;
119
+ }
120
+ /** Index of the highest-scoring mask in a multimask decoder output. */
121
+ export function bestMaskIndex(iou) {
122
+ let best = 0;
123
+ for (let i = 1; i < iou.length; i++)
124
+ if (iou[i] > iou[best])
125
+ best = i;
126
+ return best;
127
+ }
128
+ /** Run the encoder on an RGBA image → a reusable embedding. */
129
+ export async function runEncoder(encoder, data, width, height, inputSize) {
130
+ const scale = inputSize / Math.max(width, height);
131
+ const input = preprocess(data, width, height, inputSize, scale);
132
+ const out = await encoder.run({
133
+ [encoder.inputNames[0]]: new ort.Tensor('float32', input, [1, 3, inputSize, inputSize]),
134
+ });
135
+ const emb = out[encoder.outputNames[0]];
136
+ return {
137
+ data: emb.data, dims: emb.dims,
138
+ scale, imageWidth: width, imageHeight: height,
139
+ };
140
+ }
141
+ /** Run the decoder for one prompt against a cached embedding → a binary mask. */
142
+ export async function runDecoder(decoder, e, prompt) {
143
+ const { pointCoords, pointLabels, numPoints } = buildDecoderPrompt(prompt, e.scale);
144
+ const out = await decoder.run({
145
+ image_embeddings: new ort.Tensor('float32', e.data, e.dims),
146
+ point_coords: new ort.Tensor('float32', pointCoords, [1, numPoints, 2]),
147
+ point_labels: new ort.Tensor('float32', pointLabels, [1, numPoints]),
148
+ mask_input: new ort.Tensor('float32', new Float32Array(256 * 256), [1, 1, 256, 256]),
149
+ has_mask_input: new ort.Tensor('float32', Float32Array.from([0]), [1]),
150
+ orig_im_size: new ort.Tensor('float32', Float32Array.from([e.imageHeight, e.imageWidth]), [2]),
151
+ });
152
+ const masks = out['masks'] ?? out[decoder.outputNames[0]];
153
+ const iou = out['iou_predictions']?.data ?? Float32Array.from([1]);
154
+ const [, m, h, w] = masks.dims;
155
+ const idx = bestMaskIndex(iou.slice(0, m));
156
+ const logits = masks.data.subarray(idx * h * w, (idx + 1) * h * w);
157
+ return { mask: binarizeMask(logits), width: w, height: h, iou: iou[idx] ?? 1 };
158
+ }
159
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLW9ubngtY29yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLW9ubngtY29yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssR0FBRyxNQUFNLGlCQUFpQixDQUFDO0FBSXZDOzs7Ozs7R0FNRztBQUVILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDcEQsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNqRCxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUM7QUFtQi9COztzRUFFc0U7QUFDdEUsTUFBTSxDQUFDLEtBQUssVUFBVSxVQUFVLENBQUMsR0FBVyxFQUFFLFVBQWdDO0lBQzVFLE1BQU0sS0FBSyxHQUFHLE9BQU8sTUFBTSxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ3RHLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDbEQsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsT0FBTyxNQUFNLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUFDLENBQUM7SUFFN0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDOUIsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQUUs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RyxLQUFLLENBQUMsQ0FBQztRQUMzQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzFCLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7UUFDbkIsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN4QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDOUIsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQztZQUMxQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzFCLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7WUFDbkIsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUN2QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQzNCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLEVBQUUsR0FBRyxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUM1QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQyxFQUFFLEdBQUcsS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDNUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsRUFBRSxHQUFHLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FB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TSxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQy9GLENBQUMsQ0FBQztJQUNILE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFELE1BQU0sR0FBRyxHQUFJLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLElBQXFCLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckYsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBZ0IsQ0FBQztJQUMzQyxNQUFNLEdBQUcsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzQyxNQUFNLE1BQU0sR0FBSSxLQUFLLENBQUMsSUFBcUIsQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLE9BQU8sRUFBRSxJQUFJLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0FBQ2pGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBvcnQgZnJvbSAnb25ueHJ1bnRpbWUtd2ViJztcblxuaW1wb3J0IHR5cGUgeyBTYW1Qcm9tcHQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc2FtLmNvbnRyYWN0JztcblxuLyoqXG4gKiBTaGFyZWQsIERPTS1mcmVlIFNBTSBpbmZlcmVuY2UgcHJpbWl0aXZlcyB1c2VkIGJ5IEJPVEggaW5mZXJlbmNlIGJhY2tlbmRzOlxuICogdGhlIGluLXByb2Nlc3Mgc2Vzc2lvbiAoYE9ubnhTYW1TZXNzaW9uYCwgbWFpbiB0aHJlYWQpIGFuZCB0aGUgZGVkaWNhdGVkXG4gKiBXZWIgV29ya2VyIChgb25ueC1zYW0ud29ya2VyYCkuIEtlZXBpbmcgdGhlc2UgaGVyZSBhdm9pZHMgZHVwbGljYXRpbmcgdGhlXG4gKiBwcmVwcm9jZXNzaW5nIC8gZGVjb2Rlci1wcm9tcHQgbWF0aCBhbmQga2VlcHMgdGhlIHdvcmtlciBET00tZnJlZSAoaXQgY2FuJ3RcbiAqIGltcG9ydCBzYW0tcHJvbXB0LnRzLCB3aGljaCBwdWxscyBpbiBET00gdHlwZXMpLlxuICovXG5cbmV4cG9ydCBjb25zdCBQSVhFTF9NRUFOID0gWzEyMy42NzUsIDExNi4yOCwgMTAzLjUzXTtcbmV4cG9ydCBjb25zdCBQSVhFTF9TVEQgPSBbNTguMzk1LCA1Ny4xMiwgNTcuMzc1XTtcbmNvbnN0IE1PREVMX0NBQ0hFID0gJ3NhbS1vbm54JztcblxuLyoqIEVuY29kZXIgb3V0cHV0IGZvciBvbmUgaW1hZ2UsIHJldXNlZCBhY3Jvc3MgcHJvbXB0cy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29yZUVtYmVkZGluZyB7XG4gIGRhdGE6IEZsb2F0MzJBcnJheTtcbiAgZGltczogbnVtYmVyW107XG4gIHNjYWxlOiBudW1iZXI7XG4gIGltYWdlV2lkdGg6IG51bWJlcjtcbiAgaW1hZ2VIZWlnaHQ6IG51bWJlcjtcbn1cblxuLyoqIERlY29kZXIgb3V0cHV0OiBhIGJpbmFyeSBtYXNrIGF0IG9yaWdpbmFsLWltYWdlIHJlc29sdXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIENvcmVNYXNrIHtcbiAgbWFzazogVWludDhBcnJheTtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG4gIGlvdTogbnVtYmVyO1xufVxuXG4vKiogRmV0Y2ggYSBtb2RlbCBhcyBhbiBBcnJheUJ1ZmZlciwgc3RyZWFtaW5nIHByb2dyZXNzIGFuZCBjYWNoaW5nIGluIHRoZSBDYWNoZVxuICogIEFQSSAoc28gaXQgaXNuJ3QgcmUtZG93bmxvYWRlZCkuIENhY2hlIGhpdCDihpIgcHJvZ3Jlc3MganVtcHMgdG8gMS4gV29ya3Mgb25cbiAqICB0aGUgbWFpbiB0aHJlYWQgYW5kIGluIGEgd29ya2VyIChib3RoIGhhdmUgYGZldGNoYCArIGBjYWNoZXNgKS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaE1vZGVsKHVybDogc3RyaW5nLCBvblByb2dyZXNzPzogKGY6IG51bWJlcikgPT4gdm9pZCk6IFByb21pc2U8QXJyYXlCdWZmZXI+IHtcbiAgY29uc3QgY2FjaGUgPSB0eXBlb2YgY2FjaGVzICE9PSAndW5kZWZpbmVkJyA/IGF3YWl0IGNhY2hlcy5vcGVuKE1PREVMX0NBQ0hFKS5jYXRjaCgoKSA9PiBudWxsKSA6IG51bGw7XG4gIGNvbnN0IGhpdCA9IGNhY2hlID8gYXdhaXQgY2FjaGUubWF0Y2godXJsKSA6IG51bGw7XG4gIGlmIChoaXQpIHsgb25Qcm9ncmVzcz8uKDEpOyByZXR1cm4gYXdhaXQgaGl0LmFycmF5QnVmZmVyKCk7IH1cblxuICBjb25zdCByZXNwID0gYXdhaXQgZmV0Y2godXJsKTtcbiAgaWYgKCFyZXNwLm9rKSB0aHJvdyBuZXcgRXJyb3IoYGZldGNoICR7dXJsfSBmYWlsZWQ6IEhUVFAgJHtyZXNwLnN0YXR1c31gKTtcbiAgY29uc3QgdG90YWwgPSBOdW1iZXIocmVzcC5oZWFkZXJzLmdldCgnY29udGVudC1sZW5ndGgnKSkgfHwgMDtcbiAgaWYgKCFyZXNwLmJvZHkgfHwgIXRvdGFsKSB7XG4gICAgY29uc3QgYnVmID0gYXdhaXQgcmVzcC5hcnJheUJ1ZmZlcigpO1xuICAgIG9uUHJvZ3Jlc3M/LigxKTtcbiAgICBpZiAoY2FjaGUpIGF3YWl0IGNhY2hlLnB1dCh1cmwsIG5ldyBSZXNwb25zZShidWYpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIHJldHVybiBidWY7XG4gIH1cbiAgY29uc3QgcmVhZGVyID0gcmVzcC5ib2R5LmdldFJlYWRlcigpO1xuICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICBsZXQgcmVjZWl2ZWQgPSAwO1xuICBmb3IgKDs7KSB7XG4gICAgY29uc3QgeyBkb25lLCB2YWx1ZSB9ID0gYXdhaXQgcmVhZGVyLnJlYWQoKTtcbiAgICBpZiAoZG9uZSkgYnJlYWs7XG4gICAgY2h1bmtzLnB1c2godmFsdWUpO1xuICAgIHJlY2VpdmVkICs9IHZhbHVlLmxlbmd0aDtcbiAgICBvblByb2dyZXNzPy4ocmVjZWl2ZWQgLyB0b3RhbCk7XG4gIH1cbiAgY29uc3Qgb3V0ID0gbmV3IFVpbnQ4QXJyYXkocmVjZWl2ZWQpO1xuICBsZXQgb2ZmID0gMDtcbiAgZm9yIChjb25zdCBjIG9mIGNodW5rcykgeyBvdXQuc2V0KGMsIG9mZik7IG9mZiArPSBjLmxlbmd0aDsgfVxuICBpZiAoY2FjaGUpIHtcbiAgICBhd2FpdCBjYWNoZS5wdXQodXJsLCBuZXcgUmVzcG9uc2Uob3V0LnNsaWNlKCksIHsgaGVhZGVyczogeyAnY29udGVudC1sZW5ndGgnOiBTdHJpbmcocmVjZWl2ZWQpIH0gfSkpXG4gICAgICAuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgfVxuICBvblByb2dyZXNzPy4oMSk7XG4gIHJldHVybiBvdXQuYnVmZmVyO1xufVxuXG4vKiogUmVzaXplIChsb25nIHNpZGUg4oaSIHNpemUsIGJpbGluZWFyKSwgcGFkIHRvIHNpemXDl3NpemUsIFNBTS1ub3JtYWxpemUg4oaSIENIVyBmbG9hdDMyLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByZXByb2Nlc3MoXG4gIGRhdGE6IFVpbnQ4Q2xhbXBlZEFycmF5LCB3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlciwgc2l6ZTogbnVtYmVyLCBzY2FsZTogbnVtYmVyLFxuKTogRmxvYXQzMkFycmF5IHtcbiAgY29uc3QgbmV3VyA9IE1hdGgucm91bmQod2lkdGggKiBzY2FsZSk7XG4gIGNvbnN0IG5ld0ggPSBNYXRoLnJvdW5kKGhlaWdodCAqIHNjYWxlKTtcbiAgY29uc3QgY2h3ID0gbmV3IEZsb2F0MzJBcnJheSgzICogc2l6ZSAqIHNpemUpOyAvLyB6ZXJvLXBhZGRlZFxuICBmb3IgKGxldCB5ID0gMDsgeSA8IG5ld0g7IHkrKykge1xuICAgIGNvbnN0IHN5ID0gTWF0aC5taW4oaGVpZ2h0IC0gMSwgeSAvIHNjYWxlKTtcbiAgICBjb25zdCB5MCA9IE1hdGguZmxvb3Ioc3kpO1xuICAgIGNvbnN0IGZ5ID0gc3kgLSB5MDtcbiAgICBjb25zdCB5MSA9IE1hdGgubWluKGhlaWdodCAtIDEsIHkwICsgMSk7XG4gICAgZm9yIChsZXQgeCA9IDA7IHggPCBuZXdXOyB4KyspIHtcbiAgICAgIGNvbnN0IHN4ID0gTWF0aC5taW4od2lkdGggLSAxLCB4IC8gc2NhbGUpO1xuICAgICAgY29uc3QgeDAgPSBNYXRoLmZsb29yKHN4KTtcbiAgICAgIGNvbnN0IGZ4ID0gc3ggLSB4MDtcbiAgICAgIGNvbnN0IHgxID0gTWF0aC5taW4od2lkdGggLSAxLCB4MCArIDEpO1xuICAgICAgZm9yIChsZXQgYyA9IDA7IGMgPCAzOyBjKyspIHtcbiAgICAgICAgY29uc3QgcDAwID0gZGF0YVsoeTAgKiB3aWR0aCArIHgwKSAqIDQgKyBjXTtcbiAgICAgICAgY29uc3QgcDAxID0gZGF0YVsoeTAgKiB3aWR0aCArIHgxKSAqIDQgKyBjXTtcbiAgICAgICAgY29uc3QgcDEwID0gZGF0YVsoeTEgKiB3aWR0aCArIHgwKSAqIDQgKyBjXTtcbiAgICAgICAgY29uc3QgcDExID0gZGF0YVsoeTEgKiB3aWR0aCArIHgxKSAqIDQgKyBjXTtcbiAgICAgICAgY29uc3QgdG9wID0gcDAwICsgKHAwMSAtIHAwMCkgKiBmeDtcbiAgICAgICAgY29uc3QgYm90ID0gcDEwICsgKHAxMSAtIHAxMCkgKiBmeDtcbiAgICAgICAgY29uc3QgdiA9IHRvcCArIChib3QgLSB0b3ApICogZnk7XG4gICAgICAgIGNod1tjICogc2l6ZSAqIHNpemUgKyB5ICogc2l6ZSArIHhdID0gKHYgLSBQSVhFTF9NRUFOW2NdKSAvIFBJWEVMX1NURFtjXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNodztcbn1cblxuLyoqIEFzc2VtYmxlIGRlY29kZXIgYHBvaW50X2Nvb3Jkc2AvYHBvaW50X2xhYmVsc2AgZnJvbSBhIHByb21wdCwgaW4gZW5jb2RlclxuICogIChyZXNpemVkKSBzcGFjZS4gQm94ID0gdHdvIHBvaW50cyBsYWJlbGxlZCAyLzM7IHBvaW50cyB1c2UgMS8wOyBhIHBvaW50cy1vbmx5XG4gKiAgcHJvbXB0IHBhZHMgdGhlIGFic2VudCBib3ggc2xvdCB3aXRoIGBbMCwwXWAgbGFiZWxsZWQgLTEuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGREZWNvZGVyUHJvbXB0KFxuICBwcm9tcHQ6IFNhbVByb21wdCwgc2NhbGU6IG51bWJlcixcbik6IHsgcG9pbnRDb29yZHM6IEZsb2F0MzJBcnJheTsgcG9pbnRMYWJlbHM6IEZsb2F0MzJBcnJheTsgbnVtUG9pbnRzOiBudW1iZXIgfSB7XG4gIGNvbnN0IGNvb3JkczogbnVtYmVyW10gPSBbXTtcbiAgY29uc3QgbGFiZWxzOiBudW1iZXJbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHAgb2YgcHJvbXB0LnBvaW50cyA/PyBbXSkgeyBjb29yZHMucHVzaChwLnggKiBzY2FsZSwgcC55ICogc2NhbGUpOyBsYWJlbHMucHVzaChwLmxhYmVsKTsgfVxuICBpZiAocHJvbXB0LmJveCkge1xuICAgIGNvbnN0IGIgPSBwcm9tcHQuYm94O1xuICAgIGNvb3Jkcy5wdXNoKGIueDAgKiBzY2FsZSwgYi55MCAqIHNjYWxlKTsgbGFiZWxzLnB1c2goMik7XG4gICAgY29vcmRzLnB1c2goYi54MSAqIHNjYWxlLCBiLnkxICogc2NhbGUpOyBsYWJlbHMucHVzaCgzKTtcbiAgfSBlbHNlIGlmIChsYWJlbHMubGVuZ3RoID4gMCkge1xuICAgIGNvb3Jkcy5wdXNoKDAsIDApOyBsYWJlbHMucHVzaCgtMSk7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBwb2ludENvb3JkczogRmxvYXQzMkFycmF5LmZyb20oY29vcmRzKSxcbiAgICBwb2ludExhYmVsczogRmxvYXQzMkFycmF5LmZyb20obGFiZWxzKSxcbiAgICBudW1Qb2ludHM6IGxhYmVscy5sZW5ndGgsXG4gIH07XG59XG5cbi8qKiBCaW5hcml6ZSBtYXNrIGxvZ2l0cyAoYD4gdGhyZXNob2xkYCkgaW50byBhIDAvMSBtYXNrLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJpbmFyaXplTWFzayhsb2dpdHM6IEZsb2F0MzJBcnJheSwgdGhyZXNob2xkID0gMCk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBvdXQgPSBuZXcgVWludDhBcnJheShsb2dpdHMubGVuZ3RoKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsb2dpdHMubGVuZ3RoOyBpKyspIG91dFtpXSA9IGxvZ2l0c1tpXSA+IHRocmVzaG9sZCA/IDEgOiAwO1xuICByZXR1cm4gb3V0O1xufVxuXG4vKiogSW5kZXggb2YgdGhlIGhpZ2hlc3Qtc2NvcmluZyBtYXNrIGluIGEgbXVsdGltYXNrIGRlY29kZXIgb3V0cHV0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlc3RNYXNrSW5kZXgoaW91OiBGbG9hdDMyQXJyYXkgfCBudW1iZXJbXSk6IG51bWJlciB7XG4gIGxldCBiZXN0ID0gMDtcbiAgZm9yIChsZXQgaSA9IDE7IGkgPCBpb3UubGVuZ3RoOyBpKyspIGlmIChpb3VbaV0gPiBpb3VbYmVzdF0pIGJlc3QgPSBpO1xuICByZXR1cm4gYmVzdDtcbn1cblxuLyoqIFJ1biB0aGUgZW5jb2RlciBvbiBhbiBSR0JBIGltYWdlIOKGkiBhIHJldXNhYmxlIGVtYmVkZGluZy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5FbmNvZGVyKFxuICBlbmNvZGVyOiBvcnQuSW5mZXJlbmNlU2Vzc2lvbiwgZGF0YTogVWludDhDbGFtcGVkQXJyYXksIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBpbnB1dFNpemU6IG51bWJlcixcbik6IFByb21pc2U8Q29yZUVtYmVkZGluZz4ge1xuICBjb25zdCBzY2FsZSA9IGlucHV0U2l6ZSAvIE1hdGgubWF4KHdpZHRoLCBoZWlnaHQpO1xuICBjb25zdCBpbnB1dCA9IHByZXByb2Nlc3MoZGF0YSwgd2lkdGgsIGhlaWdodCwgaW5wdXRTaXplLCBzY2FsZSk7XG4gIGNvbnN0IG91dCA9IGF3YWl0IGVuY29kZXIucnVuKHtcbiAgICBbZW5jb2Rlci5pbnB1dE5hbWVzWzBdXTogbmV3IG9ydC5UZW5zb3IoJ2Zsb2F0MzInLCBpbnB1dCwgWzEsIDMsIGlucHV0U2l6ZSwgaW5wdXRTaXplXSksXG4gIH0pO1xuICBjb25zdCBlbWIgPSBvdXRbZW5jb2Rlci5vdXRwdXROYW1lc1swXV07XG4gIHJldHVybiB7XG4gICAgZGF0YTogZW1iLmRhdGEgYXMgRmxvYXQzMkFycmF5LCBkaW1zOiBlbWIuZGltcyBhcyBudW1iZXJbXSxcbiAgICBzY2FsZSwgaW1hZ2VXaWR0aDogd2lkdGgsIGltYWdlSGVpZ2h0OiBoZWlnaHQsXG4gIH07XG59XG5cbi8qKiBSdW4gdGhlIGRlY29kZXIgZm9yIG9uZSBwcm9tcHQgYWdhaW5zdCBhIGNhY2hlZCBlbWJlZGRpbmcg4oaSIGEgYmluYXJ5IG1hc2suICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuRGVjb2RlcihcbiAgZGVjb2Rlcjogb3J0LkluZmVyZW5jZVNlc3Npb24sIGU6IENvcmVFbWJlZGRpbmcsIHByb21wdDogU2FtUHJvbXB0LFxuKTogUHJvbWlzZTxDb3JlTWFzaz4ge1xuICBjb25zdCB7IHBvaW50Q29vcmRzLCBwb2ludExhYmVscywgbnVtUG9pbnRzIH0gPSBidWlsZERlY29kZXJQcm9tcHQocHJvbXB0LCBlLnNjYWxlKTtcbiAgY29uc3Qgb3V0ID0gYXdhaXQgZGVjb2Rlci5ydW4oe1xuICAgIGltYWdlX2VtYmVkZGluZ3M6IG5ldyBvcnQuVGVuc29yKCdmbG9hdDMyJywgZS5kYXRhLCBlLmRpbXMpLFxuICAgIHBvaW50X2Nvb3JkczogbmV3IG9ydC5UZW5zb3IoJ2Zsb2F0MzInLCBwb2ludENvb3JkcywgWzEsIG51bVBvaW50cywgMl0pLFxuICAgIHBvaW50X2xhYmVsczogbmV3IG9ydC5UZW5zb3IoJ2Zsb2F0MzInLCBwb2ludExhYmVscywgWzEsIG51bVBvaW50c10pLFxuICAgIG1hc2tfaW5wdXQ6IG5ldyBvcnQuVGVuc29yKCdmbG9hdDMyJywgbmV3IEZsb2F0MzJBcnJheSgyNTYgKiAyNTYpLCBbMSwgMSwgMjU2LCAyNTZdKSxcbiAgICBoYXNfbWFza19pbnB1dDogbmV3IG9ydC5UZW5zb3IoJ2Zsb2F0MzInLCBGbG9hdDMyQXJyYXkuZnJvbShbMF0pLCBbMV0pLFxuICAgIG9yaWdfaW1fc2l6ZTogbmV3IG9ydC5UZW5zb3IoJ2Zsb2F0MzInLCBGbG9hdDMyQXJyYXkuZnJvbShbZS5pbWFnZUhlaWdodCwgZS5pbWFnZVdpZHRoXSksIFsyXSksXG4gIH0pO1xuICBjb25zdCBtYXNrcyA9IG91dFsnbWFza3MnXSA/PyBvdXRbZGVjb2Rlci5vdXRwdXROYW1lc1swXV07XG4gIGNvbnN0IGlvdSA9IChvdXRbJ2lvdV9wcmVkaWN0aW9ucyddPy5kYXRhIGFzIEZsb2F0MzJBcnJheSkgPz8gRmxvYXQzMkFycmF5LmZyb20oWzFdKTtcbiAgY29uc3QgWywgbSwgaCwgd10gPSBtYXNrcy5kaW1zIGFzIG51bWJlcltdO1xuICBjb25zdCBpZHggPSBiZXN0TWFza0luZGV4KGlvdS5zbGljZSgwLCBtKSk7XG4gIGNvbnN0IGxvZ2l0cyA9IChtYXNrcy5kYXRhIGFzIEZsb2F0MzJBcnJheSkuc3ViYXJyYXkoaWR4ICogaCAqIHcsIChpZHggKyAxKSAqIGggKiB3KTtcbiAgcmV0dXJuIHsgbWFzazogYmluYXJpemVNYXNrKGxvZ2l0cyksIHdpZHRoOiB3LCBoZWlnaHQ6IGgsIGlvdTogaW91W2lkeF0gPz8gMSB9O1xufVxuIl19
@@ -0,0 +1,255 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+ import { WandService } from '../wand/wand.service';
4
+ import { frameToRgba } from './sam-prompt';
5
+ import { getSamModel, isSamModelReady } from './sam-model-registry';
6
+ import { Region, Polygon } from '../../models/region';
7
+ import * as i0 from "@angular/core";
8
+ import * as i1 from "../wand/wand.service";
9
+ /** Interactive SAM point-prompt tool (jit-ui#90, P1).
10
+ *
11
+ * Each plain (positive) click segments the clicked object as its OWN new region
12
+ * — clicking a second fiber doesn't extend the first into it. Shift/Alt-click
13
+ * adds a negative (exclude) point that refines the CURRENT object, re-running
14
+ * the decoder against the (cached) image embedding and updating its live region.
15
+ * `commit()` (Enter) finalises early; `clear()` (Esc) discards the current
16
+ * prompt + its preview region. Mirrors the wand/brush on-canvas tool pattern and
17
+ * reuses WandService.maskToPolygons + the shared region store.
18
+ *
19
+ * Inference is behind {@link ISamSession} (lazy onnxruntime-web in production,
20
+ * a fake in tests).
21
+ */
22
+ export class SamPointToolService {
23
+ constructor(wandService) {
24
+ this.wandService = wandService;
25
+ this.overlay = null;
26
+ this.session = null;
27
+ /** In-flight session load — dedupes a warm-up preload against the first click. */
28
+ this.sessionLoad = null;
29
+ this.model = getSamModel();
30
+ this.embedding = null;
31
+ this.embeddingKey = null;
32
+ /** Accumulated point prompts, in image (matrix) coords. */
33
+ this.points = [];
34
+ /** Id of the in-progress (preview) region being refined, if committed to store. */
35
+ this.regionId = null;
36
+ this.status$ = new BehaviorSubject('');
37
+ this.busy$ = new BehaviorSubject(false);
38
+ /** Encoder-download progress (0..1) on the first click; -1 when not downloading. */
39
+ this.progress$ = new BehaviorSubject(-1);
40
+ this.boundMouseDown = (e) => { void this.onMouseDown(e); };
41
+ }
42
+ bindHost(host) { this.host = host; }
43
+ setModel(id) {
44
+ const next = getSamModel(id);
45
+ if (next.id === this.model.id)
46
+ return;
47
+ this.model = next;
48
+ this.embedding = null;
49
+ this.embeddingKey = null;
50
+ // Drop the loaded session so the next run reloads the newly-picked model
51
+ // (ensureSession() returns the cached session as-is otherwise).
52
+ this.session?.dispose();
53
+ this.session = null;
54
+ this.sessionLoad = null;
55
+ }
56
+ /** Test seam: inject a fake/alternate session. */
57
+ useSession(session) { this.session = session; }
58
+ setMode(active) {
59
+ if (active) {
60
+ this.createOverlay();
61
+ // Warm up the model in the background as soon as the tool is armed, so the
62
+ // first click doesn't pay the (download +) session-build cost on its path.
63
+ this.preload();
64
+ }
65
+ else {
66
+ this.destroyOverlay();
67
+ }
68
+ }
69
+ /** Eagerly load the model in the background (fire-and-forget). Safe to call
70
+ * repeatedly — it dedupes against an in-flight load and an existing session. */
71
+ preload() {
72
+ if (this.session || !isSamModelReady(this.model))
73
+ return;
74
+ void this.ensureSession().catch(() => undefined);
75
+ }
76
+ /** Finalise the current object: keep its region, start fresh next click. */
77
+ commit() {
78
+ this.points = [];
79
+ this.regionId = null;
80
+ this.status$.next('');
81
+ }
82
+ /** Discard the in-progress prompt + its preview region. */
83
+ clear() {
84
+ if (this.regionId != null) {
85
+ const regions = this.host.getRegions().filter((r) => r.id !== this.regionId);
86
+ this.host.setRegions(regions);
87
+ }
88
+ this.points = [];
89
+ this.regionId = null;
90
+ this.status$.next('');
91
+ }
92
+ // ── overlay lifecycle (mirrors the wand/brush tools) ────────────────────
93
+ createOverlay() {
94
+ const plotEl = this.host?.getOverlayContainer();
95
+ if (!plotEl || this.overlay)
96
+ return;
97
+ const canvas = document.createElement('canvas');
98
+ Object.assign(canvas.style, {
99
+ position: 'absolute', top: '0', left: '0', width: '100%', height: '100%',
100
+ cursor: 'crosshair', zIndex: '100',
101
+ });
102
+ canvas.width = plotEl.offsetWidth;
103
+ canvas.height = plotEl.offsetHeight;
104
+ plotEl.appendChild(canvas);
105
+ this.overlay = canvas;
106
+ canvas.addEventListener('mousedown', this.boundMouseDown);
107
+ }
108
+ destroyOverlay() {
109
+ if (!this.overlay)
110
+ return;
111
+ this.overlay.removeEventListener('mousedown', this.boundMouseDown);
112
+ this.overlay.remove();
113
+ this.overlay = null;
114
+ this.points = [];
115
+ this.regionId = null;
116
+ }
117
+ // ── per-click refinement ────────────────────────────────────────────────
118
+ async onMouseDown(e) {
119
+ if (e.button !== 0 || !this.overlay)
120
+ return;
121
+ // Re-entrancy guard: ignore clicks while a previous prompt is still
122
+ // downloading the model / encoding / decoding. Without it, clicking again
123
+ // during the slow first run (e.g. a ~172 MB ViT-B encode on WebGPU) launches
124
+ // concurrent downloads + GPU encodes that can overwhelm the GPU and freeze
125
+ // the tab. Each click is fast once the embedding is cached, so this only
126
+ // drops clicks made while genuinely busy.
127
+ if (this.busy$.value)
128
+ return;
129
+ const cached = this.host.getCachedImageData();
130
+ if (!cached || cached.frames.length === 0)
131
+ return;
132
+ const transform = this.host.getCoordinateTransform();
133
+ if (!transform.isReady())
134
+ return;
135
+ const { x: dataX, y: dataY } = transform.clientToData(e.clientX, e.clientY);
136
+ if (!Number.isFinite(dataX) || !Number.isFinite(dataY))
137
+ return;
138
+ const rx = cached.ratios[0] || 1;
139
+ const ry = cached.ratios[0] || 1;
140
+ const ox = cached.originX ?? 0;
141
+ const oy = cached.originY ?? 0;
142
+ // Shift or Alt = negative (exclude) point.
143
+ const label = e.shiftKey || e.altKey ? 0 : 1;
144
+ // A plain positive click starts a NEW object: clicking another fiber must
145
+ // segment that fiber on its own, not accumulate with earlier points and
146
+ // grow the in-progress mask into the adjacent object (which would also
147
+ // overwrite a previously-segmented region). Only Shift/Alt (exclude) points
148
+ // refine the current object. This also clears any stale prompt left after a
149
+ // region was deleted, so the next click segments fresh instead of redrawing
150
+ // the old merged mask.
151
+ if (label === 1) {
152
+ this.points = [];
153
+ this.regionId = null;
154
+ }
155
+ this.points.push({ x: (dataX - ox) / rx, y: (dataY - oy) / ry, label });
156
+ // Mark busy BEFORE ensureSession: the first click downloads the encoder
157
+ // (~14–172 MB) and builds the session, which is the longest wait — without
158
+ // this the UI showed nothing running until that finished.
159
+ this.busy$.next(true);
160
+ try {
161
+ this.status$.next('Loading SAM model…');
162
+ const session = await this.ensureSession();
163
+ const key = [
164
+ this.host.getFileName() ?? '', this.host.getActiveFrameIndex(),
165
+ `${cached.width}x${cached.height}`, `${ox},${oy},${rx}`, this.model.id,
166
+ ].join('|');
167
+ if (!this.embedding || this.embeddingKey !== key) {
168
+ this.status$.next('Encoding image…');
169
+ const rgba = frameToRgba(cached, this.host.getActiveFrameIndex());
170
+ this.embedding = await session.embed({ data: rgba, width: cached.width, height: cached.height });
171
+ this.embeddingKey = key;
172
+ }
173
+ this.status$.next('Segmenting…');
174
+ const prompt = { points: this.points.slice() };
175
+ const res = await session.decode(this.embedding, prompt);
176
+ const polys = this.wandService.maskToPolygons(res.mask, res.width, res.height, cached.width, cached.height, 0, 0);
177
+ if (polys.length === 0) {
178
+ this.status$.next('No mask for these points.');
179
+ return;
180
+ }
181
+ const poly = polys[0];
182
+ this.upsertPreview(poly.xpoints.map((x) => ox + x * rx), poly.ypoints.map((y) => oy + y * ry));
183
+ this.status$.next('Segmented — click another fiber for a new region, Shift-click to refine, Esc to undo.');
184
+ }
185
+ catch (err) {
186
+ this.status$.next(err instanceof Error ? err.message : 'SAM model unavailable.');
187
+ }
188
+ finally {
189
+ this.busy$.next(false);
190
+ this.progress$.next(-1);
191
+ }
192
+ }
193
+ /** Replace (or insert) the in-progress preview region in the shared store. */
194
+ upsertPreview(xData, yData) {
195
+ if (xData.length < 3)
196
+ return;
197
+ const poly = new Polygon();
198
+ poly.npoints = xData.length;
199
+ poly.xpoints = xData;
200
+ poly.ypoints = yData;
201
+ poly.coordinates = xData.map((x, i) => [x, yData[i]]);
202
+ poly.closed = true;
203
+ const regions = this.host.getRegions();
204
+ const existing = this.regionId != null ? regions.find((r) => r.id === this.regionId) : null;
205
+ const region = new Region();
206
+ region.bounds = poly;
207
+ region.color = this.host.getShapeColor();
208
+ region.label = 'sam';
209
+ if (existing) {
210
+ region.id = existing.id;
211
+ region.name = existing.name;
212
+ const idx = regions.findIndex((r) => r.id === this.regionId);
213
+ if (idx >= 0)
214
+ regions[idx] = region;
215
+ else
216
+ regions.push(region);
217
+ }
218
+ else {
219
+ regions.push(region);
220
+ }
221
+ this.host.setRegions(regions);
222
+ this.regionId = region.id ?? this.regionId;
223
+ }
224
+ ensureSession() {
225
+ if (this.session)
226
+ return Promise.resolve(this.session);
227
+ if (this.sessionLoad)
228
+ return this.sessionLoad;
229
+ if (!isSamModelReady(this.model)) {
230
+ return Promise.reject(new Error(`SAM model "${this.model.id}" is not configured yet (no ONNX URLs). ` +
231
+ 'Host it and call setSamModelUrls(), then retry.'));
232
+ }
233
+ this.sessionLoad = (async () => {
234
+ try {
235
+ const { OnnxSamSession } = await import('./onnx-sam-session');
236
+ const session = new OnnxSamSession();
237
+ this.progress$.next(0);
238
+ await session.loadModel(this.model, (f) => this.progress$.next(f));
239
+ this.session = session;
240
+ return session;
241
+ }
242
+ finally {
243
+ this.sessionLoad = null;
244
+ }
245
+ })();
246
+ return this.sessionLoad;
247
+ }
248
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamPointToolService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
249
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamPointToolService, providedIn: 'root' }); }
250
+ }
251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamPointToolService, decorators: [{
252
+ type: Injectable,
253
+ args: [{ providedIn: 'root' }]
254
+ }], ctorParameters: () => [{ type: i1.WandService }] });
255
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLXBvaW50LXRvb2wuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXBvaW50LXRvb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFdkMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRW5ELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVwRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7QUFFdEQ7Ozs7Ozs7Ozs7OztHQVlHO0FBRUgsTUFBTSxPQUFPLG1CQUFtQjtJQXVCOUIsWUFBb0IsV0FBd0I7UUFBeEIsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFyQnBDLFlBQU8sR0FBNkIsSUFBSSxDQUFDO1FBQ3pDLFlBQU8sR0FBdUIsSUFBSSxDQUFDO1FBQzNDLGtGQUFrRjtRQUMxRSxnQkFBVyxHQUFnQyxJQUFJLENBQUM7UUFDaEQsVUFBSyxHQUFnQixXQUFXLEVBQUUsQ0FBQztRQUVuQyxjQUFTLEdBQXdCLElBQUksQ0FBQztRQUN0QyxpQkFBWSxHQUFrQixJQUFJLENBQUM7UUFFM0MsMkRBQTJEO1FBQ25ELFdBQU0sR0FBNkMsRUFBRSxDQUFDO1FBQzlELG1GQUFtRjtRQUMzRSxhQUFRLEdBQWtCLElBQUksQ0FBQztRQUU5QixZQUFPLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUM7UUFDMUMsVUFBSyxHQUFHLElBQUksZUFBZSxDQUFVLEtBQUssQ0FBQyxDQUFDO1FBQ3JELG9GQUFv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QUFJLENBQUM7WUFDMUIsQ0FBQztRQUNILENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDTCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7SUFDMUIsQ0FBQzs4R0ExT1UsbUJBQW1CO2tIQUFuQixtQkFBbUIsY0FETixNQUFNOzsyRkFDbkIsbUJBQW1CO2tCQUQvQixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBXYW5kU2VydmljZSB9IGZyb20gJy4uL3dhbmQvd2FuZC5zZXJ2aWNlJztcbmltcG9ydCB7IFdhbmRUb29sSG9zdCB9IGZyb20gJy4uL3dhbmQvd2FuZC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgZnJhbWVUb1JnYmEgfSBmcm9tICcuL3NhbS1wcm9tcHQnO1xuaW1wb3J0IHsgZ2V0U2FtTW9kZWwsIGlzU2FtTW9kZWxSZWFkeSB9IGZyb20gJy4vc2FtLW1vZGVsLXJlZ2lzdHJ5JztcbmltcG9ydCB7IElTYW1TZXNzaW9uLCBTYW1FbWJlZGRpbmcsIFNhbU1vZGVsRGVmLCBTYW1Qcm9tcHQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc2FtLmNvbnRyYWN0JztcbmltcG9ydCB7IFJlZ2lvbiwgUG9seWdvbiB9IGZyb20gJy4uLy4uL21vZGVscy9yZWdpb24nO1xuXG4vKiogSW50ZXJhY3RpdmUgU0FNIHBvaW50LXByb21wdCB0b29sIChqaXQtdWkjOTAsIFAxKS5cbiAqXG4gKiBFYWNoIHBsYWluIChwb3NpdGl2ZSkgY2xpY2sgc2VnbWVudHMgdGhlIGNsaWNrZWQgb2JqZWN0IGFzIGl0cyBPV04gbmV3IHJlZ2lvblxuICog4oCUIGNsaWNraW5nIGEgc2Vjb25kIGZpYmVyIGRvZXNuJ3QgZXh0ZW5kIHRoZSBmaXJzdCBpbnRvIGl0LiBTaGlmdC9BbHQtY2xpY2tcbiAqIGFkZHMgYSBuZWdhdGl2ZSAoZXhjbHVkZSkgcG9pbnQgdGhhdCByZWZpbmVzIHRoZSBDVVJSRU5UIG9iamVjdCwgcmUtcnVubmluZ1xuICogdGhlIGRlY29kZXIgYWdhaW5zdCB0aGUgKGNhY2hlZCkgaW1hZ2UgZW1iZWRkaW5nIGFuZCB1cGRhdGluZyBpdHMgbGl2ZSByZWdpb24uXG4gKiBgY29tbWl0KClgIChFbnRlcikgZmluYWxpc2VzIGVhcmx5OyBgY2xlYXIoKWAgKEVzYykgZGlzY2FyZHMgdGhlIGN1cnJlbnRcbiAqIHByb21wdCArIGl0cyBwcmV2aWV3IHJlZ2lvbi4gTWlycm9ycyB0aGUgd2FuZC9icnVzaCBvbi1jYW52YXMgdG9vbCBwYXR0ZXJuIGFuZFxuICogcmV1c2VzIFdhbmRTZXJ2aWNlLm1hc2tUb1BvbHlnb25zICsgdGhlIHNoYXJlZCByZWdpb24gc3RvcmUuXG4gKlxuICogSW5mZXJlbmNlIGlzIGJlaGluZCB7QGxpbmsgSVNhbVNlc3Npb259IChsYXp5IG9ubnhydW50aW1lLXdlYiBpbiBwcm9kdWN0aW9uLFxuICogYSBmYWtlIGluIHRlc3RzKS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBTYW1Qb2ludFRvb2xTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBob3N0ITogV2FuZFRvb2xIb3N0O1xuICBwcml2YXRlIG92ZXJsYXk6IEhUTUxDYW52YXNFbGVtZW50IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgc2Vzc2lvbjogSVNhbVNlc3Npb24gfCBudWxsID0gbnVsbDtcbiAgLyoqIEluLWZsaWdodCBzZXNzaW9uIGxvYWQg4oCUIGRlZHVwZXMgYSB3YXJtLXVwIHByZWxvYWQgYWdhaW5zdCB0aGUgZmlyc3QgY2xpY2suICovXG4gIHByaXZhdGUgc2Vzc2lvbkxvYWQ6IFByb21pc2U8SVNhbVNlc3Npb24+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbW9kZWw6IFNhbU1vZGVsRGVmID0gZ2V0U2FtTW9kZWwoKTtcblxuICBwcml2YXRlIGVtYmVkZGluZzogU2FtRW1iZWRkaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZW1iZWRkaW5nS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICAvKiogQWNjdW11bGF0ZWQgcG9pbnQgcHJvbXB0cywgaW4gaW1hZ2UgKG1hdHJpeCkgY29vcmRzLiAqL1xuICBwcml2YXRlIHBvaW50czogeyB4OiBudW1iZXI7IHk6IG51bWJlcjsgbGFiZWw6IDAgfCAxIH1bXSA9IFtdO1xuICAvKiogSWQgb2YgdGhlIGluLXByb2dyZXNzIChwcmV2aWV3KSByZWdpb24gYmVpbmcgcmVmaW5lZCwgaWYgY29tbWl0dGVkIHRvIHN0b3JlLiAqL1xuICBwcml2YXRlIHJlZ2lvbklkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICByZWFkb25seSBzdGF0dXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmc+KCcnKTtcbiAgcmVhZG9ubHkgYnVzeSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVuY29kZXItZG93bmxvYWQgcHJvZ3Jlc3MgKDAuLjEpIG9uIHRoZSBmaXJzdCBjbGljazsgLTEgd2hlbiBub3QgZG93bmxvYWRpbmcuICovXG4gIHJlYWRvbmx5IHByb2dyZXNzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigtMSk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBib3VuZE1vdXNlRG93bjogKGU6IE1vdXNlRXZlbnQpID0+IHZvaWQ7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSB3YW5kU2VydmljZTogV2FuZFNlcnZpY2UpIHtcbiAgICB0aGlzLmJvdW5kTW91c2VEb3duID0gKGUpID0+IHsgdm9pZCB0aGlzLm9uTW91c2VEb3duKGUpOyB9O1xuICB9XG5cbiAgYmluZEhvc3QoaG9zdDogV2FuZFRvb2xIb3N0KTogdm9pZCB7IHRoaXMuaG9zdCA9IGhvc3Q7IH1cblxuICBzZXRNb2RlbChpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IGdldFNhbU1vZGVsKGlkKTtcbiAgICBpZiAobmV4dC5pZCA9PT0gdGhpcy5tb2RlbC5pZCkgcmV0dXJuO1xuICAgIHRoaXMubW9kZWwgPSBuZXh0O1xuICAgIHRoaXMuZW1iZWRkaW5nID0gbnVsbDtcbiAgICB0aGlzLmVtYmVkZGluZ0tleSA9IG51bGw7XG4gICAgLy8gRHJvcCB0aGUgbG9hZGVkIHNlc3Npb24gc28gdGhlIG5leHQgcnVuIHJlbG9hZHMgdGhlIG5ld2x5LXBpY2tlZCBtb2RlbFxuICAgIC8vIChlbnN1cmVTZXNzaW9uKCkgcmV0dXJucyB0aGUgY2FjaGVkIHNlc3Npb24gYXMtaXMgb3RoZXJ3aXNlKS5cbiAgICB0aGlzLnNlc3Npb24/LmRpc3Bvc2UoKTtcbiAgICB0aGlzLnNlc3Npb24gPSBudWxsO1xuICAgIHRoaXMuc2Vzc2lvbkxvYWQgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRlc3Qgc2VhbTogaW5qZWN0IGEgZmFrZS9hbHRlcm5hdGUgc2Vzc2lvbi4gKi9cbiAgdXNlU2Vzc2lvbihzZXNzaW9uOiBJU2FtU2Vzc2lvbik6IHZvaWQgeyB0aGlzLnNlc3Npb24gPSBzZXNzaW9uOyB9XG5cbiAgc2V0TW9kZShhY3RpdmU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoYWN0aXZlKSB7XG4gICAgICB0aGlzLmNyZWF0ZU92ZXJsYXkoKTtcbiAgICAgIC8vIFdhcm0gdXAgdGhlIG1vZGVsIGluIHRoZSBiYWNrZ3JvdW5kIGFzIHNvb24gYXMgdGhlIHRvb2wgaXMgYXJtZWQsIHNvIHRoZVxuICAgICAgLy8gZmlyc3QgY2xpY2sgZG9lc24ndCBwYXkgdGhlIChkb3dubG9hZCArKSBzZXNzaW9uLWJ1aWxkIGNvc3Qgb24gaXRzIHBhdGguXG4gICAgICB0aGlzLnByZWxvYWQoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kZXN0cm95T3ZlcmxheSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBFYWdlcmx5IGxvYWQgdGhlIG1vZGVsIGluIHRoZSBiYWNrZ3JvdW5kIChmaXJlLWFuZC1mb3JnZXQpLiBTYWZlIHRvIGNhbGxcbiAgICogIHJlcGVhdGVkbHkg4oCUIGl0IGRlZHVwZXMgYWdhaW5zdCBhbiBpbi1mbGlnaHQgbG9hZCBhbmQgYW4gZXhpc3Rpbmcgc2Vzc2lvbi4gKi9cbiAgcHJlbG9hZCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zZXNzaW9uIHx8ICFpc1NhbU1vZGVsUmVhZHkodGhpcy5tb2RlbCkpIHJldHVybjtcbiAgICB2b2lkIHRoaXMuZW5zdXJlU2Vzc2lvbigpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gIH1cblxuICAvKiogRmluYWxpc2UgdGhlIGN1cnJlbnQgb2JqZWN0OiBrZWVwIGl0cyByZWdpb24sIHN0YXJ0IGZyZXNoIG5leHQgY2xpY2suICovXG4gIGNvbW1pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnBvaW50cyA9IFtdO1xuICAgIHRoaXMucmVnaW9uSWQgPSBudWxsO1xuICAgIHRoaXMuc3RhdHVzJC5uZXh0KCcnKTtcbiAgfVxuXG4gIC8qKiBEaXNjYXJkIHRoZSBpbi1wcm9ncmVzcyBwcm9tcHQgKyBpdHMgcHJldmlldyByZWdpb24uICovXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnJlZ2lvbklkICE9IG51bGwpIHtcbiAgICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLmhvc3QuZ2V0UmVnaW9ucygpLmZpbHRlcigocikgPT4gci5pZCAhPT0gdGhpcy5yZWdpb25JZCk7XG4gICAgICB0aGlzLmhvc3Quc2V0UmVnaW9ucyhyZWdpb25zKTtcbiAgICB9XG4gICAgdGhpcy5wb2ludHMgPSBbXTtcbiAgICB0aGlzLnJlZ2lvbklkID0gbnVsbDtcbiAgICB0aGlzLnN0YXR1cyQubmV4dCgnJyk7XG4gIH1cblxuICAvLyDilIDilIAgb3ZlcmxheSBsaWZlY3ljbGUgKG1pcnJvcnMgdGhlIHdhbmQvYnJ1c2ggdG9vbHMpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgY3JlYXRlT3ZlcmxheSgpOiB2b2lkIHtcbiAgICBjb25zdCBwbG90RWwgPSB0aGlzLmhvc3Q/LmdldE92ZXJsYXlDb250YWluZXIoKTtcbiAgICBpZiAoIXBsb3RFbCB8fCB0aGlzLm92ZXJsYXkpIHJldHVybjtcbiAgICBjb25zdCBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICBPYmplY3QuYXNzaWduKGNhbnZhcy5zdHlsZSwge1xuICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsIHRvcDogJzAnLCBsZWZ0OiAnMCcsIHdpZHRoOiAnMTAwJScsIGhlaWdodDogJzEwMCUnLFxuICAgICAgY3Vyc29yOiAnY3Jvc3NoYWlyJywgekluZGV4OiAnMTAwJyxcbiAgICB9KTtcbiAgICBjYW52YXMud2lkdGggPSBwbG90RWwub2Zmc2V0V2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IHBsb3RFbC5vZmZzZXRIZWlnaHQ7XG4gICAgcGxvdEVsLmFwcGVuZENoaWxkKGNhbnZhcyk7XG4gICAgdGhpcy5vdmVybGF5ID0gY2FudmFzO1xuICAgIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLmJvdW5kTW91c2VEb3duKTtcbiAgfVxuXG4gIHByaXZhdGUgZGVzdHJveU92ZXJsYXkoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm92ZXJsYXkpIHJldHVybjtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5ib3VuZE1vdXNlRG93bik7XG4gICAgdGhpcy5vdmVybGF5LnJlbW92ZSgpO1xuICAgIHRoaXMub3ZlcmxheSA9IG51bGw7XG4gICAgdGhpcy5wb2ludHMgPSBbXTtcbiAgICB0aGlzLnJlZ2lvbklkID0gbnVsbDtcbiAgfVxuXG4gIC8vIOKUgOKUgCBwZXItY2xpY2sgcmVmaW5lbWVudCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIG9uTW91c2VEb3duKGU6IE1vdXNlRXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoZS5idXR0b24gIT09IDAgfHwgIXRoaXMub3ZlcmxheSkgcmV0dXJuO1xuICAgIC8vIFJlLWVudHJhbmN5IGd1YXJkOiBpZ25vcmUgY2xpY2tzIHdoaWxlIGEgcHJldmlvdXMgcHJvbXB0IGlzIHN0aWxsXG4gICAgLy8gZG93bmxvYWRpbmcgdGhlIG1vZGVsIC8gZW5jb2RpbmcgLyBkZWNvZGluZy4gV2l0aG91dCBpdCwgY2xpY2tpbmcgYWdhaW5cbiAgICAvLyBkdXJpbmcgdGhlIHNsb3cgZmlyc3QgcnVuIChlLmcuIGEgfjE3MiBNQiBWaVQtQiBlbmNvZGUgb24gV2ViR1BVKSBsYXVuY2hlc1xuICAgIC8vIGNvbmN1cnJlbnQgZG93bmxvYWRzICsgR1BVIGVuY29kZXMgdGhhdCBjYW4gb3ZlcndoZWxtIHRoZSBHUFUgYW5kIGZyZWV6ZVxuICAgIC8vIHRoZSB0YWIuIEVhY2ggY2xpY2sgaXMgZmFzdCBvbmNlIHRoZSBlbWJlZGRpbmcgaXMgY2FjaGVkLCBzbyB0aGlzIG9ubHlcbiAgICAvLyBkcm9wcyBjbGlja3MgbWFkZSB3aGlsZSBnZW51aW5lbHkgYnVzeS5cbiAgICBpZiAodGhpcy5idXN5JC52YWx1ZSkgcmV0dXJuO1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuaG9zdC5nZXRDYWNoZWRJbWFnZURhdGEoKTtcbiAgICBpZiAoIWNhY2hlZCB8fCBjYWNoZWQuZnJhbWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IHRyYW5zZm9ybSA9IHRoaXMuaG9zdC5nZXRDb29yZGluYXRlVHJhbnNmb3JtKCk7XG4gICAgaWYgKCF0cmFuc2Zvcm0uaXNSZWFkeSgpKSByZXR1cm47XG4gICAgY29uc3QgeyB4OiBkYXRhWCwgeTogZGF0YVkgfSA9IHRyYW5zZm9ybS5jbGllbnRUb0RhdGEoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKGRhdGFYKSB8fCAhTnVtYmVyLmlzRmluaXRlKGRhdGFZKSkgcmV0dXJuO1xuXG4gICAgY29uc3QgcnggPSBjYWNoZWQucmF0aW9zWzBdIHx8IDE7XG4gICAgY29uc3QgcnkgPSBjYWNoZWQucmF0aW9zWzBdIHx8IDE7XG4gICAgY29uc3Qgb3ggPSBjYWNoZWQub3JpZ2luWCA/PyAwO1xuICAgIGNvbnN0IG95ID0gY2FjaGVkLm9yaWdpblkgPz8gMDtcbiAgICAvLyBTaGlmdCBvciBBbHQgPSBuZWdhdGl2ZSAoZXhjbHVkZSkgcG9pbnQuXG4gICAgY29uc3QgbGFiZWw6IDAgfCAxID0gZS5zaGlmdEtleSB8fCBlLmFsdEtleSA/IDAgOiAxO1xuICAgIC8vIEEgcGxhaW4gcG9zaXRpdmUgY2xpY2sgc3RhcnRzIGEgTkVXIG9iamVjdDogY2xpY2tpbmcgYW5vdGhlciBmaWJlciBtdXN0XG4gICAgLy8gc2VnbWVudCB0aGF0IGZpYmVyIG9uIGl0cyBvd24sIG5vdCBhY2N1bXVsYXRlIHdpdGggZWFybGllciBwb2ludHMgYW5kXG4gICAgLy8gZ3JvdyB0aGUgaW4tcHJvZ3Jlc3MgbWFzayBpbnRvIHRoZSBhZGphY2VudCBvYmplY3QgKHdoaWNoIHdvdWxkIGFsc29cbiAgICAvLyBvdmVyd3JpdGUgYSBwcmV2aW91c2x5LXNlZ21lbnRlZCByZWdpb24pLiBPbmx5IFNoaWZ0L0FsdCAoZXhjbHVkZSkgcG9pbnRzXG4gICAgLy8gcmVmaW5lIHRoZSBjdXJyZW50IG9iamVjdC4gVGhpcyBhbHNvIGNsZWFycyBhbnkgc3RhbGUgcHJvbXB0IGxlZnQgYWZ0ZXIgYVxuICAgIC8vIHJlZ2lvbiB3YXMgZGVsZXRlZCwgc28gdGhlIG5leHQgY2xpY2sgc2VnbWVudHMgZnJlc2ggaW5zdGVhZCBvZiByZWRyYXdpbmdcbiAgICAvLyB0aGUgb2xkIG1lcmdlZCBtYXNrLlxuICAgIGlmIChsYWJlbCA9PT0gMSkge1xuICAgICAgdGhpcy5wb2ludHMgPSBbXTtcbiAgICAgIHRoaXMucmVnaW9uSWQgPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLnBvaW50cy5wdXNoKHsgeDogKGRhdGFYIC0gb3gpIC8gcngsIHk6IChkYXRhWSAtIG95KSAvIHJ5LCBsYWJlbCB9KTtcblxuICAgIC8vIE1hcmsgYnVzeSBCRUZPUkUgZW5zdXJlU2Vzc2lvbjogdGhlIGZpcnN0IGNsaWNrIGRvd25sb2FkcyB0aGUgZW5jb2RlclxuICAgIC8vICh+MTTigJMxNzIgTUIpIGFuZCBidWlsZHMgdGhlIHNlc3Npb24sIHdoaWNoIGlzIHRoZSBsb25nZXN0IHdhaXQg4oCUIHdpdGhvdXRcbiAgICAvLyB0aGlzIHRoZSBVSSBzaG93ZWQgbm90aGluZyBydW5uaW5nIHVudGlsIHRoYXQgZmluaXNoZWQuXG4gICAgdGhpcy5idXN5JC5uZXh0KHRydWUpO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLnN0YXR1cyQubmV4dCgnTG9hZGluZyBTQU0gbW9kZWzigKYnKTtcbiAgICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCB0aGlzLmVuc3VyZVNlc3Npb24oKTtcbiAgICAgIGNvbnN0IGtleSA9IFtcbiAgICAgICAgdGhpcy5ob3N0LmdldEZpbGVOYW1lKCkgPz8gJycsIHRoaXMuaG9zdC5nZXRBY3RpdmVGcmFtZUluZGV4KCksXG4gICAgICAgIGAke2NhY2hlZC53aWR0aH14JHtjYWNoZWQuaGVpZ2h0fWAsIGAke294fSwke295fSwke3J4fWAsIHRoaXMubW9kZWwuaWQsXG4gICAgICBdLmpvaW4oJ3wnKTtcbiAgICAgIGlmICghdGhpcy5lbWJlZGRpbmcgfHwgdGhpcy5lbWJlZGRpbmdLZXkgIT09IGtleSkge1xuICAgICAgICB0aGlzLnN0YXR1cyQubmV4dCgnRW5jb2RpbmcgaW1hZ2XigKYnKTtcbiAgICAgICAgY29uc3QgcmdiYSA9IGZyYW1lVG9SZ2JhKGNhY2hlZCwgdGhpcy5ob3N0LmdldEFjdGl2ZUZyYW1lSW5kZXgoKSk7XG4gICAgICAgIHRoaXMuZW1iZWRkaW5nID0gYXdhaXQgc2Vzc2lvbi5lbWJlZCh7IGRhdGE6IHJnYmEsIHdpZHRoOiBjYWNoZWQud2lkdGgsIGhlaWdodDogY2FjaGVkLmhlaWdodCB9KTtcbiAgICAgICAgdGhpcy5lbWJlZGRpbmdLZXkgPSBrZXk7XG4gICAgICB9XG4gICAgICB0aGlzLnN0YXR1cyQubmV4dCgnU2VnbWVudGluZ+KApicpO1xuICAgICAgY29uc3QgcHJvbXB0OiBTYW1Qcm9tcHQgPSB7IHBvaW50czogdGhpcy5wb2ludHMuc2xpY2UoKSB9O1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgc2Vzc2lvbi5kZWNvZGUodGhpcy5lbWJlZGRpbmcsIHByb21wdCk7XG4gICAgICBjb25zdCBwb2x5cyA9IHRoaXMud2FuZFNlcnZpY2UubWFza1RvUG9seWdvbnMoXG4gICAgICAgIHJlcy5tYXNrLCByZXMud2lkdGgsIHJlcy5oZWlnaHQsIGNhY2hlZC53aWR0aCwgY2FjaGVkLmhlaWdodCwgMCwgMCxcbiAgICAgICk7XG4gICAgICBpZiAocG9seXMubGVuZ3RoID09PSAwKSB7IHRoaXMuc3RhdHVzJC5uZXh0KCdObyBtYXNrIGZvciB0aGVzZSBwb2ludHMuJyk7IHJldHVybjsgfVxuICAgICAgY29uc3QgcG9seSA9IHBvbHlzWzBdO1xuICAgICAgdGhpcy51cHNlcnRQcmV2aWV3KFxuICAgICAgICBwb2x5Lnhwb2ludHMubWFwKCh4KSA9PiBveCArIHggKiByeCksXG4gICAgICAgIHBvbHkueXBvaW50cy5tYXAoKHkpID0+IG95ICsgeSAqIHJ5KSxcbiAgICAgICk7XG4gICAgICB0aGlzLnN0YXR1cyQubmV4dChcbiAgICAgICAgJ1NlZ21lbnRlZCDigJQgY2xpY2sgYW5vdGhlciBmaWJlciBmb3IgYSBuZXcgcmVnaW9uLCBTaGlmdC1jbGljayB0byByZWZpbmUsIEVzYyB0byB1bmRvLicsXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5zdGF0dXMkLm5leHQoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6ICdTQU0gbW9kZWwgdW5hdmFpbGFibGUuJyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuYnVzeSQubmV4dChmYWxzZSk7XG4gICAgICB0aGlzLnByb2dyZXNzJC5uZXh0KC0xKTtcbiAgICB9XG4gIH1cblxuICAvKiogUmVwbGFjZSAob3IgaW5zZXJ0KSB0aGUgaW4tcHJvZ3Jlc3MgcHJldmlldyByZWdpb24gaW4gdGhlIHNoYXJlZCBzdG9yZS4gKi9cbiAgcHJpdmF0ZSB1cHNlcnRQcmV2aWV3KHhEYXRhOiBudW1iZXJbXSwgeURhdGE6IG51bWJlcltdKTogdm9pZCB7XG4gICAgaWYgKHhEYXRhLmxlbmd0aCA8IDMpIHJldHVybjtcbiAgICBjb25zdCBwb2x5ID0gbmV3IFBvbHlnb24oKTtcbiAgICBwb2x5Lm5wb2ludHMgPSB4RGF0YS5sZW5ndGg7XG4gICAgcG9seS54cG9pbnRzID0geERhdGE7XG4gICAgcG9seS55cG9pbnRzID0geURhdGE7XG4gICAgcG9seS5jb29yZGluYXRlcyA9IHhEYXRhLm1hcCgoeCwgaSkgPT4gW3gsIHlEYXRhW2ldXSk7XG4gICAgcG9seS5jbG9zZWQgPSB0cnVlO1xuXG4gICAgY29uc3QgcmVnaW9ucyA9IHRoaXMuaG9zdC5nZXRSZWdpb25zKCk7XG4gICAgY29uc3QgZXhpc3RpbmcgPSB0aGlzLnJlZ2lvbklkICE9IG51bGwgPyByZWdpb25zLmZpbmQoKHIpID0+IHIuaWQgPT09IHRoaXMucmVnaW9uSWQpIDogbnVsbDtcbiAgICBjb25zdCByZWdpb24gPSBuZXcgUmVnaW9uKCk7XG4gICAgcmVnaW9uLmJvdW5kcyA9IHBvbHk7XG4gICAgcmVnaW9uLmNvbG9yID0gdGhpcy5ob3N0LmdldFNoYXBlQ29sb3IoKTtcbiAgICByZWdpb24ubGFiZWwgPSAnc2FtJztcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIHJlZ2lvbi5pZCA9IGV4aXN0aW5nLmlkO1xuICAgICAgcmVnaW9uLm5hbWUgPSBleGlzdGluZy5uYW1lO1xuICAgICAgY29uc3QgaWR4ID0gcmVnaW9ucy5maW5kSW5kZXgoKHIpID0+IHIuaWQgPT09IHRoaXMucmVnaW9uSWQpO1xuICAgICAgaWYgKGlkeCA+PSAwKSByZWdpb25zW2lkeF0gPSByZWdpb247IGVsc2UgcmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlZ2lvbnMucHVzaChyZWdpb24pO1xuICAgIH1cbiAgICB0aGlzLmhvc3Quc2V0UmVnaW9ucyhyZWdpb25zKTtcbiAgICB0aGlzLnJlZ2lvbklkID0gcmVnaW9uLmlkID8/IHRoaXMucmVnaW9uSWQ7XG4gIH1cblxuICBwcml2YXRlIGVuc3VyZVNlc3Npb24oKTogUHJvbWlzZTxJU2FtU2Vzc2lvbj4ge1xuICAgIGlmICh0aGlzLnNlc3Npb24pIHJldHVybiBQcm9taXNlLnJlc29sdmUodGhpcy5zZXNzaW9uKTtcbiAgICBpZiAodGhpcy5zZXNzaW9uTG9hZCkgcmV0dXJuIHRoaXMuc2Vzc2lvbkxvYWQ7XG4gICAgaWYgKCFpc1NhbU1vZGVsUmVhZHkodGhpcy5tb2RlbCkpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoXG4gICAgICAgIGBTQU0gbW9kZWwgXCIke3RoaXMubW9kZWwuaWR9XCIgaXMgbm90IGNvbmZpZ3VyZWQgeWV0IChubyBPTk5YIFVSTHMpLiBgICtcbiAgICAgICAgJ0hvc3QgaXQgYW5kIGNhbGwgc2V0U2FtTW9kZWxVcmxzKCksIHRoZW4gcmV0cnkuJyxcbiAgICAgICkpO1xuICAgIH1cbiAgICB0aGlzLnNlc3Npb25Mb2FkID0gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHsgT25ueFNhbVNlc3Npb24gfSA9IGF3YWl0IGltcG9ydCgnLi9vbm54LXNhbS1zZXNzaW9uJyk7XG4gICAgICAgIGNvbnN0IHNlc3Npb24gPSBuZXcgT25ueFNhbVNlc3Npb24oKTtcbiAgICAgICAgdGhpcy5wcm9ncmVzcyQubmV4dCgwKTtcbiAgICAgICAgYXdhaXQgc2Vzc2lvbi5sb2FkTW9kZWwodGhpcy5tb2RlbCwgKGYpID0+IHRoaXMucHJvZ3Jlc3MkLm5leHQoZikpO1xuICAgICAgICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbkxvYWQgPSBudWxsO1xuICAgICAgfVxuICAgIH0pKCk7XG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbkxvYWQ7XG4gIH1cbn1cbiJdfQ==