@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,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bezier-curve helpers (no external dependency).
|
|
3
|
+
*
|
|
4
|
+
* JIT supports true bezier regions: a polygon's vertices are the editable
|
|
5
|
+
* *anchors*, and the smooth curve through them is derived here with the
|
|
6
|
+
* Catmull-Rom construction — the same algorithm paper.js uses in
|
|
7
|
+
* `path.smooth()`. The curve interpolates every anchor and
|
|
8
|
+
* each anchor's two handles are colinear (a smooth tangent).
|
|
9
|
+
*
|
|
10
|
+
* The OSD overlay renders the curve as a true cubic SVG path + draggable handles
|
|
11
|
+
* (see {@link bezierAnchorHandles}); GeoJSON export flattens the *same* cubics
|
|
12
|
+
* into a dense point list (see {@link bezierCurve}) so a viewer without bezier
|
|
13
|
+
* support (e.g. QuPath, which just draws the coordinate list) still shows the
|
|
14
|
+
* smooth shape. Using one algorithm for both keeps what JIT draws identical to
|
|
15
|
+
* what it exports.
|
|
16
|
+
*
|
|
17
|
+
* Pure functions: no DOM, no service state. Coordinates are image pixels.
|
|
18
|
+
*/
|
|
19
|
+
export interface CurvePoints {
|
|
20
|
+
xs: number[];
|
|
21
|
+
ys: number[];
|
|
22
|
+
}
|
|
23
|
+
/** A vertex's two cubic-bezier control points (absolute coords) plus whether
|
|
24
|
+
* each side has a handle (open-path endpoints have only one). */
|
|
25
|
+
export interface AnchorHandle {
|
|
26
|
+
in: [number, number];
|
|
27
|
+
out: [number, number];
|
|
28
|
+
hasIn: boolean;
|
|
29
|
+
hasOut: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Per-anchor cubic-bezier control points using the Catmull-Rom construction
|
|
33
|
+
* (tension 1: control = anchor ± (next − prev) / 6). Matches paper.js
|
|
34
|
+
* `path.smooth()`: the resulting cubic interpolates every anchor and the two
|
|
35
|
+
* handles of each anchor are colinear. Coordinates are in the input space.
|
|
36
|
+
*/
|
|
37
|
+
export declare function bezierAnchorHandles(xs: number[], ys: number[], closed: boolean): AnchorHandle[];
|
|
38
|
+
/** The Catmull-Rom handles as **relative** offsets `[dx, dy]` per anchor — used
|
|
39
|
+
* to initialise a region's editable handles when bezier is turned on. */
|
|
40
|
+
export declare function defaultHandleOffsets(xs: number[], ys: number[], closed: boolean): {
|
|
41
|
+
in: number[][];
|
|
42
|
+
out: number[][];
|
|
43
|
+
};
|
|
44
|
+
/** Absolute handles from stored relative offsets (anchor + offset). */
|
|
45
|
+
export declare function handlesFromOffsets(xs: number[], ys: number[], inOff: number[][], outOff: number[][], closed: boolean): AnchorHandle[];
|
|
46
|
+
/** A region's handles: from its stored (editable) offsets when present, else the
|
|
47
|
+
* Catmull-Rom default. The single source of truth for both rendering and export. */
|
|
48
|
+
export declare function resolveHandles(xs: number[], ys: number[], closed: boolean, inOff?: number[][], outOff?: number[][]): AnchorHandle[];
|
|
49
|
+
/**
|
|
50
|
+
* Flatten a cubic bezier (defined by explicit per-anchor handles) into a dense
|
|
51
|
+
* point list by sampling each segment. The curve passes through every anchor; a
|
|
52
|
+
* closed ring returns to its first point.
|
|
53
|
+
*/
|
|
54
|
+
export declare function bezierCurveFromHandles(xs: number[], ys: number[], handles: AnchorHandle[], closed: boolean): CurvePoints;
|
|
55
|
+
/**
|
|
56
|
+
* Flatten the smooth Catmull-Rom bezier through the anchors (no custom handles).
|
|
57
|
+
* Falls back to the anchors when there are too few to form a curve.
|
|
58
|
+
*/
|
|
59
|
+
export declare function bezierCurve(xs: number[], ys: number[], closed: boolean): CurvePoints;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset annotation classes (jit-ui#70).
|
|
3
|
+
*
|
|
4
|
+
* A class is a flat `{ name, color }` pair (v1: no hierarchy, no special-class semantics).
|
|
5
|
+
* The `PresetSet` is the per-user, server-persisted source of truth for region colours;
|
|
6
|
+
* see `class-color.util.ts` for the deterministic colour-resolution engine.
|
|
7
|
+
*/
|
|
8
|
+
export type PresetSource = 'user' | 'default' | 'auto';
|
|
9
|
+
export interface ClassPreset {
|
|
10
|
+
/** The class name — matched against `Region.label`. */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Hex colour, `#RRGGBB`. */
|
|
13
|
+
color: string;
|
|
14
|
+
/** Reserved for a future per-class overlay-visibility toggle. */
|
|
15
|
+
visible?: boolean;
|
|
16
|
+
/** Provenance; `'auto'` = added by opt-in fallback promotion. */
|
|
17
|
+
source?: PresetSource;
|
|
18
|
+
}
|
|
19
|
+
export type MatchMode = 'exact' | 'normalized';
|
|
20
|
+
export interface PresetSet {
|
|
21
|
+
/** Ordered list of preset classes. */
|
|
22
|
+
classes: ClassPreset[];
|
|
23
|
+
/** Colours used for classes not in `classes` (assigned deterministically). */
|
|
24
|
+
fallbackPalette: string[];
|
|
25
|
+
/** Opt-in (default false): add an unknown class to `classes` the first time it is seen. */
|
|
26
|
+
autoPromote: boolean;
|
|
27
|
+
/** Label matching against `Region.label` (default `'exact'`). */
|
|
28
|
+
matchMode: MatchMode;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fallback palette for classes not present in the preset set — reasonably distinct hues.
|
|
32
|
+
* Colours are assigned by a stable hash of the class name, so the same unknown class always
|
|
33
|
+
* gets the same colour with no stored state.
|
|
34
|
+
*/
|
|
35
|
+
export declare const DEFAULT_FALLBACK_PALETTE: string[];
|
|
36
|
+
/** A fresh default preset set (deep-copied so callers can mutate safely). */
|
|
37
|
+
export declare function defaultPresetSet(): PresetSet;
|
|
38
|
+
/** True when the set has no usable classes (e.g. the server returned an empty/blank record). */
|
|
39
|
+
export declare function isEmptyPresetSet(set: PresetSet | null | undefined): boolean;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure geometry helpers extracted from PlotlyService.
|
|
3
|
+
*
|
|
4
|
+
* No DOM access, no service state, no `this` — every function is testable
|
|
5
|
+
* in isolation. Keep it that way: this module is the dumping ground for
|
|
6
|
+
* shape/mask/SVG-path utilities the wand, vertex eraser, and region editor
|
|
7
|
+
* share. If a helper grows a `this.shapes` reference, it doesn't belong here.
|
|
8
|
+
*/
|
|
9
|
+
/** A bbox-relative binary mask (1 = filled, 0 = empty). */
|
|
10
|
+
export interface BBoxMask {
|
|
11
|
+
bx: number;
|
|
12
|
+
by: number;
|
|
13
|
+
bw: number;
|
|
14
|
+
bh: number;
|
|
15
|
+
mask: Uint8Array;
|
|
16
|
+
}
|
|
17
|
+
/** Parsed single-subpath polygon vertices. */
|
|
18
|
+
export interface PolygonVertices {
|
|
19
|
+
xpoints: number[];
|
|
20
|
+
ypoints: number[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parse a single-subpath `M x,y L x,y ... Z` path into vertex arrays.
|
|
24
|
+
*
|
|
25
|
+
* Returns null for paths we can't safely round-trip (multi-subpath, curves,
|
|
26
|
+
* fewer than three vertices). The wand only adopts shapes it produced or
|
|
27
|
+
* that Plotly's drawclosedpath produces, both of which are single-subpath
|
|
28
|
+
* polygons.
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseSvgPathPolygon(path: string): PolygonVertices | null;
|
|
31
|
+
/**
|
|
32
|
+
* Build a closed SVG path string `M x,y L x,y L ... Z` from vertex arrays.
|
|
33
|
+
* Returns '' for fewer than three vertices (degenerate).
|
|
34
|
+
*/
|
|
35
|
+
export declare function polygonToSvgPath(xpoints: number[], ypoints: number[]): string;
|
|
36
|
+
/**
|
|
37
|
+
* Build an SVG path string from vertex arrays. Closed polygons end with `Z`,
|
|
38
|
+
* open polylines do not. Returns '' for fewer than two vertices (degenerate).
|
|
39
|
+
*/
|
|
40
|
+
export declare function verticesToSvgPath(xs: number[], ys: number[], closed: boolean): string;
|
|
41
|
+
/**
|
|
42
|
+
* Compare two Plotly shape objects for "same region" — used by the wand to
|
|
43
|
+
* avoid appending duplicates when the user pushes the same find result more
|
|
44
|
+
* than once. Polygons compare by SVG path string, rectangles compare by
|
|
45
|
+
* (x0, y0, x1, y1).
|
|
46
|
+
*/
|
|
47
|
+
export declare function shapesEqual(a: any, b: any): boolean;
|
|
48
|
+
/** Returns true if the two bbox-relative masks share at least one set pixel. */
|
|
49
|
+
export declare function masksOverlap(a: BBoxMask, b: BBoxMask): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Allocate a fresh accumulator covering both masks and OR them in. The
|
|
52
|
+
* resulting mask's bbox is the smallest rectangle containing both inputs.
|
|
53
|
+
*/
|
|
54
|
+
export declare function unionMasks(a: BBoxMask, b: BBoxMask): BBoxMask;
|
|
55
|
+
/**
|
|
56
|
+
* Simplify a closed ring with the Douglas–Peucker algorithm (jit-ui#85):
|
|
57
|
+
* drop every vertex that lies within `epsilon` pixels (the "altitude
|
|
58
|
+
* threshold") of the line between its kept neighbours. Anchored at vertex 0
|
|
59
|
+
* (the ring is closed by appending it). Rings of ≤ 3 vertices, or a
|
|
60
|
+
* non-positive epsilon, are returned unchanged. Output keeps the closed-ring
|
|
61
|
+
* convention (no repeated closing point).
|
|
62
|
+
*/
|
|
63
|
+
export declare function simplifyRing(xs: number[], ys: number[], epsilon: number): {
|
|
64
|
+
xs: number[];
|
|
65
|
+
ys: number[];
|
|
66
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { ShapeSelection } from './shape';
|
|
2
|
+
export declare class Region {
|
|
3
|
+
/** Stable, unique identity for selection and equality. Minted by
|
|
4
|
+
* PlotlyService when a region first enters the system. Never derived
|
|
5
|
+
* from array index — name collisions across delete/add cycles must
|
|
6
|
+
* not break PrimeNG row selection. */
|
|
7
|
+
id: number;
|
|
8
|
+
name: string;
|
|
9
|
+
bounds?: Rectangle | Polygon | MultiPolygon | null;
|
|
10
|
+
/** profile = an intensity-profile line ROI; rendered/dragged like a region but
|
|
11
|
+
* excluded from the Regions tab and exports. Use `isProfile()` to test it —
|
|
12
|
+
* it's the canonical marker that separates intensity lines (owned by the
|
|
13
|
+
* intensity tool, sampled into the inset) from annotation regions (owned by
|
|
14
|
+
* the Region Editor). Both backends (Plotly, OSD) honour it. */
|
|
15
|
+
kind?: 'profile';
|
|
16
|
+
color?: string;
|
|
17
|
+
label?: string;
|
|
18
|
+
/** True when the user set this region's colour explicitly (Region Editor Color
|
|
19
|
+
* column). Preset colour resolution (jit-ui#70) skips overridden regions so a
|
|
20
|
+
* manual colour is not clobbered when presets are (re)applied on load/import. */
|
|
21
|
+
colorOverridden?: boolean;
|
|
22
|
+
filename?: string;
|
|
23
|
+
/** Zero-based z-slice this region belongs to within a stack — mirrors
|
|
24
|
+
* QuPath's `geometry.plane.z` (a missing plane / default plane reads back as
|
|
25
|
+
* 0). Used to place/filter ROIs per slice; 0 for a plain single-plane image
|
|
26
|
+
* or a region drawn without a slice context (jit-ui#93). */
|
|
27
|
+
z: number;
|
|
28
|
+
shapeColor?: string | undefined;
|
|
29
|
+
bytesPerPixel: number;
|
|
30
|
+
/**
|
|
31
|
+
* resolution is the resolution at which the region
|
|
32
|
+
* was found. In order to get it in the full image
|
|
33
|
+
* coordinates it will normally be 0. However if
|
|
34
|
+
* there is a mistake with the resolution it may not
|
|
35
|
+
* be. We return the resolution here in order to be
|
|
36
|
+
* sure what it is. The server may need to be changed
|
|
37
|
+
* to ensure that results regions are always returned
|
|
38
|
+
* at resolution = 0
|
|
39
|
+
*/
|
|
40
|
+
resolution: number;
|
|
41
|
+
cropped: boolean;
|
|
42
|
+
tileNumber: number;
|
|
43
|
+
tileCoordinates: number[] | null;
|
|
44
|
+
/** True for intensity-profile line ROIs (the intensity tool's lines). These are
|
|
45
|
+
* NOT annotation regions: they never appear in the Region Editor and editor
|
|
46
|
+
* operations (select/save/delete) must never touch them. */
|
|
47
|
+
isProfile(): boolean;
|
|
48
|
+
toString(): string;
|
|
49
|
+
/**
|
|
50
|
+
* Returns a ShapeSelection object that can be used to
|
|
51
|
+
* create a shape in Plotly.
|
|
52
|
+
* @param showRegionLabel
|
|
53
|
+
* @return ShapeSelection
|
|
54
|
+
*/
|
|
55
|
+
getShape(showRegionLabel?: boolean): ShapeSelection;
|
|
56
|
+
isRectangle(bnds: any): bnds is Rectangle;
|
|
57
|
+
isPolygon(bnds: any): bnds is Polygon;
|
|
58
|
+
}
|
|
59
|
+
export declare class Rectangle {
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
}
|
|
65
|
+
export declare class Polygon {
|
|
66
|
+
npoints: number;
|
|
67
|
+
xpoints: number[];
|
|
68
|
+
ypoints: number[];
|
|
69
|
+
coordinates: number[][];
|
|
70
|
+
/** false for open polylines; true (default) for closed polygons */
|
|
71
|
+
closed: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* When true the vertices are treated as bezier-spline **anchors** and the
|
|
74
|
+
* region is rendered/exported as a smooth curve through them. The vertices
|
|
75
|
+
* stay the editable anchors — toggling this flag is the toBezier
|
|
76
|
+
* (`true`) / toPolygon (`false`), which only add/remove the curve, never move
|
|
77
|
+
* the anchors. GeoJSON keeps the flattened curve as the geometry (so QuPath
|
|
78
|
+
* renders it) plus the anchors + handles + flag in properties (so JIT
|
|
79
|
+
* round-trips the editable bezier).
|
|
80
|
+
*/
|
|
81
|
+
bezier: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Per-anchor cubic-bezier control-point offsets, **relative** to their anchor
|
|
84
|
+
* (so they translate with it). Present only for bezier regions; initialised
|
|
85
|
+
* from the Catmull-Rom construction (a smooth curve) when bezier is turned on,
|
|
86
|
+
* then individually editable by dragging the handles. `handlesIn[i]` /
|
|
87
|
+
* `handlesOut[i]` are `[dx, dy]` for vertex `i`.
|
|
88
|
+
*/
|
|
89
|
+
handlesIn?: number[][];
|
|
90
|
+
handlesOut?: number[][];
|
|
91
|
+
/**
|
|
92
|
+
* Interior rings (holes) — jit-ui#85. Each ring is a list of `[x, y]`
|
|
93
|
+
* image-pixel pairs in the SAME closed-polygon convention as the exterior
|
|
94
|
+
* (`coordinates`): no repeated closing point. Present only on closed polygons.
|
|
95
|
+
* A point inside the exterior **and** inside any hole is OUTSIDE the region
|
|
96
|
+
* (even-odd rule). Absent/empty == a solid polygon (the prior behaviour), so
|
|
97
|
+
* every existing region is unaffected.
|
|
98
|
+
*/
|
|
99
|
+
holes?: number[][][];
|
|
100
|
+
/**
|
|
101
|
+
* Per-hole bézier control-point offsets, parallel to {@link holes} (one entry per ring, each a
|
|
102
|
+
* list of `[dx, dy]` per ring vertex, **relative** to the vertex). Present only when `bezier` is
|
|
103
|
+
* on for a donut — seeded from the Catmull-Rom default and individually editable, exactly like
|
|
104
|
+
* the exterior {@link handlesIn}/{@link handlesOut}. So a donut smoothed to a bézier curves its
|
|
105
|
+
* holes too (jit-ui#102).
|
|
106
|
+
*/
|
|
107
|
+
holeHandlesIn?: number[][][];
|
|
108
|
+
holeHandlesOut?: number[][][];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* A region whose geometry is several disjoint parts — e.g. the result of merging
|
|
112
|
+
* two non-touching regions, or the inverse of a blob (jit-ui#85). Each part is a
|
|
113
|
+
* closed {@link Polygon} that may carry its own holes, so a MultiPolygon
|
|
114
|
+
* represents "sparse bits, some with donut holes" as a single region. Maps 1:1
|
|
115
|
+
* onto a GeoJSON `MultiPolygon` (and QuPath's geometry).
|
|
116
|
+
*
|
|
117
|
+
* A single-part MultiPolygon is equivalent to that Polygon; callers should
|
|
118
|
+
* prefer a plain {@link Polygon} for one connected part.
|
|
119
|
+
*/
|
|
120
|
+
export declare class MultiPolygon {
|
|
121
|
+
/** One or more disjoint closed polygons (each may have holes). */
|
|
122
|
+
polygons: Polygon[];
|
|
123
|
+
}
|
|
124
|
+
export type Bounds = Rectangle | Polygon | {
|
|
125
|
+
x?: number;
|
|
126
|
+
y?: number;
|
|
127
|
+
width?: number;
|
|
128
|
+
height?: number;
|
|
129
|
+
npoints?: number;
|
|
130
|
+
xpoints?: number[];
|
|
131
|
+
ypoints?: number[];
|
|
132
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Region } from './region';
|
|
2
|
+
import { Datum, Font, Shape, ShapeLabel, ShapeLine, XAxisName, YAxisName } from 'plotly.js-dist-min';
|
|
3
|
+
export declare class ShapeSelection implements Shape {
|
|
4
|
+
/** Stable, unique identity carried alongside the shape so it round-trips
|
|
5
|
+
* through Plotly's relayout untouched. Plotly preserves unknown
|
|
6
|
+
* properties on shape objects, so this survives the same way `legend`
|
|
7
|
+
* and `fileName` already do. */
|
|
8
|
+
id: number;
|
|
9
|
+
name: string;
|
|
10
|
+
fillcolor: string;
|
|
11
|
+
label: Partial<ShapeLabel>;
|
|
12
|
+
layer: 'below' | 'above';
|
|
13
|
+
legendgroup: string;
|
|
14
|
+
legendgrouptitle: {
|
|
15
|
+
text: string;
|
|
16
|
+
font?: Partial<Font>;
|
|
17
|
+
};
|
|
18
|
+
legendrank: number;
|
|
19
|
+
line: Partial<ShapeLine>;
|
|
20
|
+
opacity: number;
|
|
21
|
+
path: string;
|
|
22
|
+
showlegend: boolean;
|
|
23
|
+
templateitemname: string;
|
|
24
|
+
type: 'rect' | 'circle' | 'line' | 'path';
|
|
25
|
+
visible: boolean | 'legendonly';
|
|
26
|
+
x0: Datum;
|
|
27
|
+
x1: Datum;
|
|
28
|
+
xanchor: number | string;
|
|
29
|
+
xref: 'paper' | XAxisName;
|
|
30
|
+
xsizemode: 'scaled' | 'pixel';
|
|
31
|
+
y0: Datum;
|
|
32
|
+
y1: Datum;
|
|
33
|
+
yanchor: number | string;
|
|
34
|
+
yref: 'paper' | YAxisName;
|
|
35
|
+
ysizemode: 'scaled' | 'pixel';
|
|
36
|
+
editable: boolean;
|
|
37
|
+
legend: any;
|
|
38
|
+
fileName: string | undefined;
|
|
39
|
+
kind?: 'profile';
|
|
40
|
+
/**
|
|
41
|
+
* Returns a Region object based on the shape type.
|
|
42
|
+
*/
|
|
43
|
+
getRegion(): Region;
|
|
44
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Rectangle, Region } from './models/region';
|
|
2
|
+
import { ShapeSelection } from './models/shape';
|
|
3
|
+
export declare const COLORMAP_OPTIONS: {
|
|
4
|
+
label: string;
|
|
5
|
+
data: null;
|
|
6
|
+
children: {
|
|
7
|
+
label: string;
|
|
8
|
+
data: {
|
|
9
|
+
value: string;
|
|
10
|
+
src: string;
|
|
11
|
+
};
|
|
12
|
+
}[];
|
|
13
|
+
}[];
|
|
14
|
+
export declare const CONFIG: {
|
|
15
|
+
displaylogo: boolean;
|
|
16
|
+
responsive: boolean;
|
|
17
|
+
displayModeBar: boolean;
|
|
18
|
+
scrollZoom: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare const CONFIG_SURFACE: {
|
|
21
|
+
displaylogo: boolean;
|
|
22
|
+
responsive: boolean;
|
|
23
|
+
displayModeBar: boolean;
|
|
24
|
+
scrollZoom: boolean;
|
|
25
|
+
};
|
|
26
|
+
export declare class PlotUtilities {
|
|
27
|
+
/**
|
|
28
|
+
* Rounds all the point coordinates of a path ('M13.54,54.566L35.44,33.3L36.22,89.6Z')
|
|
29
|
+
* becomes 'M14,55L35,33L36,90Z'
|
|
30
|
+
* @param path
|
|
31
|
+
*/
|
|
32
|
+
roundPathCoordinates(path: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Transform a 1d array into a matrix given a given width
|
|
35
|
+
* @param array Uint8Array
|
|
36
|
+
* @param elementsPerSubArray
|
|
37
|
+
*/
|
|
38
|
+
arrayToMatrix(array: any[] | Uint8Array, elementsPerSubArray: number): any[];
|
|
39
|
+
/**
|
|
40
|
+
* coordinates are of the bottom left and upper right corners of the rectangle, The coordinates
|
|
41
|
+
* are taken given a yAxis that is up side down (as for all images). If Zoom is out of the image boundary,
|
|
42
|
+
* it will return the image size coordinates for the new rectangle.
|
|
43
|
+
* @param coordinates plotly coordinates ([Xaxis.range[0], xAxis.range[1], yAxis.range[0], yaxis.range[1]])
|
|
44
|
+
* @param trueImageSize true image size [0, x, 0, y]
|
|
45
|
+
*/
|
|
46
|
+
getRectangle(coordinates: number[], trueImageSize: number[]): Rectangle;
|
|
47
|
+
/**
|
|
48
|
+
* given a dom object (found by id), return a Rectangle of the bounding element.
|
|
49
|
+
* @param div
|
|
50
|
+
*/
|
|
51
|
+
getDomRectangle(div: string): Rectangle;
|
|
52
|
+
/**
|
|
53
|
+
* snap region to closest pixel in the coordinate (round the coordinates of the region)
|
|
54
|
+
* @param shape
|
|
55
|
+
* @private
|
|
56
|
+
*/
|
|
57
|
+
snapRegion(shape: ShapeSelection): ShapeSelection;
|
|
58
|
+
/**
|
|
59
|
+
* Given a figure (path or rectangle), returns a polygon
|
|
60
|
+
* @param fig
|
|
61
|
+
*/
|
|
62
|
+
getPolygon(fig: any): any;
|
|
63
|
+
/**
|
|
64
|
+
* TESTED
|
|
65
|
+
* Rounds a list of numbers
|
|
66
|
+
* @param a
|
|
67
|
+
*/
|
|
68
|
+
round(a: number[]): number[];
|
|
69
|
+
/**
|
|
70
|
+
* TESTED
|
|
71
|
+
* Returns true of zoom is the same as image size
|
|
72
|
+
* @param rect Rectangle area
|
|
73
|
+
* @param trueImgSize
|
|
74
|
+
* @return true if rect is out of image size boundary
|
|
75
|
+
*/
|
|
76
|
+
isZoomSameAsImgSize(rect: Rectangle, trueImgSize: number[]): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Save the json string to a file
|
|
79
|
+
* @param jsonString
|
|
80
|
+
*/
|
|
81
|
+
saveToFile(jsonString: any, baseName?: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Function that imports ROIs from a geojson object
|
|
84
|
+
* @param geoJsonStr
|
|
85
|
+
* @return Region[]
|
|
86
|
+
*/
|
|
87
|
+
importROIsFromGeoJson(geoJsonStr: string): Region[];
|
|
88
|
+
/**
|
|
89
|
+
* Function that returns a geojson object from a Plotly ROI
|
|
90
|
+
* @param rois
|
|
91
|
+
* @return FeatureCollection<Geometry, GeoJsonProperties>
|
|
92
|
+
*/
|
|
93
|
+
exportROIsToGeoJson(rois: Region[]): string;
|
|
94
|
+
/**
|
|
95
|
+
* Convert GeoJSON interior rings into the neutral hole representation
|
|
96
|
+
* (`number[][]` per ring, no repeated closing point). Degenerate rings (< 3
|
|
97
|
+
* distinct points) are dropped. jit-ui#85.
|
|
98
|
+
*/
|
|
99
|
+
/**
|
|
100
|
+
* Build a closed {@link Polygon} from a GeoJSON ring set: `rings[0]` is the
|
|
101
|
+
* exterior (closing point dropped), `rings[1..]` are interior holes. jit-ui#85.
|
|
102
|
+
*/
|
|
103
|
+
private polygonFromRings;
|
|
104
|
+
private ringsToHoles;
|
|
105
|
+
rgbToHex(r: number, g: number, b: number): string;
|
|
106
|
+
hexToRgb(hex: string | undefined): number[];
|
|
107
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ProcessingImage } from './processing-image';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* Converts between various image representations. Bridges image-js, browser
|
|
5
|
+
* canvas/image elements, and the neutral {@link ProcessingImage}. Generic image
|
|
6
|
+
* plumbing — no app/pipeline coupling.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ImageConverterService {
|
|
9
|
+
/**
|
|
10
|
+
* Convert an image-js Image instance to ProcessingImage.
|
|
11
|
+
* image-js stores pixel data in a typed array with shape (width*height*channels).
|
|
12
|
+
*/
|
|
13
|
+
fromImageJs(image: any): ProcessingImage;
|
|
14
|
+
/** Convert from an HTMLCanvasElement. */
|
|
15
|
+
fromCanvas(canvas: HTMLCanvasElement): ProcessingImage;
|
|
16
|
+
/** Convert from an HTMLImageElement. */
|
|
17
|
+
fromHtmlImage(img: HTMLImageElement): ProcessingImage;
|
|
18
|
+
/** Convert ProcessingImage to a 2D array suitable for Plotly heatmap (grayscale). */
|
|
19
|
+
toPlotlyHeatmapZ(image: ProcessingImage): number[][];
|
|
20
|
+
/** Convert ProcessingImage to Plotly RGB arrays [r[][], g[][], b[][]]. */
|
|
21
|
+
toPlotlyRgbArrays(image: ProcessingImage): {
|
|
22
|
+
r: number[][];
|
|
23
|
+
g: number[][];
|
|
24
|
+
b: number[][];
|
|
25
|
+
};
|
|
26
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ImageConverterService, never>;
|
|
27
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ImageConverterService>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ProcessingImage } from './processing-image';
|
|
2
|
+
/** Crop options in source-image pixels. Out-of-range values are clamped. */
|
|
3
|
+
export interface CropImageOptions {
|
|
4
|
+
x?: number;
|
|
5
|
+
y?: number;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
/** Power-of-two downsample level applied to the crop (0 = full resolution). */
|
|
9
|
+
level?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Crop a rectangular region out of a {@link ProcessingImage} (browser-side, the
|
|
13
|
+
* counterpart of the JIT server's Slide Crop), optionally downsampling the crop
|
|
14
|
+
* by `2^level`. The rectangle is in source pixels and clamped to the image, so
|
|
15
|
+
* out-of-range values snap to the valid region rather than throwing. Always
|
|
16
|
+
* returns a 4-channel (RGBA) image.
|
|
17
|
+
*/
|
|
18
|
+
export declare function cropImage(image: ProcessingImage, opts?: CropImageOptions): ProcessingImage;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified image container used throughout the processing pipeline.
|
|
3
|
+
* Decouples pipeline logic from any specific library's image format.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ProcessingImage {
|
|
6
|
+
readonly width: number;
|
|
7
|
+
readonly height: number;
|
|
8
|
+
readonly channels: number;
|
|
9
|
+
readonly data: Uint8ClampedArray;
|
|
10
|
+
/** Create from browser ImageData. */
|
|
11
|
+
static fromImageData(imageData: ImageData): ProcessingImage;
|
|
12
|
+
constructor(width: number, height: number, channels: number, data: Uint8ClampedArray);
|
|
13
|
+
/** Convert to browser-native ImageData (RGBA). */
|
|
14
|
+
toImageData(): ImageData;
|
|
15
|
+
/** Convert to Blob for saving/downloading. */
|
|
16
|
+
toBlob(mime?: string): Promise<Blob>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Provider } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* A self-contained, isolated visualization backend chain for a component subtree.
|
|
4
|
+
*
|
|
5
|
+
* The chain services are `providedIn: 'root'` singletons, so by default the whole
|
|
6
|
+
* app shares one viewer's state (regions, image, channels, render handles) — which
|
|
7
|
+
* is correct for the single main viewer. A consumer that needs a SECOND, independent
|
|
8
|
+
* viewer (e.g. a modal that mounts `<visualizer>` over the live main view
|
|
9
|
+
* and must not clobber its regions/image) drops this into its component `providers`:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* @Component({
|
|
13
|
+
* ...,
|
|
14
|
+
* providers: [
|
|
15
|
+
* ...provideVisualization(), // isolated chain instance
|
|
16
|
+
* // plus the host ports + config for THIS viewer:
|
|
17
|
+
* { provide: IMAGE_STATE_PORT, useClass: MyImageStateAdapter },
|
|
18
|
+
* { provide: TILE_ACCESS_PORT, useClass: MyTileAccessAdapter },
|
|
19
|
+
* { provide: REGION_IO_PORT, useClass: MyRegionIoAdapter },
|
|
20
|
+
* { provide: VIZ_CONFIG, useValue: { slideCropServer: '' } },
|
|
21
|
+
* ],
|
|
22
|
+
* })
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Component-scoped providers shadow the root singletons for that subtree, so the
|
|
26
|
+
* embedded viewer gets its own router/Plotly/OSD/stores/tools while the rest of the
|
|
27
|
+
* app keeps the default root instance.
|
|
28
|
+
*
|
|
29
|
+
* Lists EVERY stateful service in the chain. Stateless collaborators (HttpClient,
|
|
30
|
+
* MessageService, WandService) deliberately resolve to root — they hold no
|
|
31
|
+
* per-viewer state, so sharing them is correct and keeps this list minimal. When a
|
|
32
|
+
* new stateful service joins the rendering chain, add it here too.
|
|
33
|
+
*/
|
|
34
|
+
export declare function provideVisualization(): Provider[];
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Region } from '../models/region';
|
|
2
|
+
/** A single closed ring (+ optional holes) in image-pixel coordinates. A region
|
|
3
|
+
* rasterizes as the union of its parts. Plain data so it survives a
|
|
4
|
+
* `postMessage` structured clone into the mask worker. */
|
|
5
|
+
export interface MaskPart {
|
|
6
|
+
xpoints: number[];
|
|
7
|
+
ypoints: number[];
|
|
8
|
+
holes?: number[][][];
|
|
9
|
+
}
|
|
10
|
+
/** A bbox-relative binary mask, as returned by `WandService.rasterizePolygon`. */
|
|
11
|
+
export interface BBoxMask {
|
|
12
|
+
bx: number;
|
|
13
|
+
by: number;
|
|
14
|
+
bw: number;
|
|
15
|
+
bh: number;
|
|
16
|
+
mask: Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
/** Polygon-fill function (the wand's scanline rasterizer), injected so this
|
|
19
|
+
* module stays free of Angular/DOM and can run inside a worker. */
|
|
20
|
+
export type RasterizeFn = (xpoints: number[], ypoints: number[], imageWidth: number, imageHeight: number, holes?: number[][][]) => BBoxMask | null;
|
|
21
|
+
/**
|
|
22
|
+
* The largest mask we will allocate, in pixels. A single-channel 8-bit mask is
|
|
23
|
+
* one byte per pixel, so this is also its byte size. Whole-slide level-0 images
|
|
24
|
+
* (e.g. 119040×90112 ≈ 1.07e10 px) blow past both the JS typed-array length cap
|
|
25
|
+
* (~4.29e9) and available memory, so masks for images larger than this are
|
|
26
|
+
* rasterized at a proportionally downscaled resolution. ~100 MP ≈ 100 MB.
|
|
27
|
+
*/
|
|
28
|
+
export declare const MAX_MASK_PIXELS = 100000000;
|
|
29
|
+
/** Downscale factor (≤ 1) to keep `width * height` within {@link MAX_MASK_PIXELS}.
|
|
30
|
+
* 1 when the image already fits. */
|
|
31
|
+
export declare function maskScaleFor(width: number, height: number): number;
|
|
32
|
+
/** Multiply every coordinate (and hole coordinate) of a region's parts by
|
|
33
|
+
* `scale`, for rasterizing into a downscaled mask. Returns the parts unchanged
|
|
34
|
+
* when `scale` is 1. */
|
|
35
|
+
export declare function scaleParts(parts: MaskPart[], scale: number): MaskPart[];
|
|
36
|
+
/** Flatten a region's geometry to plain rings. Rectangles become a 4-point ring;
|
|
37
|
+
* polygons keep their points + holes; multi-polygons expand to one part each. */
|
|
38
|
+
export declare function regionToParts(region: Region): MaskPart[];
|
|
39
|
+
/** A rasterized label mask plus the PNG bit depth it should be encoded at. */
|
|
40
|
+
export interface LabelMask {
|
|
41
|
+
data: Uint8Array | Uint16Array;
|
|
42
|
+
/** 8 for ≤255 distinct values, 16 for a multi-class mask with >255 regions. */
|
|
43
|
+
bitDepth: 8 | 16;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Rasterize regions (as plain parts) to a full image-size label mask (row-major,
|
|
47
|
+
* `W * H` samples; pixel `(x, y)` at `y * W + x`). Background is 0.
|
|
48
|
+
*
|
|
49
|
+
* - `'binary'` — every region pixel is 255 (standard 8-bit black/white mask:
|
|
50
|
+
* `> 0` = foreground; also directly viewable).
|
|
51
|
+
* - `'multiclass'` — each region gets a distinct 1-based id (its index + 1).
|
|
52
|
+
* Stays 8-bit for ≤255 regions; promotes to 16-bit beyond that. Ids are
|
|
53
|
+
* distinct up to the 16-bit ceiling (65535 regions); a selection larger than
|
|
54
|
+
* that exceeds the PNG's representable range and ids wrap (not a realistic
|
|
55
|
+
* hand-annotation case, but called out so the limit is explicit).
|
|
56
|
+
*
|
|
57
|
+
* Later regions paint over earlier ones where they overlap. `onProgress` is
|
|
58
|
+
* called after each region (1-based) so a caller can drive a progress bar.
|
|
59
|
+
* Returns null when nothing rasterises (no regions, zero/insane size).
|
|
60
|
+
*/
|
|
61
|
+
export declare function regionsToMask(regions: MaskPart[][], imageWidth: number, imageHeight: number, mode: 'binary' | 'multiclass', rasterize: RasterizeFn, onProgress?: (done: number, total: number) => void): LabelMask | null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory for the mask-export Web Worker, isolated in its own module so the
|
|
3
|
+
* `import.meta.url` reference (required by the bundler to locate the worker) is
|
|
4
|
+
* never pulled into the ts-jest CommonJS compile of the component — the unit
|
|
5
|
+
* tests `jest.mock` this module instead.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createMaskWorker(): Worker;
|