@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.
- package/LICENSE +21 -0
- package/README.md +404 -0
- package/esm2022/index.mjs +52 -0
- package/esm2022/jax-data-science-sci-image-visualizer.mjs +5 -0
- package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +398 -0
- package/esm2022/lib/contracts/capabilities.contract.mjs +32 -0
- package/esm2022/lib/contracts/cell-segmenter.contract.mjs +12 -0
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +14 -0
- package/esm2022/lib/contracts/colormap-lut.mjs +95 -0
- package/esm2022/lib/contracts/coordinate-transform.contract.mjs +2 -0
- package/esm2022/lib/contracts/display-types.mjs +8 -0
- package/esm2022/lib/contracts/image.contract.mjs +11 -0
- package/esm2022/lib/contracts/intensity.mjs +28 -0
- package/esm2022/lib/contracts/plot-type.mjs +112 -0
- package/esm2022/lib/contracts/ports/image-state.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/preferences.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/region-io.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/tile-access.port.mjs +3 -0
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +4 -0
- package/esm2022/lib/contracts/region-overlay.contract.mjs +2 -0
- package/esm2022/lib/contracts/region-store.contract.mjs +2 -0
- package/esm2022/lib/contracts/sam.contract.mjs +12 -0
- package/esm2022/lib/contracts/toolbar-config.mjs +8 -0
- package/esm2022/lib/contracts/visualizer.contract.mjs +10 -0
- package/esm2022/lib/contracts/viz-config.mjs +3 -0
- package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +260 -0
- package/esm2022/lib/implementations/base-store-visualizer.mjs +76 -0
- package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +106 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +847 -0
- package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +92 -0
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2283 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +126 -0
- package/esm2022/lib/implementations/osd/display-pipeline.mjs +143 -0
- package/esm2022/lib/implementations/osd/histogram-sampler.mjs +217 -0
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +1780 -0
- package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +25 -0
- package/esm2022/lib/implementations/osd/osd-coords.mjs +53 -0
- package/esm2022/lib/implementations/osd/osd-lib.mjs +20 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +1237 -0
- package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +88 -0
- package/esm2022/lib/implementations/osd/slice-cache.mjs +488 -0
- package/esm2022/lib/implementations/osd/tile-client.mjs +29 -0
- package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +37 -0
- package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +31 -0
- package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +183 -0
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +2137 -0
- package/esm2022/lib/implementations/simple-slice-access.service.mjs +99 -0
- package/esm2022/lib/models/bezier.mjs +120 -0
- package/esm2022/lib/models/class-preset.mjs +46 -0
- package/esm2022/lib/models/geometry.mjs +198 -0
- package/esm2022/lib/models/region.mjs +166 -0
- package/esm2022/lib/models/shape.mjs +53 -0
- package/esm2022/lib/plot.utilities.mjs +693 -0
- package/esm2022/lib/processing/image-converter.service.mjs +90 -0
- package/esm2022/lib/processing/image-crop.mjs +62 -0
- package/esm2022/lib/processing/processing-image.mjs +50 -0
- package/esm2022/lib/provide-visualization.mjs +63 -0
- package/esm2022/lib/region-editor/mask-raster.mjs +95 -0
- package/esm2022/lib/region-editor/mask-worker.mjs +10 -0
- package/esm2022/lib/region-editor/region-editor.component.mjs +1190 -0
- package/esm2022/lib/region-ops.service.mjs +301 -0
- package/esm2022/lib/render-orchestrator.mjs +87 -0
- package/esm2022/lib/routing-visualizer.service.mjs +533 -0
- package/esm2022/lib/store/class-color.util.mjs +52 -0
- package/esm2022/lib/store/region-store.service.mjs +1029 -0
- package/esm2022/lib/store/visualizer-store.service.mjs +352 -0
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +546 -0
- package/esm2022/lib/toolbar/crop/slide-crop.mjs +57 -0
- package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +115 -0
- package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +84 -0
- package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +133 -0
- package/esm2022/lib/toolbar/segmentation/ort-runtime-config.mjs +31 -0
- package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +108 -0
- package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +159 -0
- package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +255 -0
- package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +94 -0
- package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +188 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +311 -0
- package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +234 -0
- package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +499 -0
- package/esm2022/lib/toolbar/wand/wand.service.mjs +921 -0
- package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +157 -0
- package/esm2022/lib/visualization.module.mjs +162 -0
- package/esm2022/lib/visualizer.component.mjs +1597 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs +327 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21314 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -0
- package/fesm2022/mask.worker.js +989 -0
- package/fesm2022/onnx-sam.worker.js +202 -0
- package/index.d.ts +39 -0
- package/lib/channel-histogram/channel-histogram.component.d.ts +112 -0
- package/lib/contracts/capabilities.contract.d.ts +30 -0
- package/lib/contracts/cell-segmenter.contract.d.ts +40 -0
- package/lib/contracts/channel-histogram-api.contract.d.ts +98 -0
- package/lib/contracts/colormap-lut.d.ts +21 -0
- package/lib/contracts/coordinate-transform.contract.d.ts +43 -0
- package/lib/contracts/display-types.d.ts +41 -0
- package/lib/contracts/image.contract.d.ts +72 -0
- package/lib/contracts/intensity.d.ts +18 -0
- package/lib/contracts/plot-type.d.ts +108 -0
- package/lib/contracts/ports/image-state.port.d.ts +29 -0
- package/lib/contracts/ports/preferences.port.d.ts +19 -0
- package/lib/contracts/ports/region-io.port.d.ts +29 -0
- package/lib/contracts/ports/tile-access.port.d.ts +27 -0
- package/lib/contracts/region-editor-api.contract.d.ts +83 -0
- package/lib/contracts/region-overlay.contract.d.ts +47 -0
- package/lib/contracts/region-store.contract.d.ts +74 -0
- package/lib/contracts/sam.contract.d.ts +98 -0
- package/lib/contracts/toolbar-config.d.ts +24 -0
- package/lib/contracts/visualizer.contract.d.ts +346 -0
- package/lib/contracts/viz-config.d.ts +25 -0
- package/lib/hex-color-picker/hex-color-picker.component.d.ts +47 -0
- package/lib/implementations/base-store-visualizer.d.ts +71 -0
- package/lib/implementations/napari-js/napari-axes-labels.d.ts +47 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +115 -0
- package/lib/implementations/napari-js/napari-scale-bar.d.ts +31 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +455 -0
- package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +46 -0
- package/lib/implementations/osd/display-pipeline.d.ts +47 -0
- package/lib/implementations/osd/histogram-sampler.d.ts +85 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +476 -0
- package/lib/implementations/osd/osd-coordinate-transform.d.ts +17 -0
- package/lib/implementations/osd/osd-coords.d.ts +16 -0
- package/lib/implementations/osd/osd-lib.d.ts +19 -0
- package/lib/implementations/osd/osd-region-overlay.d.ts +191 -0
- package/lib/implementations/osd/osd-scale-bar.d.ts +17 -0
- package/lib/implementations/osd/slice-cache.d.ts +161 -0
- package/lib/implementations/osd/tile-client.d.ts +32 -0
- package/lib/implementations/plotly/plotly-coordinate-transform.d.ts +19 -0
- package/lib/implementations/plotly/plotly-region-overlay.d.ts +23 -0
- package/lib/implementations/plotly/plotly-trace-builders.d.ts +60 -0
- package/lib/implementations/plotly/plotly.service.d.ts +594 -0
- package/lib/implementations/simple-slice-access.service.d.ts +64 -0
- package/lib/models/bezier.d.ts +59 -0
- package/lib/models/class-preset.d.ts +39 -0
- package/lib/models/geometry.d.ts +66 -0
- package/lib/models/region.d.ts +132 -0
- package/lib/models/shape.d.ts +44 -0
- package/lib/plot.utilities.d.ts +107 -0
- package/lib/processing/image-converter.service.d.ts +28 -0
- package/lib/processing/image-crop.d.ts +18 -0
- package/lib/processing/processing-image.d.ts +17 -0
- package/lib/provide-visualization.d.ts +34 -0
- package/lib/region-editor/mask-raster.d.ts +61 -0
- package/lib/region-editor/mask-worker.d.ts +7 -0
- package/lib/region-editor/region-editor.component.d.ts +305 -0
- package/lib/region-ops.service.d.ts +92 -0
- package/lib/render-orchestrator.d.ts +59 -0
- package/lib/routing-visualizer.service.d.ts +227 -0
- package/lib/store/class-color.util.d.ts +26 -0
- package/lib/store/region-store.service.d.ts +315 -0
- package/lib/store/visualizer-store.service.d.ts +123 -0
- package/lib/toolbar/brush/brush-tool.service.d.ts +143 -0
- package/lib/toolbar/crop/slide-crop.d.ts +30 -0
- package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +32 -0
- package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +39 -0
- package/lib/toolbar/segmentation/onnx-sam-session.d.ts +25 -0
- package/lib/toolbar/segmentation/ort-runtime-config.d.ts +4 -0
- package/lib/toolbar/segmentation/sam-model-registry.d.ts +36 -0
- package/lib/toolbar/segmentation/sam-onnx-core.d.ts +48 -0
- package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +59 -0
- package/lib/toolbar/segmentation/sam-prompt.d.ts +34 -0
- package/lib/toolbar/segmentation/sam-tool.service.d.ts +50 -0
- package/lib/toolbar/toolbar.component.d.ts +167 -0
- package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +64 -0
- package/lib/toolbar/wand/wand-tool.service.d.ts +149 -0
- package/lib/toolbar/wand/wand.service.d.ts +133 -0
- package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +49 -0
- package/lib/visualization.module.d.ts +45 -0
- package/lib/visualizer.component.d.ts +378 -0
- package/package.json +73 -0
- package/src/lib/assets/3d-coordinates.svg +49 -0
- package/src/lib/assets/cells.svg +1 -0
- package/src/lib/assets/click.svg +1 -0
- package/src/lib/assets/colormap-luts.json +1 -0
- package/src/lib/assets/contour.svg +48 -0
- package/src/lib/assets/cube-3d.svg +1 -0
- package/src/lib/assets/edit-selection-white.svg +47 -0
- package/src/lib/assets/heatmap.svg +1 -0
- package/src/lib/assets/icons/colormap-Pastel1.png +0 -0
- package/src/lib/assets/icons/colormap-accent.png +0 -0
- package/src/lib/assets/icons/colormap-afmhot.png +0 -0
- package/src/lib/assets/icons/colormap-autumn.png +0 -0
- package/src/lib/assets/icons/colormap-berlin.png +0 -0
- package/src/lib/assets/icons/colormap-binary.png +0 -0
- package/src/lib/assets/icons/colormap-blackbody.png +0 -0
- package/src/lib/assets/icons/colormap-bluered.png +0 -0
- package/src/lib/assets/icons/colormap-blues.png +0 -0
- package/src/lib/assets/icons/colormap-bone.png +0 -0
- package/src/lib/assets/icons/colormap-brbg.png +0 -0
- package/src/lib/assets/icons/colormap-brg.png +0 -0
- package/src/lib/assets/icons/colormap-bugn.png +0 -0
- package/src/lib/assets/icons/colormap-bupu.png +0 -0
- package/src/lib/assets/icons/colormap-bwr.png +0 -0
- package/src/lib/assets/icons/colormap-cividis.png +0 -0
- package/src/lib/assets/icons/colormap-cmrmap.png +0 -0
- package/src/lib/assets/icons/colormap-cool.png +0 -0
- package/src/lib/assets/icons/colormap-coolwarm.png +0 -0
- package/src/lib/assets/icons/colormap-copper.png +0 -0
- package/src/lib/assets/icons/colormap-cubehelix.png +0 -0
- package/src/lib/assets/icons/colormap-dark2.png +0 -0
- package/src/lib/assets/icons/colormap-earth.png +0 -0
- package/src/lib/assets/icons/colormap-electric.png +0 -0
- package/src/lib/assets/icons/colormap-flag.png +0 -0
- package/src/lib/assets/icons/colormap-gist_earth.png +0 -0
- package/src/lib/assets/icons/colormap-gist_gray.png +0 -0
- package/src/lib/assets/icons/colormap-gist_heat.png +0 -0
- package/src/lib/assets/icons/colormap-gist_ncar.png +0 -0
- package/src/lib/assets/icons/colormap-gist_rainbow.png +0 -0
- package/src/lib/assets/icons/colormap-gist_stern.png +0 -0
- package/src/lib/assets/icons/colormap-gist_yarg.png +0 -0
- package/src/lib/assets/icons/colormap-gnbu.png +0 -0
- package/src/lib/assets/icons/colormap-gnuplot.png +0 -0
- package/src/lib/assets/icons/colormap-gnuplot2.png +0 -0
- package/src/lib/assets/icons/colormap-gray.png +0 -0
- package/src/lib/assets/icons/colormap-greens-inv.png +0 -0
- package/src/lib/assets/icons/colormap-greens.png +0 -0
- package/src/lib/assets/icons/colormap-greys-inv.png +0 -0
- package/src/lib/assets/icons/colormap-greys.png +0 -0
- package/src/lib/assets/icons/colormap-hot.png +0 -0
- package/src/lib/assets/icons/colormap-hsv.png +0 -0
- package/src/lib/assets/icons/colormap-inferno.png +0 -0
- package/src/lib/assets/icons/colormap-jet.png +0 -0
- package/src/lib/assets/icons/colormap-magma.png +0 -0
- package/src/lib/assets/icons/colormap-managua.png +0 -0
- package/src/lib/assets/icons/colormap-nipy_spectral.png +0 -0
- package/src/lib/assets/icons/colormap-ocean.png +0 -0
- package/src/lib/assets/icons/colormap-oranges.png +0 -0
- package/src/lib/assets/icons/colormap-orrd.png +0 -0
- package/src/lib/assets/icons/colormap-pastel2.png +0 -0
- package/src/lib/assets/icons/colormap-picnic.png +0 -0
- package/src/lib/assets/icons/colormap-pink.png +0 -0
- package/src/lib/assets/icons/colormap-piyg.png +0 -0
- package/src/lib/assets/icons/colormap-placeholder.png +0 -0
- package/src/lib/assets/icons/colormap-plasma.png +0 -0
- package/src/lib/assets/icons/colormap-portland.png +0 -0
- package/src/lib/assets/icons/colormap-prgn.png +0 -0
- package/src/lib/assets/icons/colormap-prism.png +0 -0
- package/src/lib/assets/icons/colormap-pubu.png +0 -0
- package/src/lib/assets/icons/colormap-pubugn.png +0 -0
- package/src/lib/assets/icons/colormap-puor.png +0 -0
- package/src/lib/assets/icons/colormap-purd.png +0 -0
- package/src/lib/assets/icons/colormap-purples.png +0 -0
- package/src/lib/assets/icons/colormap-rainbow.png +0 -0
- package/src/lib/assets/icons/colormap-rdbu.png +0 -0
- package/src/lib/assets/icons/colormap-rdgy.png +0 -0
- package/src/lib/assets/icons/colormap-rdpu.png +0 -0
- package/src/lib/assets/icons/colormap-rdylbu.png +0 -0
- package/src/lib/assets/icons/colormap-rdylgn.png +0 -0
- package/src/lib/assets/icons/colormap-reds.png +0 -0
- package/src/lib/assets/icons/colormap-seismic.png +0 -0
- package/src/lib/assets/icons/colormap-set1.png +0 -0
- package/src/lib/assets/icons/colormap-set2.png +0 -0
- package/src/lib/assets/icons/colormap-set3.png +0 -0
- package/src/lib/assets/icons/colormap-spectral.png +0 -0
- package/src/lib/assets/icons/colormap-spring.png +0 -0
- package/src/lib/assets/icons/colormap-summer.png +0 -0
- package/src/lib/assets/icons/colormap-tab10.png +0 -0
- package/src/lib/assets/icons/colormap-tab20.png +0 -0
- package/src/lib/assets/icons/colormap-tab20b.png +0 -0
- package/src/lib/assets/icons/colormap-tab20c.png +0 -0
- package/src/lib/assets/icons/colormap-terrain.png +0 -0
- package/src/lib/assets/icons/colormap-turbo.png +0 -0
- package/src/lib/assets/icons/colormap-twilight.png +0 -0
- package/src/lib/assets/icons/colormap-twilight_shifted.png +0 -0
- package/src/lib/assets/icons/colormap-vanimo.png +0 -0
- package/src/lib/assets/icons/colormap-viridis.png +0 -0
- package/src/lib/assets/icons/colormap-winter.png +0 -0
- package/src/lib/assets/icons/colormap-wistia.png +0 -0
- package/src/lib/assets/icons/colormap-ylgn.png +0 -0
- package/src/lib/assets/icons/colormap-ylgnbu-inv.png +0 -0
- package/src/lib/assets/icons/colormap-ylgnbu.png +0 -0
- package/src/lib/assets/icons/colormap-ylorbr.png +0 -0
- package/src/lib/assets/icons/colormap-ylorrd-inv.png +0 -0
- package/src/lib/assets/icons/colormap-ylorrd.png +0 -0
- package/src/lib/assets/interactive-segmentation-cursor.svg +1 -0
- package/src/lib/assets/invert.svg +1 -0
- package/src/lib/assets/isosurface.svg +7 -0
- package/src/lib/assets/mask.svg +1 -0
- package/src/lib/assets/paintbrush.svg +1 -0
- package/src/lib/assets/picture-segmentation.svg +43 -0
- package/src/lib/assets/polygon-vertices.svg +13 -0
- package/src/lib/assets/polyline.svg +3 -0
- package/src/lib/assets/redo.svg +39 -0
- package/src/lib/assets/region-editor.svg +37 -0
- package/src/lib/assets/region-move.svg +7 -0
- package/src/lib/assets/smooth.svg +56 -0
- package/src/lib/assets/spline-chart.svg +7 -0
- package/src/lib/assets/surface.svg +37 -0
- package/src/lib/assets/test/download-379.svg +1 -0
- package/src/lib/assets/test/download-98.svg +1 -0
- package/src/lib/assets/test/json-1.svg +1 -0
- package/src/lib/assets/test/load-53.svg +1 -0
- package/src/lib/assets/test/mask-44.svg +1 -0
- package/src/lib/assets/test/mask-download-44.svg +15 -0
- package/src/lib/assets/test/mask-save-44.svg +11 -0
- package/src/lib/assets/test/overlay-1.svg +1 -0
- package/src/lib/assets/test/overlay-4.svg +1 -0
- package/src/lib/assets/test/region-26.svg +1 -0
- package/src/lib/assets/test/save-56.svg +1 -0
- package/src/lib/assets/test/upload-43.svg +1 -0
- package/src/lib/assets/to-bezier.svg +15 -0
- package/src/lib/assets/to-polygon.svg +11 -0
- package/src/lib/assets/undo.svg +38 -0
- package/src/lib/assets/vertex-add.svg +12 -0
- package/src/lib/assets/vertex-delete.svg +12 -0
- package/src/lib/assets/wand.svg +54 -0
- package/src/lib/assets/zoom-box.svg +10 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for SAM inference — no DOM, no ORT, no `this` — so they're unit
|
|
3
|
+
* testable. The session uses these to assemble decoder inputs and to convert
|
|
4
|
+
* the cached image frame into the RGBA buffer the encoder preprocesses.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Build an RGBA buffer (the encoder's input image) from a cached image frame.
|
|
8
|
+
* Grayscale frames are replicated across R/G/B; RGB tuples are copied through.
|
|
9
|
+
* Out-of-range/missing pixels become opaque black.
|
|
10
|
+
*/
|
|
11
|
+
export function frameToRgba(cached, frameIndex) {
|
|
12
|
+
const { width, height } = cached;
|
|
13
|
+
const frame = cached.frames[frameIndex] ?? cached.frames[0];
|
|
14
|
+
const rgba = new Uint8ClampedArray(width * height * 4);
|
|
15
|
+
for (let y = 0; y < height; y++) {
|
|
16
|
+
const row = frame?.[y];
|
|
17
|
+
for (let x = 0; x < width; x++) {
|
|
18
|
+
const o = (y * width + x) * 4;
|
|
19
|
+
const px = row?.[x];
|
|
20
|
+
if (px == null) {
|
|
21
|
+
rgba[o + 3] = 255;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (cached.isGrayscale) {
|
|
25
|
+
const v = px;
|
|
26
|
+
rgba[o] = v;
|
|
27
|
+
rgba[o + 1] = v;
|
|
28
|
+
rgba[o + 2] = v;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const t = px;
|
|
32
|
+
rgba[o] = t[0];
|
|
33
|
+
rgba[o + 1] = t[1];
|
|
34
|
+
rgba[o + 2] = t[2];
|
|
35
|
+
}
|
|
36
|
+
rgba[o + 3] = 255;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return rgba;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Assemble the SAM decoder's `point_coords` / `point_labels` from a prompt.
|
|
43
|
+
*
|
|
44
|
+
* Coordinates are scaled into the encoder's resized space (`scale =
|
|
45
|
+
* inputSize / max(imageW, imageH)`). A box is encoded as two points labelled
|
|
46
|
+
* `2` (top-left) and `3` (bottom-right); positive/negative points use `1`/`0`.
|
|
47
|
+
* When there are points but no box, a padding point `[0,0]` labelled `-1` is
|
|
48
|
+
* appended (the decoder expects the box slots padded when absent).
|
|
49
|
+
*/
|
|
50
|
+
export function buildDecoderPrompt(prompt, scale) {
|
|
51
|
+
const coords = [];
|
|
52
|
+
const labels = [];
|
|
53
|
+
for (const p of prompt.points ?? []) {
|
|
54
|
+
coords.push(p.x * scale, p.y * scale);
|
|
55
|
+
labels.push(p.label);
|
|
56
|
+
}
|
|
57
|
+
if (prompt.box) {
|
|
58
|
+
const b = prompt.box;
|
|
59
|
+
coords.push(b.x0 * scale, b.y0 * scale);
|
|
60
|
+
labels.push(2);
|
|
61
|
+
coords.push(b.x1 * scale, b.y1 * scale);
|
|
62
|
+
labels.push(3);
|
|
63
|
+
}
|
|
64
|
+
else if (labels.length > 0) {
|
|
65
|
+
// Points-only: pad the (absent) box slot.
|
|
66
|
+
coords.push(0, 0);
|
|
67
|
+
labels.push(-1);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
pointCoords: Float32Array.from(coords),
|
|
71
|
+
pointLabels: Float32Array.from(labels),
|
|
72
|
+
numPoints: labels.length,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Binarize SAM mask logits (`> threshold`, default 0 per SAM's mask_threshold)
|
|
77
|
+
* into a 0/1 mask the contour tracer (WandService.maskToPolygons) consumes.
|
|
78
|
+
*/
|
|
79
|
+
export function binarizeMask(logits, threshold = 0) {
|
|
80
|
+
const out = new Uint8Array(logits.length);
|
|
81
|
+
for (let i = 0; i < logits.length; i++)
|
|
82
|
+
out[i] = logits[i] > threshold ? 1 : 0;
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/** Index of the highest-scoring mask in a multimask decoder output. */
|
|
86
|
+
export function bestMaskIndex(iouPredictions) {
|
|
87
|
+
let best = 0;
|
|
88
|
+
for (let i = 1; i < iouPredictions.length; i++) {
|
|
89
|
+
if (iouPredictions[i] > iouPredictions[best])
|
|
90
|
+
best = i;
|
|
91
|
+
}
|
|
92
|
+
return best;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLXByb21wdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXByb21wdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQTs7OztHQUlHO0FBRUg7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUMsTUFBdUIsRUFBRSxVQUFrQjtJQUNyRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUNqQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxLQUFLLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3ZELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNoQyxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN2QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDL0IsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM5QixNQUFNLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNwQixJQUFJLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDZixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQztnQkFDbEIsU0FBUztZQUNYLENBQUM7WUFDRCxJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztn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QUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0UsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQsdUVBQXVFO0FBQ3ZFLE1BQU0sVUFBVSxhQUFhLENBQUMsY0FBdUM7SUFDbkUsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUMvQyxJQUFJLGNBQWMsQ0FBQyxDQUFDLENBQUMsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDO1lBQUUsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2FjaGVkSW1hZ2VEYXRhIH0gZnJvbSAnLi4vd2FuZC93YW5kLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBTYW1Qcm9tcHQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc2FtLmNvbnRyYWN0JztcblxuLyoqXG4gKiBQdXJlIGhlbHBlcnMgZm9yIFNBTSBpbmZlcmVuY2Ug4oCUIG5vIERPTSwgbm8gT1JULCBubyBgdGhpc2Ag4oCUIHNvIHRoZXkncmUgdW5pdFxuICogdGVzdGFibGUuIFRoZSBzZXNzaW9uIHVzZXMgdGhlc2UgdG8gYXNzZW1ibGUgZGVjb2RlciBpbnB1dHMgYW5kIHRvIGNvbnZlcnRcbiAqIHRoZSBjYWNoZWQgaW1hZ2UgZnJhbWUgaW50byB0aGUgUkdCQSBidWZmZXIgdGhlIGVuY29kZXIgcHJlcHJvY2Vzc2VzLlxuICovXG5cbi8qKlxuICogQnVpbGQgYW4gUkdCQSBidWZmZXIgKHRoZSBlbmNvZGVyJ3MgaW5wdXQgaW1hZ2UpIGZyb20gYSBjYWNoZWQgaW1hZ2UgZnJhbWUuXG4gKiBHcmF5c2NhbGUgZnJhbWVzIGFyZSByZXBsaWNhdGVkIGFjcm9zcyBSL0cvQjsgUkdCIHR1cGxlcyBhcmUgY29waWVkIHRocm91Z2guXG4gKiBPdXQtb2YtcmFuZ2UvbWlzc2luZyBwaXhlbHMgYmVjb21lIG9wYXF1ZSBibGFjay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZyYW1lVG9SZ2JhKGNhY2hlZDogQ2FjaGVkSW1hZ2VEYXRhLCBmcmFtZUluZGV4OiBudW1iZXIpOiBVaW50OENsYW1wZWRBcnJheSB7XG4gIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gY2FjaGVkO1xuICBjb25zdCBmcmFtZSA9IGNhY2hlZC5mcmFtZXNbZnJhbWVJbmRleF0gPz8gY2FjaGVkLmZyYW1lc1swXTtcbiAgY29uc3QgcmdiYSA9IG5ldyBVaW50OENsYW1wZWRBcnJheSh3aWR0aCAqIGhlaWdodCAqIDQpO1xuICBmb3IgKGxldCB5ID0gMDsgeSA8IGhlaWdodDsgeSsrKSB7XG4gICAgY29uc3Qgcm93ID0gZnJhbWU/Llt5XTtcbiAgICBmb3IgKGxldCB4ID0gMDsgeCA8IHdpZHRoOyB4KyspIHtcbiAgICAgIGNvbnN0IG8gPSAoeSAqIHdpZHRoICsgeCkgKiA0O1xuICAgICAgY29uc3QgcHggPSByb3c/Llt4XTtcbiAgICAgIGlmIChweCA9PSBudWxsKSB7XG4gICAgICAgIHJnYmFbbyArIDNdID0gMjU1O1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmIChjYWNoZWQuaXNHcmF5c2NhbGUpIHtcbiAgICAgICAgY29uc3QgdiA9IHB4IGFzIG51bWJlcjtcbiAgICAgICAgcmdiYVtvXSA9IHY7IHJnYmFbbyArIDFdID0gdjsgcmdiYVtvICsgMl0gPSB2O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgdCA9IHB4IGFzIG51bWJlcltdO1xuICAgICAgICByZ2JhW29dID0gdFswXTsgcmdiYVtvICsgMV0gPSB0WzFdOyByZ2JhW28gKyAyXSA9IHRbMl07XG4gICAgICB9XG4gICAgICByZ2JhW28gKyAzXSA9IDI1NTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJnYmE7XG59XG5cbi8qKlxuICogQXNzZW1ibGUgdGhlIFNBTSBkZWNvZGVyJ3MgYHBvaW50X2Nvb3Jkc2AgLyBgcG9pbnRfbGFiZWxzYCBmcm9tIGEgcHJvbXB0LlxuICpcbiAqIENvb3JkaW5hdGVzIGFyZSBzY2FsZWQgaW50byB0aGUgZW5jb2RlcidzIHJlc2l6ZWQgc3BhY2UgKGBzY2FsZSA9XG4gKiBpbnB1dFNpemUgLyBtYXgoaW1hZ2VXLCBpbWFnZUgpYCkuIEEgYm94IGlzIGVuY29kZWQgYXMgdHdvIHBvaW50cyBsYWJlbGxlZFxuICogYDJgICh0b3AtbGVmdCkgYW5kIGAzYCAoYm90dG9tLXJpZ2h0KTsgcG9zaXRpdmUvbmVnYXRpdmUgcG9pbnRzIHVzZSBgMWAvYDBgLlxuICogV2hlbiB0aGVyZSBhcmUgcG9pbnRzIGJ1dCBubyBib3gsIGEgcGFkZGluZyBwb2ludCBgWzAsMF1gIGxhYmVsbGVkIGAtMWAgaXNcbiAqIGFwcGVuZGVkICh0aGUgZGVjb2RlciBleHBlY3RzIHRoZSBib3ggc2xvdHMgcGFkZGVkIHdoZW4gYWJzZW50KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkRGVjb2RlclByb21wdChcbiAgcHJvbXB0OiBTYW1Qcm9tcHQsXG4gIHNjYWxlOiBudW1iZXIsXG4pOiB7IHBvaW50Q29vcmRzOiBGbG9hdDMyQXJyYXk7IHBvaW50TGFiZWxzOiBGbG9hdDMyQXJyYXk7IG51bVBvaW50czogbnVtYmVyIH0ge1xuICBjb25zdCBjb29yZHM6IG51bWJlcltdID0gW107XG4gIGNvbnN0IGxhYmVsczogbnVtYmVyW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IHAgb2YgcHJvbXB0LnBvaW50cyA/PyBbXSkge1xuICAgIGNvb3Jkcy5wdXNoKHAueCAqIHNjYWxlLCBwLnkgKiBzY2FsZSk7XG4gICAgbGFiZWxzLnB1c2gocC5sYWJlbCk7XG4gIH1cblxuICBpZiAocHJvbXB0LmJveCkge1xuICAgIGNvbnN0IGIgPSBwcm9tcHQuYm94O1xuICAgIGNvb3Jkcy5wdXNoKGIueDAgKiBzY2FsZSwgYi55MCAqIHNjYWxlKTtcbiAgICBsYWJlbHMucHVzaCgyKTtcbiAgICBjb29yZHMucHVzaChiLngxICogc2NhbGUsIGIueTEgKiBzY2FsZSk7XG4gICAgbGFiZWxzLnB1c2goMyk7XG4gIH0gZWxzZSBpZiAobGFiZWxzLmxlbmd0aCA+IDApIHtcbiAgICAvLyBQb2ludHMtb25seTogcGFkIHRoZSAoYWJzZW50KSBib3ggc2xvdC5cbiAgICBjb29yZHMucHVzaCgwLCAwKTtcbiAgICBsYWJlbHMucHVzaCgtMSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHBvaW50Q29vcmRzOiBGbG9hdDMyQXJyYXkuZnJvbShjb29yZHMpLFxuICAgIHBvaW50TGFiZWxzOiBGbG9hdDMyQXJyYXkuZnJvbShsYWJlbHMpLFxuICAgIG51bVBvaW50czogbGFiZWxzLmxlbmd0aCxcbiAgfTtcbn1cblxuLyoqXG4gKiBCaW5hcml6ZSBTQU0gbWFzayBsb2dpdHMgKGA+IHRocmVzaG9sZGAsIGRlZmF1bHQgMCBwZXIgU0FNJ3MgbWFza190aHJlc2hvbGQpXG4gKiBpbnRvIGEgMC8xIG1hc2sgdGhlIGNvbnRvdXIgdHJhY2VyIChXYW5kU2VydmljZS5tYXNrVG9Qb2x5Z29ucykgY29uc3VtZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBiaW5hcml6ZU1hc2sobG9naXRzOiBGbG9hdDMyQXJyYXkgfCBudW1iZXJbXSwgdGhyZXNob2xkID0gMCk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBvdXQgPSBuZXcgVWludDhBcnJheShsb2dpdHMubGVuZ3RoKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsb2dpdHMubGVuZ3RoOyBpKyspIG91dFtpXSA9IGxvZ2l0c1tpXSA+IHRocmVzaG9sZCA/IDEgOiAwO1xuICByZXR1cm4gb3V0O1xufVxuXG4vKiogSW5kZXggb2YgdGhlIGhpZ2hlc3Qtc2NvcmluZyBtYXNrIGluIGEgbXVsdGltYXNrIGRlY29kZXIgb3V0cHV0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlc3RNYXNrSW5kZXgoaW91UHJlZGljdGlvbnM6IEZsb2F0MzJBcnJheSB8IG51bWJlcltdKTogbnVtYmVyIHtcbiAgbGV0IGJlc3QgPSAwO1xuICBmb3IgKGxldCBpID0gMTsgaSA8IGlvdVByZWRpY3Rpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGlvdVByZWRpY3Rpb25zW2ldID4gaW91UHJlZGljdGlvbnNbYmVzdF0pIGJlc3QgPSBpO1xuICB9XG4gIHJldHVybiBiZXN0O1xufVxuIl19
|
|
@@ -0,0 +1,188 @@
|
|
|
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, Rectangle } from '../../models/region';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
import * as i1 from "../wand/wand.service";
|
|
9
|
+
/**
|
|
10
|
+
* Box-prompted SAM segmentation tool (jit-ui#90, P0). On `segmentBoxes()` it
|
|
11
|
+
* reads every rectangle region, runs the (cached) encoder once for the image,
|
|
12
|
+
* then runs the decoder per box, traces each mask to a polygon (reusing
|
|
13
|
+
* WandService.maskToPolygons) and commits them as regions.
|
|
14
|
+
*
|
|
15
|
+
* Inference is abstracted behind {@link ISamSession}: production uses the
|
|
16
|
+
* onnxruntime-web session (lazy-imported so ORT never loads in unit tests);
|
|
17
|
+
* tests inject a fake via {@link useSession}.
|
|
18
|
+
*/
|
|
19
|
+
export class SamToolService {
|
|
20
|
+
constructor(wandService) {
|
|
21
|
+
this.wandService = wandService;
|
|
22
|
+
this.session = null;
|
|
23
|
+
this.model = getSamModel();
|
|
24
|
+
/** Cached encoder embedding + the key (image identity) it was computed for. */
|
|
25
|
+
this.embedding = null;
|
|
26
|
+
this.embeddingKey = null;
|
|
27
|
+
/** Status text + busy flag for a spinner / toast in the host. */
|
|
28
|
+
this.status$ = new BehaviorSubject('');
|
|
29
|
+
this.busy$ = new BehaviorSubject(false);
|
|
30
|
+
/** Encoder-download progress: -1 = not downloading, 0..1 = downloading. */
|
|
31
|
+
this.progress$ = new BehaviorSubject(-1);
|
|
32
|
+
}
|
|
33
|
+
/** Bind to the active backend's host (called by the backend, like the wand). */
|
|
34
|
+
bindHost(host) {
|
|
35
|
+
this.host = host;
|
|
36
|
+
}
|
|
37
|
+
/** Choose the registered model to use; invalidates any cached embedding. */
|
|
38
|
+
setModel(id) {
|
|
39
|
+
const next = getSamModel(id);
|
|
40
|
+
if (next.id === this.model.id)
|
|
41
|
+
return;
|
|
42
|
+
this.model = next;
|
|
43
|
+
this.invalidateEmbedding();
|
|
44
|
+
// Drop the loaded session so the next run reloads the newly-picked model's
|
|
45
|
+
// ONNX pair — ensureSession() returns the cached session as-is, so without
|
|
46
|
+
// this a model switch would keep running the previous model.
|
|
47
|
+
this.session?.dispose();
|
|
48
|
+
this.session = null;
|
|
49
|
+
}
|
|
50
|
+
/** Drop the cached embedding (e.g. after the image/slice changes). */
|
|
51
|
+
invalidateEmbedding() {
|
|
52
|
+
this.embedding = null;
|
|
53
|
+
this.embeddingKey = null;
|
|
54
|
+
}
|
|
55
|
+
/** Test seam: inject a fake/alternate inference session. */
|
|
56
|
+
useSession(session) {
|
|
57
|
+
this.session = session;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Segment every rectangle region with a box prompt and append the resulting
|
|
61
|
+
* masks as new polygon regions. Returns how many regions were added.
|
|
62
|
+
*/
|
|
63
|
+
async segmentBoxes() {
|
|
64
|
+
if (!this.host)
|
|
65
|
+
return 0;
|
|
66
|
+
// Re-entrancy guard: a second Segment press while the first run is still
|
|
67
|
+
// downloading/encoding would launch a concurrent model download + GPU
|
|
68
|
+
// encode (and can freeze the tab on a heavy WebGPU ViT-B). Ignore it.
|
|
69
|
+
if (this.busy$.value)
|
|
70
|
+
return 0;
|
|
71
|
+
const cached = this.host.getCachedImageData();
|
|
72
|
+
if (!cached || cached.frames.length === 0) {
|
|
73
|
+
this.status$.next('No image loaded.');
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
const regions = this.host.getRegions();
|
|
77
|
+
const rects = regions.filter((r) => r.bounds instanceof Rectangle);
|
|
78
|
+
if (rects.length === 0) {
|
|
79
|
+
this.status$.next('Draw one or more rectangles, then press Segment.');
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const rx = cached.ratios[0] || 1;
|
|
83
|
+
const ry = cached.ratios[0] || 1;
|
|
84
|
+
const ox = cached.originX ?? 0;
|
|
85
|
+
const oy = cached.originY ?? 0;
|
|
86
|
+
let session;
|
|
87
|
+
try {
|
|
88
|
+
session = await this.ensureSession();
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
this.busy$.next(false);
|
|
92
|
+
this.status$.next(err instanceof Error ? err.message : 'SAM model unavailable.');
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
this.busy$.next(true);
|
|
96
|
+
try {
|
|
97
|
+
// Encode once per image; reuse the embedding across all boxes.
|
|
98
|
+
const key = [
|
|
99
|
+
this.host.getFileName() ?? '',
|
|
100
|
+
this.host.getActiveFrameIndex(),
|
|
101
|
+
`${cached.width}x${cached.height}`,
|
|
102
|
+
`${ox},${oy},${rx}`,
|
|
103
|
+
this.model.id,
|
|
104
|
+
].join('|');
|
|
105
|
+
if (!this.embedding || this.embeddingKey !== key) {
|
|
106
|
+
this.status$.next('Encoding image…');
|
|
107
|
+
const rgba = frameToRgba(cached, this.host.getActiveFrameIndex());
|
|
108
|
+
this.embedding = await session.embed({ data: rgba, width: cached.width, height: cached.height });
|
|
109
|
+
this.embeddingKey = key;
|
|
110
|
+
}
|
|
111
|
+
const masks = [];
|
|
112
|
+
const consumed = new Set(); // prompt rectangles that produced a mask
|
|
113
|
+
let added = 0;
|
|
114
|
+
for (let i = 0; i < rects.length; i++) {
|
|
115
|
+
this.status$.next(`Segmenting ${i + 1}/${rects.length}…`);
|
|
116
|
+
const b = rects[i].bounds;
|
|
117
|
+
// Rectangle is in data coords → convert to image (matrix) coords.
|
|
118
|
+
const box = {
|
|
119
|
+
x0: (b.x - ox) / rx,
|
|
120
|
+
y0: (b.y - oy) / ry,
|
|
121
|
+
x1: (b.x + b.width - ox) / rx,
|
|
122
|
+
y1: (b.y + b.height - oy) / ry,
|
|
123
|
+
};
|
|
124
|
+
const res = await session.decode(this.embedding, { box });
|
|
125
|
+
const polys = this.wandService.maskToPolygons(res.mask, res.width, res.height, cached.width, cached.height, 0, 0);
|
|
126
|
+
if (polys.length === 0)
|
|
127
|
+
continue;
|
|
128
|
+
// Keep the largest connected piece (maskToPolygons returns largest-first).
|
|
129
|
+
const poly = polys[0];
|
|
130
|
+
masks.push(this.makeRegion(poly.xpoints.map((x) => ox + x * rx), poly.ypoints.map((y) => oy + y * ry), rects[i].color));
|
|
131
|
+
consumed.add(rects[i]); // this rectangle is now represented by its mask
|
|
132
|
+
added++;
|
|
133
|
+
}
|
|
134
|
+
// Replace each segmented prompt rectangle with its mask region; keep any
|
|
135
|
+
// rectangle that produced no mask (so it can be retried) + other regions.
|
|
136
|
+
const out = regions.filter((r) => !consumed.has(r)).concat(masks);
|
|
137
|
+
this.host.setRegions(out);
|
|
138
|
+
this.status$.next(added > 0 ? `Added ${added} region(s).` : 'No masks found.');
|
|
139
|
+
return added;
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
this.status$.next(err instanceof Error ? err.message : 'Segmentation failed.');
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
this.busy$.next(false);
|
|
147
|
+
this.progress$.next(-1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
makeRegion(xData, yData, color) {
|
|
151
|
+
const poly = new Polygon();
|
|
152
|
+
poly.npoints = xData.length;
|
|
153
|
+
poly.xpoints = xData;
|
|
154
|
+
poly.ypoints = yData;
|
|
155
|
+
poly.coordinates = xData.map((x, i) => [x, yData[i]]);
|
|
156
|
+
poly.closed = true;
|
|
157
|
+
const region = new Region();
|
|
158
|
+
region.bounds = poly;
|
|
159
|
+
// Inherit the source prompt rectangle's color; fall back to the host default.
|
|
160
|
+
region.color = color || this.host.getShapeColor();
|
|
161
|
+
// Default class/annotation name, matching the wand/brush + overlay-drawn regions.
|
|
162
|
+
region.label = 'sam';
|
|
163
|
+
return region;
|
|
164
|
+
}
|
|
165
|
+
async ensureSession() {
|
|
166
|
+
if (this.session)
|
|
167
|
+
return this.session;
|
|
168
|
+
if (!isSamModelReady(this.model)) {
|
|
169
|
+
throw new Error(`SAM model "${this.model.id}" is not configured yet (no ONNX URLs). ` +
|
|
170
|
+
'Host it and call setSamModelUrls(), then retry.');
|
|
171
|
+
}
|
|
172
|
+
// Lazy-import so onnxruntime-web is never pulled into unit tests / the
|
|
173
|
+
// initial bundle — only when segmentation actually runs.
|
|
174
|
+
const { OnnxSamSession } = await import('./onnx-sam-session');
|
|
175
|
+
const session = new OnnxSamSession();
|
|
176
|
+
this.progress$.next(0);
|
|
177
|
+
await session.loadModel(this.model, (f) => this.progress$.next(f));
|
|
178
|
+
this.session = session;
|
|
179
|
+
return session;
|
|
180
|
+
}
|
|
181
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamToolService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
182
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamToolService, providedIn: 'root' }); }
|
|
183
|
+
}
|
|
184
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamToolService, decorators: [{
|
|
185
|
+
type: Injectable,
|
|
186
|
+
args: [{ providedIn: 'root' }]
|
|
187
|
+
}], ctorParameters: () => [{ type: i1.WandService }] });
|
|
188
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLXRvb2wuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXRvb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFdkMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRW5ELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVwRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBTWpFOzs7Ozs7Ozs7R0FTRztBQUVILE1BQU0sT0FBTyxjQUFjO0lBZXpCLFlBQW9CLFdBQXdCO1FBQXhCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBYnBDLFlBQU8sR0FBdUIsSUFBSSxDQUFDO1FBQ25DLFVBQUssR0FBZ0IsV0FBVyxFQUFFLENBQUM7UUFFM0MsK0VBQStFO1FBQ3ZFLGNBQVMsR0FBd0IsSUFBSSxDQUFDO1FBQ3RDLGlCQUFZLEdBQWtCLElBQUksQ0FBQztRQUUzQyxpRUFBaUU7UUFDeEQsWUFBTyxHQUFHLElBQUksZUFBZSxDQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLFVBQUssR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUNyRCwyRUFBMkU7UUFDbEUsY0FBUyxHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFTixDQUFDO0lBRWhELGdGQUFnRjtJQUNoRixRQUFRLENBQUMsSUFBaUI7UUFDeEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENB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Q0FBQyxFQUFFLDBDQUEwQztnQkFDckUsaURBQWlELENBQ2xELENBQUM7UUFDSixDQUFDO1FBQ0QsdUVBQXVFO1FBQ3ZFLHlEQUF5RDtRQUN6RCxNQUFNLEVBQUUsY0FBYyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUM5RCxNQUFNLE9BQU8sR0FBRyxJQUFJLGNBQWMsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3ZCLE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25FLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7OEdBakxVLGNBQWM7a0hBQWQsY0FBYyxjQURELE1BQU07OzJGQUNuQixjQUFjO2tCQUQxQixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBXYW5kU2VydmljZSB9IGZyb20gJy4uL3dhbmQvd2FuZC5zZXJ2aWNlJztcbmltcG9ydCB7IFdhbmRUb29sSG9zdCB9IGZyb20gJy4uL3dhbmQvd2FuZC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgZnJhbWVUb1JnYmEgfSBmcm9tICcuL3NhbS1wcm9tcHQnO1xuaW1wb3J0IHsgZ2V0U2FtTW9kZWwsIGlzU2FtTW9kZWxSZWFkeSB9IGZyb20gJy4vc2FtLW1vZGVsLXJlZ2lzdHJ5JztcbmltcG9ydCB7IElTYW1TZXNzaW9uLCBTYW1FbWJlZGRpbmcsIFNhbU1vZGVsRGVmIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NhbS5jb250cmFjdCc7XG5pbXBvcnQgeyBSZWdpb24sIFBvbHlnb24sIFJlY3RhbmdsZSB9IGZyb20gJy4uLy4uL21vZGVscy9yZWdpb24nO1xuXG4vKiogVGhlIFNBTSB0b29sIGJpbmRzIHRvIHRoZSBzYW1lIGhvc3QgdGhlIHdhbmQvYnJ1c2ggdXNlLCBzbyBlYWNoIGJhY2tlbmRcbiAqICByZXVzZXMgaXRzIGV4aXN0aW5nIHBpeGVsIHJlYWRiYWNrICsgY29vcmRpbmF0ZSB0cmFuc2Zvcm0gKyByZWdpb24gc3RvcmUuICovXG5leHBvcnQgdHlwZSBTYW1Ub29sSG9zdCA9IFdhbmRUb29sSG9zdDtcblxuLyoqXG4gKiBCb3gtcHJvbXB0ZWQgU0FNIHNlZ21lbnRhdGlvbiB0b29sIChqaXQtdWkjOTAsIFAwKS4gT24gYHNlZ21lbnRCb3hlcygpYCBpdFxuICogcmVhZHMgZXZlcnkgcmVjdGFuZ2xlIHJlZ2lvbiwgcnVucyB0aGUgKGNhY2hlZCkgZW5jb2RlciBvbmNlIGZvciB0aGUgaW1hZ2UsXG4gKiB0aGVuIHJ1bnMgdGhlIGRlY29kZXIgcGVyIGJveCwgdHJhY2VzIGVhY2ggbWFzayB0byBhIHBvbHlnb24gKHJldXNpbmdcbiAqIFdhbmRTZXJ2aWNlLm1hc2tUb1BvbHlnb25zKSBhbmQgY29tbWl0cyB0aGVtIGFzIHJlZ2lvbnMuXG4gKlxuICogSW5mZXJlbmNlIGlzIGFic3RyYWN0ZWQgYmVoaW5kIHtAbGluayBJU2FtU2Vzc2lvbn06IHByb2R1Y3Rpb24gdXNlcyB0aGVcbiAqIG9ubnhydW50aW1lLXdlYiBzZXNzaW9uIChsYXp5LWltcG9ydGVkIHNvIE9SVCBuZXZlciBsb2FkcyBpbiB1bml0IHRlc3RzKTtcbiAqIHRlc3RzIGluamVjdCBhIGZha2UgdmlhIHtAbGluayB1c2VTZXNzaW9ufS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBTYW1Ub29sU2VydmljZSB7XG4gIHByaXZhdGUgaG9zdCE6IFNhbVRvb2xIb3N0O1xuICBwcml2YXRlIHNlc3Npb246IElTYW1TZXNzaW9uIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbW9kZWw6IFNhbU1vZGVsRGVmID0gZ2V0U2FtTW9kZWwoKTtcblxuICAvKiogQ2FjaGVkIGVuY29kZXIgZW1iZWRkaW5nICsgdGhlIGtleSAoaW1hZ2UgaWRlbnRpdHkpIGl0IHdhcyBjb21wdXRlZCBmb3IuICovXG4gIHByaXZhdGUgZW1iZWRkaW5nOiBTYW1FbWJlZGRpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBlbWJlZGRpbmdLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBTdGF0dXMgdGV4dCArIGJ1c3kgZmxhZyBmb3IgYSBzcGlubmVyIC8gdG9hc3QgaW4gdGhlIGhvc3QuICovXG4gIHJlYWRvbmx5IHN0YXR1cyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xuICByZWFkb25seSBidXN5JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogRW5jb2Rlci1kb3dubG9hZCBwcm9ncmVzczogLTEgPSBub3QgZG93bmxvYWRpbmcsIDAuLjEgPSBkb3dubG9hZGluZy4gKi9cbiAgcmVhZG9ubHkgcHJvZ3Jlc3MkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KC0xKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHdhbmRTZXJ2aWNlOiBXYW5kU2VydmljZSkge31cblxuICAvKiogQmluZCB0byB0aGUgYWN0aXZlIGJhY2tlbmQncyBob3N0IChjYWxsZWQgYnkgdGhlIGJhY2tlbmQsIGxpa2UgdGhlIHdhbmQpLiAqL1xuICBiaW5kSG9zdChob3N0OiBTYW1Ub29sSG9zdCk6IHZvaWQge1xuICAgIHRoaXMuaG9zdCA9IGhvc3Q7XG4gIH1cblxuICAvKiogQ2hvb3NlIHRoZSByZWdpc3RlcmVkIG1vZGVsIHRvIHVzZTsgaW52YWxpZGF0ZXMgYW55IGNhY2hlZCBlbWJlZGRpbmcuICovXG4gIHNldE1vZGVsKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gZ2V0U2FtTW9kZWwoaWQpO1xuICAgIGlmIChuZXh0LmlkID09PSB0aGlzLm1vZGVsLmlkKSByZXR1cm47XG4gICAgdGhpcy5tb2RlbCA9IG5leHQ7XG4gICAgdGhpcy5pbnZhbGlkYXRlRW1iZWRkaW5nKCk7XG4gICAgLy8gRHJvcCB0aGUgbG9hZGVkIHNlc3Npb24gc28gdGhlIG5leHQgcnVuIHJlbG9hZHMgdGhlIG5ld2x5LXBpY2tlZCBtb2RlbCdzXG4gICAgLy8gT05OWCBwYWlyIOKAlCBlbnN1cmVTZXNzaW9uKCkgcmV0dXJucyB0aGUgY2FjaGVkIHNlc3Npb24gYXMtaXMsIHNvIHdpdGhvdXRcbiAgICAvLyB0aGlzIGEgbW9kZWwgc3dpdGNoIHdvdWxkIGtlZXAgcnVubmluZyB0aGUgcHJldmlvdXMgbW9kZWwuXG4gICAgdGhpcy5zZXNzaW9uPy5kaXNwb3NlKCk7XG4gICAgdGhpcy5zZXNzaW9uID0gbnVsbDtcbiAgfVxuXG4gIC8qKiBEcm9wIHRoZSBjYWNoZWQgZW1iZWRkaW5nIChlLmcuIGFmdGVyIHRoZSBpbWFnZS9zbGljZSBjaGFuZ2VzKS4gKi9cbiAgaW52YWxpZGF0ZUVtYmVkZGluZygpOiB2b2lkIHtcbiAgICB0aGlzLmVtYmVkZGluZyA9IG51bGw7XG4gICAgdGhpcy5lbWJlZGRpbmdLZXkgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRlc3Qgc2VhbTogaW5qZWN0IGEgZmFrZS9hbHRlcm5hdGUgaW5mZXJlbmNlIHNlc3Npb24uICovXG4gIHVzZVNlc3Npb24oc2Vzc2lvbjogSVNhbVNlc3Npb24pOiB2b2lkIHtcbiAgICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlZ21lbnQgZXZlcnkgcmVjdGFuZ2xlIHJlZ2lvbiB3aXRoIGEgYm94IHByb21wdCBhbmQgYXBwZW5kIHRoZSByZXN1bHRpbmdcbiAgICogbWFza3MgYXMgbmV3IHBvbHlnb24gcmVnaW9ucy4gUmV0dXJucyBob3cgbWFueSByZWdpb25zIHdlcmUgYWRkZWQuXG4gICAqL1xuICBhc3luYyBzZWdtZW50Qm94ZXMoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAoIXRoaXMuaG9zdCkgcmV0dXJuIDA7XG4gICAgLy8gUmUtZW50cmFuY3kgZ3VhcmQ6IGEgc2Vjb25kIFNlZ21lbnQgcHJlc3Mgd2hpbGUgdGhlIGZpcnN0IHJ1biBpcyBzdGlsbFxuICAgIC8vIGRvd25sb2FkaW5nL2VuY29kaW5nIHdvdWxkIGxhdW5jaCBhIGNvbmN1cnJlbnQgbW9kZWwgZG93bmxvYWQgKyBHUFVcbiAgICAvLyBlbmNvZGUgKGFuZCBjYW4gZnJlZXplIHRoZSB0YWIgb24gYSBoZWF2eSBXZWJHUFUgVmlULUIpLiBJZ25vcmUgaXQuXG4gICAgaWYgKHRoaXMuYnVzeSQudmFsdWUpIHJldHVybiAwO1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuaG9zdC5nZXRDYWNoZWRJbWFnZURhdGEoKTtcbiAgICBpZiAoIWNhY2hlZCB8fCBjYWNoZWQuZnJhbWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5zdGF0dXMkLm5leHQoJ05vIGltYWdlIGxvYWRlZC4nKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLmhvc3QuZ2V0UmVnaW9ucygpO1xuICAgIGNvbnN0IHJlY3RzID0gcmVnaW9ucy5maWx0ZXIoKHIpID0+IHIuYm91bmRzIGluc3RhbmNlb2YgUmVjdGFuZ2xlKTtcbiAgICBpZiAocmVjdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLnN0YXR1cyQubmV4dCgnRHJhdyBvbmUgb3IgbW9yZSByZWN0YW5nbGVzLCB0aGVuIHByZXNzIFNlZ21lbnQuJyk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBjb25zdCByeCA9IGNhY2hlZC5yYXRpb3NbMF0gfHwgMTtcbiAgICBjb25zdCByeSA9IGNhY2hlZC5yYXRpb3NbMF0gfHwgMTtcbiAgICBjb25zdCBveCA9IGNhY2hlZC5vcmlnaW5YID8/IDA7XG4gICAgY29uc3Qgb3kgPSBjYWNoZWQub3JpZ2luWSA/PyAwO1xuXG4gICAgbGV0IHNlc3Npb246IElTYW1TZXNzaW9uO1xuICAgIHRyeSB7XG4gICAgICBzZXNzaW9uID0gYXdhaXQgdGhpcy5lbnN1cmVTZXNzaW9uKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmJ1c3kkLm5leHQoZmFsc2UpO1xuICAgICAgdGhpcy5zdGF0dXMkLm5leHQoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6ICdTQU0gbW9kZWwgdW5hdmFpbGFibGUuJyk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICB0aGlzLmJ1c3kkLm5leHQodHJ1ZSk7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEVuY29kZSBvbmNlIHBlciBpbWFnZTsgcmV1c2UgdGhlIGVtYmVkZGluZyBhY3Jvc3MgYWxsIGJveGVzLlxuICAgICAgY29uc3Qga2V5ID0gW1xuICAgICAgICB0aGlzLmhvc3QuZ2V0RmlsZU5hbWUoKSA/PyAnJyxcbiAgICAgICAgdGhpcy5ob3N0LmdldEFjdGl2ZUZyYW1lSW5kZXgoKSxcbiAgICAgICAgYCR7Y2FjaGVkLndpZHRofXgke2NhY2hlZC5oZWlnaHR9YCxcbiAgICAgICAgYCR7b3h9LCR7b3l9LCR7cnh9YCxcbiAgICAgICAgdGhpcy5tb2RlbC5pZCxcbiAgICAgIF0uam9pbignfCcpO1xuICAgICAgaWYgKCF0aGlzLmVtYmVkZGluZyB8fCB0aGlzLmVtYmVkZGluZ0tleSAhPT0ga2V5KSB7XG4gICAgICAgIHRoaXMuc3RhdHVzJC5uZXh0KCdFbmNvZGluZyBpbWFnZeKApicpO1xuICAgICAgICBjb25zdCByZ2JhID0gZnJhbWVUb1JnYmEoY2FjaGVkLCB0aGlzLmhvc3QuZ2V0QWN0aXZlRnJhbWVJbmRleCgpKTtcbiAgICAgICAgdGhpcy5lbWJlZGRpbmcgPSBhd2FpdCBzZXNzaW9uLmVtYmVkKHsgZGF0YTogcmdiYSwgd2lkdGg6IGNhY2hlZC53aWR0aCwgaGVpZ2h0OiBjYWNoZWQuaGVpZ2h0IH0pO1xuICAgICAgICB0aGlzLmVtYmVkZGluZ0tleSA9IGtleTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWFza3M6IFJlZ2lvbltdID0gW107XG4gICAgICBjb25zdCBjb25zdW1lZCA9IG5ldyBTZXQ8UmVnaW9uPigpOyAvLyBwcm9tcHQgcmVjdGFuZ2xlcyB0aGF0IHByb2R1Y2VkIGEgbWFza1xuICAgICAgbGV0IGFkZGVkID0gMDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVjdHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5zdGF0dXMkLm5leHQoYFNlZ21lbnRpbmcgJHtpICsgMX0vJHtyZWN0cy5sZW5ndGh94oCmYCk7XG4gICAgICAgIGNvbnN0IGIgPSByZWN0c1tpXS5ib3VuZHMgYXMgUmVjdGFuZ2xlO1xuICAgICAgICAvLyBSZWN0YW5nbGUgaXMgaW4gZGF0YSBjb29yZHMg4oaSIGNvbnZlcnQgdG8gaW1hZ2UgKG1hdHJpeCkgY29vcmRzLlxuICAgICAgICBjb25zdCBib3ggPSB7XG4gICAgICAgICAgeDA6IChiLnggLSBveCkgLyByeCxcbiAgICAgICAgICB5MDogKGIueSAtIG95KSAvIHJ5LFxuICAgICAgICAgIHgxOiAoYi54ICsgYi53aWR0aCAtIG94KSAvIHJ4LFxuICAgICAgICAgIHkxOiAoYi55ICsgYi5oZWlnaHQgLSBveSkgLyByeSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgc2Vzc2lvbi5kZWNvZGUodGhpcy5lbWJlZGRpbmcsIHsgYm94IH0pO1xuICAgICAgICBjb25zdCBwb2x5cyA9IHRoaXMud2FuZFNlcnZpY2UubWFza1RvUG9seWdvbnMoXG4gICAgICAgICAgcmVzLm1hc2ssIHJlcy53aWR0aCwgcmVzLmhlaWdodCwgY2FjaGVkLndpZHRoLCBjYWNoZWQuaGVpZ2h0LCAwLCAwLFxuICAgICAgICApO1xuICAgICAgICBpZiAocG9seXMubGVuZ3RoID09PSAwKSBjb250aW51ZTtcbiAgICAgICAgLy8gS2VlcCB0aGUgbGFyZ2VzdCBjb25uZWN0ZWQgcGllY2UgKG1hc2tUb1BvbHlnb25zIHJldHVybnMgbGFyZ2VzdC1maXJzdCkuXG4gICAgICAgIGNvbnN0IHBvbHkgPSBwb2x5c1swXTtcbiAgICAgICAgbWFza3MucHVzaCh0aGlzLm1ha2VSZWdpb24oXG4gICAgICAgICAgcG9seS54cG9pbnRzLm1hcCgoeCkgPT4gb3ggKyB4ICogcngpLFxuICAgICAgICAgIHBvbHkueXBvaW50cy5tYXAoKHkpID0+IG95ICsgeSAqIHJ5KSxcbiAgICAgICAgICByZWN0c1tpXS5jb2xvciwgLy8gaW5oZXJpdCB0aGUgcHJvbXB0IHJlY3RhbmdsZSdzIGNvbG9yXG4gICAgICAgICkpO1xuICAgICAgICBjb25zdW1lZC5hZGQocmVjdHNbaV0pOyAvLyB0aGlzIHJlY3RhbmdsZSBpcyBub3cgcmVwcmVzZW50ZWQgYnkgaXRzIG1hc2tcbiAgICAgICAgYWRkZWQrKztcbiAgICAgIH1cblxuICAgICAgLy8gUmVwbGFjZSBlYWNoIHNlZ21lbnRlZCBwcm9tcHQgcmVjdGFuZ2xlIHdpdGggaXRzIG1hc2sgcmVnaW9uOyBrZWVwIGFueVxuICAgICAgLy8gcmVjdGFuZ2xlIHRoYXQgcHJvZHVjZWQgbm8gbWFzayAoc28gaXQgY2FuIGJlIHJldHJpZWQpICsgb3RoZXIgcmVnaW9ucy5cbiAgICAgIGNvbnN0IG91dCA9IHJlZ2lvbnMuZmlsdGVyKChyKSA9PiAhY29uc3VtZWQuaGFzKHIpKS5jb25jYXQobWFza3MpO1xuICAgICAgdGhpcy5ob3N0LnNldFJlZ2lvbnMob3V0KTtcbiAgICAgIHRoaXMuc3RhdHVzJC5uZXh0KGFkZGVkID4gMCA/IGBBZGRlZCAke2FkZGVkfSByZWdpb24ocykuYCA6ICdObyBtYXNrcyBmb3VuZC4nKTtcbiAgICAgIHJldHVybiBhZGRlZDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuc3RhdHVzJC5uZXh0KGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAnU2VnbWVudGF0aW9uIGZhaWxlZC4nKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmJ1c3kkLm5leHQoZmFsc2UpO1xuICAgICAgdGhpcy5wcm9ncmVzcyQubmV4dCgtMSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtYWtlUmVnaW9uKHhEYXRhOiBudW1iZXJbXSwgeURhdGE6IG51bWJlcltdLCBjb2xvcj86IHN0cmluZyk6IFJlZ2lvbiB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0geERhdGEubGVuZ3RoO1xuICAgIHBvbHkueHBvaW50cyA9IHhEYXRhO1xuICAgIHBvbHkueXBvaW50cyA9IHlEYXRhO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSB4RGF0YS5tYXAoKHgsIGkpID0+IFt4LCB5RGF0YVtpXV0pO1xuICAgIHBvbHkuY2xvc2VkID0gdHJ1ZTtcblxuICAgIGNvbnN0IHJlZ2lvbiA9IG5ldyBSZWdpb24oKTtcbiAgICByZWdpb24uYm91bmRzID0gcG9seTtcbiAgICAvLyBJbmhlcml0IHRoZSBzb3VyY2UgcHJvbXB0IHJlY3RhbmdsZSdzIGNvbG9yOyBmYWxsIGJhY2sgdG8gdGhlIGhvc3QgZGVmYXVsdC5cbiAgICByZWdpb24uY29sb3IgPSBjb2xvciB8fCB0aGlzLmhvc3QuZ2V0U2hhcGVDb2xvcigpO1xuICAgIC8vIERlZmF1bHQgY2xhc3MvYW5ub3RhdGlvbiBuYW1lLCBtYXRjaGluZyB0aGUgd2FuZC9icnVzaCArIG92ZXJsYXktZHJhd24gcmVnaW9ucy5cbiAgICByZWdpb24ubGFiZWwgPSAnc2FtJztcbiAgICByZXR1cm4gcmVnaW9uO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVTZXNzaW9uKCk6IFByb21pc2U8SVNhbVNlc3Npb24+IHtcbiAgICBpZiAodGhpcy5zZXNzaW9uKSByZXR1cm4gdGhpcy5zZXNzaW9uO1xuICAgIGlmICghaXNTYW1Nb2RlbFJlYWR5KHRoaXMubW9kZWwpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBTQU0gbW9kZWwgXCIke3RoaXMubW9kZWwuaWR9XCIgaXMgbm90IGNvbmZpZ3VyZWQgeWV0IChubyBPTk5YIFVSTHMpLiBgICtcbiAgICAgICAgJ0hvc3QgaXQgYW5kIGNhbGwgc2V0U2FtTW9kZWxVcmxzKCksIHRoZW4gcmV0cnkuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIExhenktaW1wb3J0IHNvIG9ubnhydW50aW1lLXdlYiBpcyBuZXZlciBwdWxsZWQgaW50byB1bml0IHRlc3RzIC8gdGhlXG4gICAgLy8gaW5pdGlhbCBidW5kbGUg4oCUIG9ubHkgd2hlbiBzZWdtZW50YXRpb24gYWN0dWFsbHkgcnVucy5cbiAgICBjb25zdCB7IE9ubnhTYW1TZXNzaW9uIH0gPSBhd2FpdCBpbXBvcnQoJy4vb25ueC1zYW0tc2Vzc2lvbicpO1xuICAgIGNvbnN0IHNlc3Npb24gPSBuZXcgT25ueFNhbVNlc3Npb24oKTtcbiAgICB0aGlzLnByb2dyZXNzJC5uZXh0KDApO1xuICAgIGF3YWl0IHNlc3Npb24ubG9hZE1vZGVsKHRoaXMubW9kZWwsIChmKSA9PiB0aGlzLnByb2dyZXNzJC5uZXh0KGYpKTtcbiAgICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICAgIHJldHVybiBzZXNzaW9uO1xuICB9XG59XG4iXX0=
|