@jax-data-science/sci-image-visualizer 0.2.19 → 0.3.1
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/esm2022/index.mjs +2 -9
- package/esm2022/lib/contracts/instance-segmenter.contract.mjs +10 -10
- package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +10 -9
- package/esm2022/lib/contracts/toolbar-tool.contract.mjs +64 -0
- package/esm2022/lib/toolbar/model-info.mjs +32 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +82 -55
- package/esm2022/lib/visualizer.component.mjs +131 -138
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-iPNL2JyC.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs} +2 -2
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-iPNL2JyC.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map} +1 -1
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +710 -1565
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/index.d.ts +1 -6
- package/lib/contracts/instance-segmenter.contract.d.ts +7 -3
- package/lib/contracts/semantic-segmenter.contract.d.ts +7 -2
- package/lib/contracts/toolbar-tool.contract.d.ts +190 -0
- package/lib/toolbar/model-info.d.ts +17 -0
- package/lib/toolbar/toolbar.component.d.ts +53 -30
- package/lib/visualizer.component.d.ts +49 -58
- package/package.json +3 -5
- package/src/lib/assets/cell-detection.svg +37 -0
- package/src/lib/assets/cells.svg +1 -1
- package/src/lib/assets/sam-box-prompt.svg +61 -0
- package/src/lib/assets/sam-point-prompt.svg +91 -0
- package/esm2022/lib/toolbar/segmentation/retinal-layer-tool.service.mjs +0 -197
- package/esm2022/lib/toolbar/segmentation/retinal-model-registry.mjs +0 -119
- package/esm2022/lib/toolbar/segmentation/retinal-segmenter.service.mjs +0 -172
- package/esm2022/lib/toolbar/segmentation/yolo-detect-tool.service.mjs +0 -208
- package/esm2022/lib/toolbar/segmentation/yolo-model-registry.mjs +0 -129
- package/esm2022/lib/toolbar/segmentation/yolo-segmenter.service.mjs +0 -172
- package/lib/toolbar/segmentation/retinal-layer-tool.service.d.ts +0 -49
- package/lib/toolbar/segmentation/retinal-model-registry.d.ts +0 -71
- package/lib/toolbar/segmentation/retinal-segmenter.service.d.ts +0 -60
- package/lib/toolbar/segmentation/yolo-detect-tool.service.d.ts +0 -51
- package/lib/toolbar/segmentation/yolo-model-registry.d.ts +0 -59
- package/lib/toolbar/segmentation/yolo-segmenter.service.d.ts +0 -50
package/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from './lib/contracts/viz-config';
|
|
|
16
16
|
export * from './lib/contracts/image.contract';
|
|
17
17
|
export * from './lib/contracts/plot-type';
|
|
18
18
|
export * from './lib/contracts/toolbar-config';
|
|
19
|
+
export * from './lib/contracts/toolbar-tool.contract';
|
|
19
20
|
export * from './lib/contracts/capabilities.contract';
|
|
20
21
|
export * from './lib/contracts/region-overlay.contract';
|
|
21
22
|
export * from './lib/contracts/display-types';
|
|
@@ -23,17 +24,11 @@ export * from './lib/contracts/sam.contract';
|
|
|
23
24
|
export * from './lib/contracts/cell-segmenter.contract';
|
|
24
25
|
export { CellposeSegmenterService } from './lib/toolbar/segmentation/cellpose-segmenter.service';
|
|
25
26
|
export * from './lib/contracts/instance-segmenter.contract';
|
|
26
|
-
export { YoloSegmenterService } from './lib/toolbar/segmentation/yolo-segmenter.service';
|
|
27
|
-
export { YoloDetectToolService, YOLO_REGION_SOURCE } from './lib/toolbar/segmentation/yolo-detect-tool.service';
|
|
28
27
|
export * from './lib/contracts/semantic-segmenter.contract';
|
|
29
|
-
export { RetinalSegmenterService } from './lib/toolbar/segmentation/retinal-segmenter.service';
|
|
30
|
-
export { RetinalLayerToolService, RETINAL_REGION_SOURCE, } from './lib/toolbar/segmentation/retinal-layer-tool.service';
|
|
31
28
|
export { ProcessingImage } from './lib/processing/processing-image';
|
|
32
29
|
export { cropImage, CropImageOptions } from './lib/processing/image-crop';
|
|
33
30
|
export { ImageConverterService } from './lib/processing/image-converter.service';
|
|
34
31
|
export { SAM_MODELS, DEFAULT_SAM_MODEL_ID, getSamModel, isSamModelReady, setSamModelUrls, setDefaultSamModel, getDefaultSamModelId, } from './lib/toolbar/segmentation/sam-model-registry';
|
|
35
|
-
export { YOLO_MODELS, DEFAULT_YOLO_MODEL_ID, getYoloModel, isYoloModelReady, setYoloModelUrls, setDefaultYoloModel, getDefaultYoloModelId, YoloModelDef, } from './lib/toolbar/segmentation/yolo-model-registry';
|
|
36
|
-
export { RETINAL_MODELS, DEFAULT_RETINAL_MODEL_ID, getRetinalModel, isRetinalModelReady, readyRetinalModels, setRetinalModelUrls, setDefaultRetinalModel, getDefaultRetinalModelId, RetinalModelDef, } from './lib/toolbar/segmentation/retinal-model-registry';
|
|
37
32
|
export { setOrtWasmBase, getOrtWasmBase } from './lib/toolbar/segmentation/ort-runtime-config';
|
|
38
33
|
export * from './lib/models/region';
|
|
39
34
|
export * from './lib/models/class-preset';
|
|
@@ -128,8 +128,12 @@ export interface IInstanceSegmenter {
|
|
|
128
128
|
}, opts?: InstanceSegmentOptions, progress?: InstanceSegmentProgress): Promise<InstanceSegmentation>;
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
|
-
* DI token for the automatic instance segmenter.
|
|
132
|
-
*
|
|
133
|
-
*
|
|
131
|
+
* DI token for the automatic instance segmenter.
|
|
132
|
+
*
|
|
133
|
+
* **No default.** It used to fall back to an in-library YOLO service, and that
|
|
134
|
+
* factory was what pulled `yolo-segdetect-js` into every bundle of this package
|
|
135
|
+
* — which is not shippable while the checkpoints are closed. A host provides an
|
|
136
|
+
* implementation (see `@jax-data-science/sci-image-visualizer-jax-tools`), or
|
|
137
|
+
* nothing does and no tool needing it is registered.
|
|
134
138
|
*/
|
|
135
139
|
export declare const INSTANCE_SEGMENTER: InjectionToken<IInstanceSegmenter>;
|
|
@@ -99,7 +99,12 @@ export interface ISemanticSegmenter {
|
|
|
99
99
|
}, opts?: SemanticSegmentOptions, progress?: SemanticSegmentProgress): Promise<SemanticSegmentation>;
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
|
-
* DI token for the semantic segmenter
|
|
103
|
-
*
|
|
102
|
+
* DI token for the semantic segmenter.
|
|
103
|
+
*
|
|
104
|
+
* **No default.** It used to fall back to an in-library jax-ai-js service, and
|
|
105
|
+
* that factory was what pulled `jax-ai-js` into every bundle of this package —
|
|
106
|
+
* which is not shippable while the checkpoints are closed. A host provides an
|
|
107
|
+
* implementation (see `@jax-data-science/sci-image-visualizer-jax-tools`), or
|
|
108
|
+
* nothing does and no tool needing it is registered.
|
|
104
109
|
*/
|
|
105
110
|
export declare const SEMANTIC_SEGMENTER: InjectionToken<ISemanticSegmenter>;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a tool gets into the toolbar without this library knowing what it is.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS
|
|
5
|
+
* The YOLO detector and the retinal-layer segmenter used to be built in: their
|
|
6
|
+
* buttons were hardcoded in the toolbar template, their model registries named
|
|
7
|
+
* JAX checkpoints, and the `INSTANCE_SEGMENTER` / `SEMANTIC_SEGMENTER` tokens
|
|
8
|
+
* defaulted to in-library services that imported `yolo-segdetect-js` and
|
|
9
|
+
* `jax-ai-js`. Those default factories were the only thing pulling either
|
|
10
|
+
* package into the bundle — the contracts themselves were already clean.
|
|
11
|
+
*
|
|
12
|
+
* That arrangement cannot ship in an open library while the models are closed.
|
|
13
|
+
* So the tools move out, into a package that depends on this one, and arrive
|
|
14
|
+
* back through {@link TOOLBAR_TOOLS}. This library keeps the contracts, the
|
|
15
|
+
* chrome and the region plumbing; it no longer knows that YOLO exists.
|
|
16
|
+
*
|
|
17
|
+
* A host registers tools with a multi-provider:
|
|
18
|
+
*
|
|
19
|
+
* { provide: TOOLBAR_TOOLS, useExisting: YoloToolContribution, multi: true }
|
|
20
|
+
*
|
|
21
|
+
* Register nothing and the toolbar has no segmentation tools, the help dialog
|
|
22
|
+
* lists none, and neither model package is in the graph.
|
|
23
|
+
*
|
|
24
|
+
* WHY PARAMS ARE DECLARED, NOT RENDERED
|
|
25
|
+
* A contribution describes its parameters ({@link ToolParamSpec}) instead of
|
|
26
|
+
* supplying a component to draw them. The toolbar renders one generic dialog
|
|
27
|
+
* from that description. The alternative — each plugin shipping its own dialog
|
|
28
|
+
* component — would make every plugin depend on this library's exact PrimeNG
|
|
29
|
+
* version and styling internals to look like the rest of the toolbar, and the
|
|
30
|
+
* two dialogs that exist today are entirely numbers and one checkbox. A schema
|
|
31
|
+
* covers them, and it is the same shape jit-ui already uses for its pipeline
|
|
32
|
+
* step parameters, so the vocabulary is familiar.
|
|
33
|
+
*
|
|
34
|
+
* If a tool ever needs a control this cannot express, add a variant here rather
|
|
35
|
+
* than an escape hatch that returns a component — the moment one tool draws
|
|
36
|
+
* itself, the toolbar stops being able to lay tools out consistently.
|
|
37
|
+
*
|
|
38
|
+
* WHY AN EMPTY MODEL LIST HIDES THE TOOL
|
|
39
|
+
* {@link ToolbarToolContribution.models} returning `[]` removes the tool from
|
|
40
|
+
* the toolbar entirely. This preserves the behaviour the built-in tools already
|
|
41
|
+
* had (their buttons were `*ngIf`'d on a filtered registry), and it gives a host
|
|
42
|
+
* one switch for "the weights are not configured in this deployment" that does
|
|
43
|
+
* not require unregistering the provider.
|
|
44
|
+
*/
|
|
45
|
+
import { InjectionToken } from '@angular/core';
|
|
46
|
+
import type { Observable } from 'rxjs';
|
|
47
|
+
import type { IVisualizer } from './visualizer.contract';
|
|
48
|
+
/** A number field. Rendered as a stepper, matching the built-in dialogs. */
|
|
49
|
+
export interface NumberParamSpec {
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
type: 'number';
|
|
53
|
+
min?: number;
|
|
54
|
+
max?: number;
|
|
55
|
+
step?: number;
|
|
56
|
+
/** Decimal places to show. Omit for integers. */
|
|
57
|
+
fractionDigits?: number;
|
|
58
|
+
/** Hover help. Plain text; it is not rendered as HTML. */
|
|
59
|
+
tooltip?: string;
|
|
60
|
+
}
|
|
61
|
+
/** A checkbox. `label` sits beside it and may run to a sentence or two. */
|
|
62
|
+
export interface BooleanParamSpec {
|
|
63
|
+
id: string;
|
|
64
|
+
label: string;
|
|
65
|
+
type: 'boolean';
|
|
66
|
+
tooltip?: string;
|
|
67
|
+
}
|
|
68
|
+
/** A fixed set of choices. */
|
|
69
|
+
export interface SelectParamSpec {
|
|
70
|
+
id: string;
|
|
71
|
+
label: string;
|
|
72
|
+
type: 'select';
|
|
73
|
+
options: {
|
|
74
|
+
label: string;
|
|
75
|
+
value: string | number;
|
|
76
|
+
}[];
|
|
77
|
+
tooltip?: string;
|
|
78
|
+
}
|
|
79
|
+
export type ToolParamSpec = NumberParamSpec | BooleanParamSpec | SelectParamSpec;
|
|
80
|
+
/** One selectable checkpoint. */
|
|
81
|
+
export interface ToolModelOption {
|
|
82
|
+
id: string;
|
|
83
|
+
label: string;
|
|
84
|
+
/**
|
|
85
|
+
* Describes the checkpoint in the picker's hover tooltip — size, speed,
|
|
86
|
+
* training domain, accuracy. **Rendered as HTML**, so it is trusted content
|
|
87
|
+
* from the contributing package, never anything user-supplied.
|
|
88
|
+
*/
|
|
89
|
+
info?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Parameter values this checkpoint wants, merged over
|
|
92
|
+
* {@link ToolbarToolContribution.defaultParams} when it is selected. Defaults
|
|
93
|
+
* belong to the model rather than the tool — a detector trained on native 40x
|
|
94
|
+
* patches wants different tiling from one trained on thumbnails.
|
|
95
|
+
*/
|
|
96
|
+
defaults?: Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The `status$` / `busy$` / `progress$` surface the toolbar drives its sticky
|
|
100
|
+
* toast and progress bar from. `progress$` is a 0..1 fraction, or -1 for
|
|
101
|
+
* indeterminate.
|
|
102
|
+
*/
|
|
103
|
+
export interface ToolProgress {
|
|
104
|
+
status$: Observable<string>;
|
|
105
|
+
busy$: Observable<boolean>;
|
|
106
|
+
progress$: Observable<number>;
|
|
107
|
+
}
|
|
108
|
+
/** Toolbar icon: a published asset, or a PrimeIcon class name. */
|
|
109
|
+
export type ToolIcon = {
|
|
110
|
+
src: string;
|
|
111
|
+
pi?: never;
|
|
112
|
+
} | {
|
|
113
|
+
pi: string;
|
|
114
|
+
src?: never;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* A tool contributed to the toolbar.
|
|
118
|
+
*
|
|
119
|
+
* Implement it on an `@Injectable()` service in the contributing package, so it
|
|
120
|
+
* can inject its own segmenter and model registry — this library provides
|
|
121
|
+
* neither and must not learn to.
|
|
122
|
+
*/
|
|
123
|
+
export interface ToolbarToolContribution {
|
|
124
|
+
/** Stable identity, used for tracking and persisted preferences. */
|
|
125
|
+
id: string;
|
|
126
|
+
/** Short name, used in the toast and the help dialog heading. */
|
|
127
|
+
label: string;
|
|
128
|
+
icon: ToolIcon;
|
|
129
|
+
/** Tooltip on the run button — say what it does to the current view. */
|
|
130
|
+
runTooltip: string;
|
|
131
|
+
/** Tooltip on the checkpoint picker. Defaults to "Pick the model". */
|
|
132
|
+
modelTooltip?: string;
|
|
133
|
+
/** Tooltip on the parameters button. Defaults to "Parameters". */
|
|
134
|
+
paramsTooltip?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Where it sits among the segmentation tools. Lower sorts first; ties fall
|
|
137
|
+
* back to registration order. The built-in prompted tools occupy 0-99, so
|
|
138
|
+
* contributed tools should start at 100 to land after them.
|
|
139
|
+
*/
|
|
140
|
+
order?: number;
|
|
141
|
+
/** Selectable checkpoints. **Empty hides the tool.** */
|
|
142
|
+
models(): ToolModelOption[];
|
|
143
|
+
/** Which checkpoint runs when the user has not chosen. */
|
|
144
|
+
defaultModelId(): string;
|
|
145
|
+
/**
|
|
146
|
+
* Called when the user picks a checkpoint, before parameters are re-seeded.
|
|
147
|
+
* Use it to record the choice in the contributing package's own registry.
|
|
148
|
+
*/
|
|
149
|
+
onModelChange?(modelId: string): void;
|
|
150
|
+
/** Parameter fields, in dialog order. Empty hides the parameters button. */
|
|
151
|
+
params: ToolParamSpec[];
|
|
152
|
+
/**
|
|
153
|
+
* Baseline parameter values for a checkpoint. Called on first use and again
|
|
154
|
+
* on "Reset to model defaults", so it must be pure and must return every key
|
|
155
|
+
* the tool reads — a parameter the dialog shows but this omits renders as
|
|
156
|
+
* empty and reaches `run` as undefined.
|
|
157
|
+
*/
|
|
158
|
+
defaultParams(modelId: string): Record<string, unknown>;
|
|
159
|
+
/**
|
|
160
|
+
* Entry for the help dialog's tool list. `body` is rendered as HTML and may
|
|
161
|
+
* reference published assets (e.g. the tool's own icon).
|
|
162
|
+
*/
|
|
163
|
+
help?: {
|
|
164
|
+
body: string;
|
|
165
|
+
};
|
|
166
|
+
/** Progress surface for the toast. */
|
|
167
|
+
progress: ToolProgress;
|
|
168
|
+
/**
|
|
169
|
+
* Run over what is currently displayed, and write whatever it finds through
|
|
170
|
+
* `viz`. Resolves with the number of regions added.
|
|
171
|
+
*
|
|
172
|
+
* Everything the tool needs is on {@link IVisualizer}, which is part of this
|
|
173
|
+
* library's public surface — a contribution never reaches into internals.
|
|
174
|
+
* Region writes go through the same path the built-in tools use, so the
|
|
175
|
+
* index-based overlays and the Regions table stay consistent.
|
|
176
|
+
*/
|
|
177
|
+
run(viz: IVisualizer, params: Record<string, unknown>): Promise<number>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Multi-provider token for contributed tools.
|
|
181
|
+
*
|
|
182
|
+
* Deliberately has no `factory`: unregistered means no tools, which is what
|
|
183
|
+
* makes this library shippable without the closed model packages. Inject it
|
|
184
|
+
* `{ optional: true }` and treat null as empty.
|
|
185
|
+
*/
|
|
186
|
+
export declare const TOOLBAR_TOOLS: InjectionToken<readonly ToolbarToolContribution[]>;
|
|
187
|
+
/** Sort contributed tools into display order. */
|
|
188
|
+
export declare function sortToolContributions(tools: readonly ToolbarToolContribution[]): ToolbarToolContribution[];
|
|
189
|
+
/** The tools a toolbar should actually show: those with at least one model. */
|
|
190
|
+
export declare function visibleToolContributions(tools: readonly ToolbarToolContribution[] | null | undefined): ToolbarToolContribution[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-model descriptions for the info icon beside each item of the SAM / YOLO /
|
|
3
|
+
* retinal model dropdowns, keyed by registry model id.
|
|
4
|
+
*
|
|
5
|
+
* Lives in the toolbar layer rather than in the model registries for two
|
|
6
|
+
* reasons: the toolbar receives only `{ id, label }` from its host, so registry
|
|
7
|
+
* copy would have to be threaded through every host; and this text was already
|
|
8
|
+
* owned here — the SAM entries are the prose from the "About the SAM models"
|
|
9
|
+
* overlay panel this replaced, moved next to the model it describes.
|
|
10
|
+
*
|
|
11
|
+
* The quoted numbers come from the registries (`sizeMb`, `miou`, `patchSize`,
|
|
12
|
+
* per-model tiling `defaults`) — keep them in step when those change.
|
|
13
|
+
*
|
|
14
|
+
* Rendered with `[escape]="false"`, so `<b>` / `<br>` / entities are honoured.
|
|
15
|
+
* A model with no entry here simply gets no info icon.
|
|
16
|
+
*/
|
|
17
|
+
export declare const MODEL_INFO: Record<string, string>;
|
|
@@ -3,6 +3,7 @@ import { MenuItem } from 'primeng/api';
|
|
|
3
3
|
import { IImageInfo } from '../contracts/image.contract';
|
|
4
4
|
import { PlotType, PlotTypeDescriptor } from '../contracts/plot-type';
|
|
5
5
|
import { ToolbarToolVisibility } from '../contracts/toolbar-config';
|
|
6
|
+
import { ToolbarToolContribution } from '../contracts/toolbar-tool.contract';
|
|
6
7
|
import * as i0 from "@angular/core";
|
|
7
8
|
/**
|
|
8
9
|
* Presentational toolbar for the plotting viewport.
|
|
@@ -66,18 +67,14 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
66
67
|
label: string;
|
|
67
68
|
}[];
|
|
68
69
|
samModelId: string;
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
id: string;
|
|
78
|
-
label: string;
|
|
79
|
-
}[];
|
|
80
|
-
retinalModelId: string;
|
|
70
|
+
/**
|
|
71
|
+
* Tools contributed through {@link TOOLBAR_TOOLS}, already filtered to the
|
|
72
|
+
* ones with models and sorted. The host resolves them so it can own the
|
|
73
|
+
* per-tool parameter state; this component only draws them.
|
|
74
|
+
*/
|
|
75
|
+
contributedTools: ToolbarToolContribution[];
|
|
76
|
+
/** Active checkpoint per contributed tool, keyed by tool id. */
|
|
77
|
+
toolModelIds: Record<string, string>;
|
|
81
78
|
selectPlotType: EventEmitter<PlotType>;
|
|
82
79
|
/** Intensity (LINE) mode: add another colored line ROI + inset trace. */
|
|
83
80
|
addProfileLine: EventEmitter<void>;
|
|
@@ -117,18 +114,15 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
117
114
|
segmentRegions: EventEmitter<void>;
|
|
118
115
|
/** Run cellpose-SAM (auto) inside each drawn rectangle's crop (jit-ui#90). */
|
|
119
116
|
segmentCellpose: EventEmitter<void>;
|
|
120
|
-
/** Run
|
|
121
|
-
|
|
122
|
-
/** Pick
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
retinalModelChange: EventEmitter<string>;
|
|
130
|
-
/** Open the retinal-layer parameter dialog. */
|
|
131
|
-
openRetinalParams: EventEmitter<void>;
|
|
117
|
+
/** Run a contributed tool over the current view, by tool id. */
|
|
118
|
+
runTool: EventEmitter<string>;
|
|
119
|
+
/** Pick a contributed tool's checkpoint. */
|
|
120
|
+
toolModelChange: EventEmitter<{
|
|
121
|
+
toolId: string;
|
|
122
|
+
modelId: string;
|
|
123
|
+
}>;
|
|
124
|
+
/** Open a contributed tool's parameter dialog, by tool id. */
|
|
125
|
+
openToolParams: EventEmitter<string>;
|
|
132
126
|
/** SAM model picker (jit-ui#90 P1). */
|
|
133
127
|
samModelChange: EventEmitter<string>;
|
|
134
128
|
wandSensitivityChange: EventEmitter<number | undefined>;
|
|
@@ -155,15 +149,44 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
155
149
|
* Held as a stable array (rebuilt only when `samModels`/`samModelId` change),
|
|
156
150
|
* NOT a getter: a getter returns a fresh array with new `command` closures on
|
|
157
151
|
* every change-detection tick, which makes the bound `p-menu` overlay rebuild
|
|
158
|
-
* its DOM mid-interaction and swallow the click on a menu item.
|
|
152
|
+
* its DOM mid-interaction and swallow the click on a menu item.
|
|
153
|
+
*
|
|
154
|
+
* `tooltip` carries the model's description from {@link MODEL_INFO}; the
|
|
155
|
+
* menus' shared item template turns it into the hover info icon. p-menu's own
|
|
156
|
+
* rendering ignores the field (it reads `item.title`), so it is free to use. */
|
|
159
157
|
samMenuItems: MenuItem[];
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Model menus for the contributed tools, keyed by tool id. Same stable-array
|
|
160
|
+
* reasoning as {@link samMenuItems} — and it is why this is a map rebuilt in
|
|
161
|
+
* `ngOnChanges` rather than a method called from the template, which would
|
|
162
|
+
* hand `p-menu` a new array every tick.
|
|
163
|
+
*
|
|
164
|
+
* A contributed tool supplies its own per-model description, so unlike the
|
|
165
|
+
* SAM menu these do not consult {@link MODEL_INFO}: this library has no
|
|
166
|
+
* copy for checkpoints it does not know about.
|
|
167
|
+
*/
|
|
168
|
+
toolMenuItems: Record<string, MenuItem[]>;
|
|
164
169
|
/** Rebuild the SAM model menu when the model list or active selection
|
|
165
170
|
* changes (keeps the array reference stable across other CD ticks). */
|
|
166
171
|
ngOnChanges(changes: SimpleChanges): void;
|
|
172
|
+
/**
|
|
173
|
+
* Strip markup from a model description so it can be read aloud.
|
|
174
|
+
*
|
|
175
|
+
* The copy in MODEL_INFO and in a contribution's `ToolModelOption.info` is
|
|
176
|
+
* written for a visual tooltip rendered with `[escape]="false"`, so it carries
|
|
177
|
+
* `<b>` and `<br>`. Passed to `aria-label` verbatim a screen reader announces
|
|
178
|
+
* the tags, so they are removed and `<br>` becomes a sentence break. Entities
|
|
179
|
+
* used in that copy (` `, `×`, `&`) are decoded for the same
|
|
180
|
+
* reason.
|
|
181
|
+
*/
|
|
182
|
+
plainText(html: string): string;
|
|
183
|
+
/** Contributed tool names for the help dialog's prompted/no-prompt contrast,
|
|
184
|
+
* e.g. "YOLO, Retinal layers". Empty when nothing is registered, which is
|
|
185
|
+
* why the sentence that uses it is itself conditional. */
|
|
186
|
+
get contributedToolNames(): string;
|
|
187
|
+
/** Keeps each contributed tool's `p-menu` overlay alive across CD ticks —
|
|
188
|
+
* re-creating it mid-interaction swallows the click on a menu item. */
|
|
189
|
+
trackToolById(_index: number, tool: ToolbarToolContribution): string;
|
|
167
190
|
/** The Image plot type renders as a natively pan/zoom-able raster, so the
|
|
168
191
|
* generic zoom/pan tools are hidden. */
|
|
169
192
|
get isImageView(): boolean;
|
|
@@ -191,5 +214,5 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
191
214
|
get isIntensityCapable(): boolean;
|
|
192
215
|
showHelp(): void;
|
|
193
216
|
static ɵfac: i0.ɵɵFactoryDeclaration<ToolbarComponent, never>;
|
|
194
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ToolbarComponent, "plotting-toolbar", never, { "imageInfo": { "alias": "imageInfo"; "required": false; }; "plotTypeOptions": { "alias": "plotTypeOptions"; "required": false; }; "selectedPlotType": { "alias": "selectedPlotType"; "required": false; }; "isoRange": { "alias": "isoRange"; "required": false; }; "maxIndex": { "alias": "maxIndex"; "required": false; }; "zIndex": { "alias": "zIndex"; "required": false; }; "isHeatmap": { "alias": "isHeatmap"; "required": false; }; "activeDragMode": { "alias": "activeDragMode"; "required": false; }; "activeSurface3dMode": { "alias": "activeSurface3dMode"; "required": false; }; "axesVisible": { "alias": "axesVisible"; "required": false; }; "wireframeActive": { "alias": "wireframeActive"; "required": false; }; "resolutionScale": { "alias": "resolutionScale"; "required": false; }; "wandSensitivity": { "alias": "wandSensitivity"; "required": false; }; "brushSize": { "alias": "brushSize"; "required": false; }; "vertexEraserRadius": { "alias": "vertexEraserRadius"; "required": false; }; "canUndo": { "alias": "canUndo"; "required": false; }; "canRedo": { "alias": "canRedo"; "required": false; }; "stackOptions": { "alias": "stackOptions"; "required": false; }; "tools": { "alias": "tools"; "required": false; }; "imageSmoothingEnabled": { "alias": "imageSmoothingEnabled"; "required": false; }; "samModels": { "alias": "samModels"; "required": false; }; "samModelId": { "alias": "samModelId"; "required": false; }; "
|
|
217
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ToolbarComponent, "plotting-toolbar", never, { "imageInfo": { "alias": "imageInfo"; "required": false; }; "plotTypeOptions": { "alias": "plotTypeOptions"; "required": false; }; "selectedPlotType": { "alias": "selectedPlotType"; "required": false; }; "isoRange": { "alias": "isoRange"; "required": false; }; "maxIndex": { "alias": "maxIndex"; "required": false; }; "zIndex": { "alias": "zIndex"; "required": false; }; "isHeatmap": { "alias": "isHeatmap"; "required": false; }; "activeDragMode": { "alias": "activeDragMode"; "required": false; }; "activeSurface3dMode": { "alias": "activeSurface3dMode"; "required": false; }; "axesVisible": { "alias": "axesVisible"; "required": false; }; "wireframeActive": { "alias": "wireframeActive"; "required": false; }; "resolutionScale": { "alias": "resolutionScale"; "required": false; }; "wandSensitivity": { "alias": "wandSensitivity"; "required": false; }; "brushSize": { "alias": "brushSize"; "required": false; }; "vertexEraserRadius": { "alias": "vertexEraserRadius"; "required": false; }; "canUndo": { "alias": "canUndo"; "required": false; }; "canRedo": { "alias": "canRedo"; "required": false; }; "stackOptions": { "alias": "stackOptions"; "required": false; }; "tools": { "alias": "tools"; "required": false; }; "imageSmoothingEnabled": { "alias": "imageSmoothingEnabled"; "required": false; }; "samModels": { "alias": "samModels"; "required": false; }; "samModelId": { "alias": "samModelId"; "required": false; }; "contributedTools": { "alias": "contributedTools"; "required": false; }; "toolModelIds": { "alias": "toolModelIds"; "required": false; }; }, { "selectPlotType": "selectPlotType"; "addProfileLine": "addProfileLine"; "toggleImageSmoothing": "toggleImageSmoothing"; "isoRangeChange": "isoRangeChange"; "openChannelHistogram": "openChannelHistogram"; "openRegionEditor": "openRegionEditor"; "selectStackOption": "selectStackOption"; "zScrub": "zScrub"; "zSlide": "zSlide"; "zIndexInput": "zIndexInput"; "reloadAndPlot": "reloadAndPlot"; "downloadImage": "downloadImage"; "autoscaleImage": "autoscaleImage"; "toggleDragMode": "toggleDragMode"; "zoomIn": "zoomIn"; "zoomOut": "zoomOut"; "toggleSurface3dMode": "toggleSurface3dMode"; "resetSurfaceCamera": "resetSurfaceCamera"; "toggleAxes": "toggleAxes"; "toggleWireframe": "toggleWireframe"; "selectResolution": "selectResolution"; "deleteRegion": "deleteRegion"; "undoRegion": "undoRegion"; "redoRegion": "redoRegion"; "segmentRegions": "segmentRegions"; "segmentCellpose": "segmentCellpose"; "runTool": "runTool"; "toolModelChange": "toolModelChange"; "openToolParams": "openToolParams"; "samModelChange": "samModelChange"; "wandSensitivityChange": "wandSensitivityChange"; "brushSizeChange": "brushSizeChange"; "vertexEraserRadiusChange": "vertexEraserRadiusChange"; }, never, ["*"], false, never>;
|
|
195
218
|
}
|
|
@@ -12,10 +12,7 @@ import { IVisualizer } from './contracts/visualizer.contract';
|
|
|
12
12
|
import { SamToolService } from './toolbar/segmentation/sam-tool.service';
|
|
13
13
|
import { SamPointToolService } from './toolbar/segmentation/sam-point-tool.service';
|
|
14
14
|
import { CellSegmentToolService } from './toolbar/segmentation/cell-segment-tool.service';
|
|
15
|
-
import {
|
|
16
|
-
import type { IInstanceSegmenter, InstanceSegmentOptions } from './contracts/instance-segmenter.contract';
|
|
17
|
-
import { RetinalLayerToolService } from './toolbar/segmentation/retinal-layer-tool.service';
|
|
18
|
-
import type { ISemanticSegmenter, SemanticSegmentOptions } from './contracts/semantic-segmenter.contract';
|
|
15
|
+
import { NumberParamSpec, SelectParamSpec, ToolParamSpec, ToolbarToolContribution } from './contracts/toolbar-tool.contract';
|
|
19
16
|
import { ToolbarToolVisibility } from './contracts/toolbar-config';
|
|
20
17
|
import { VizConfig } from './contracts/viz-config';
|
|
21
18
|
import * as i0 from "@angular/core";
|
|
@@ -28,10 +25,6 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
28
25
|
private session;
|
|
29
26
|
private samTool;
|
|
30
27
|
private cellSegmentTool;
|
|
31
|
-
private yoloDetectTool;
|
|
32
|
-
private instanceSegmenter;
|
|
33
|
-
private semanticSegmenter;
|
|
34
|
-
private retinalLayerTool;
|
|
35
28
|
private samPointTool;
|
|
36
29
|
private regionOps;
|
|
37
30
|
private vizConfig?;
|
|
@@ -131,28 +124,22 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
131
124
|
label: string;
|
|
132
125
|
}[];
|
|
133
126
|
samModelId: string;
|
|
134
|
-
/**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
*
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
retinalModelId: string;
|
|
151
|
-
showRetinalParams: boolean;
|
|
152
|
-
retinalParams: SemanticSegmentOptions;
|
|
153
|
-
/** Download size of the active retinal model, surfaced in the dialog because
|
|
154
|
-
* ~590 MB is worth knowing before clicking Run rather than after. */
|
|
155
|
-
get retinalModelSizeMb(): number;
|
|
127
|
+
/**
|
|
128
|
+
* No-prompt tools registered through {@link TOOLBAR_TOOLS}, filtered to those
|
|
129
|
+
* with configured models and sorted. This library registers none — a host
|
|
130
|
+
* supplies them — so an open build has an empty array here and the toolbar
|
|
131
|
+
* and help dialog simply omit that group.
|
|
132
|
+
*/
|
|
133
|
+
contributedTools: ToolbarToolContribution[];
|
|
134
|
+
/** Active checkpoint per contributed tool. */
|
|
135
|
+
toolModelIds: Record<string, string>;
|
|
136
|
+
/**
|
|
137
|
+
* Parameter values per contributed tool, seeded from each tool's own defaults
|
|
138
|
+
* — which encode the scale and crowding its checkpoint was trained for.
|
|
139
|
+
*/
|
|
140
|
+
toolParams: Record<string, Record<string, unknown>>;
|
|
141
|
+
/** Which tool's parameter dialog is open, or null. */
|
|
142
|
+
openParamsToolId: string | null;
|
|
156
143
|
/** SAM download/segment toast state (bound by the `sam` p-toast template). */
|
|
157
144
|
samStatus: string;
|
|
158
145
|
samProgress: number;
|
|
@@ -263,7 +250,7 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
263
250
|
private wheelListener?;
|
|
264
251
|
/** Debounced z-slice scrubbing (see SliceScrubber — refactoring plan Step 7). */
|
|
265
252
|
private readonly scrubber;
|
|
266
|
-
constructor(state: ImageStatePort, plotService: IVisualizer, messageService: MessageService, ngZone: NgZone, cdr: ChangeDetectorRef, session: VisualizerStore, samTool: SamToolService, cellSegmentTool: CellSegmentToolService,
|
|
253
|
+
constructor(state: ImageStatePort, plotService: IVisualizer, messageService: MessageService, ngZone: NgZone, cdr: ChangeDetectorRef, session: VisualizerStore, samTool: SamToolService, cellSegmentTool: CellSegmentToolService, samPointTool: SamPointToolService, regionOps: RegionOpsService, vizConfig?: VizConfig | undefined, toolContributions?: readonly ToolbarToolContribution[]);
|
|
267
254
|
/**
|
|
268
255
|
* Plot types offered in the selector for the current image:
|
|
269
256
|
* - Outside **test mode**, only the curated default set (descriptors with a
|
|
@@ -411,37 +398,41 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
411
398
|
* (jit-ui#90). Each box is cropped (browser slide-crop) then run through the
|
|
412
399
|
* cellpose-js model; the same sticky `sam` toast + progress bar is reused. */
|
|
413
400
|
segmentCellpose(): Promise<void>;
|
|
414
|
-
/**
|
|
415
|
-
|
|
401
|
+
/**
|
|
402
|
+
* Parameters currently bound by the generic parameter dialog, for whichever
|
|
403
|
+
* tool is open. Seeded lazily: a tool's defaults are only asked for when the
|
|
404
|
+
* user first touches it, so registering a tool costs nothing until used.
|
|
405
|
+
*/
|
|
406
|
+
paramsFor(toolId: string): Record<string, unknown>;
|
|
407
|
+
/** Active checkpoint for a tool, falling back to the tool's own default. */
|
|
408
|
+
modelIdFor(tool: ToolbarToolContribution): string;
|
|
416
409
|
/** Switching checkpoint re-seeds the parameters, since the defaults belong to
|
|
417
410
|
* the model rather than to the tool. */
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
*
|
|
424
|
-
|
|
411
|
+
onToolModelChange(e: {
|
|
412
|
+
toolId: string;
|
|
413
|
+
modelId: string;
|
|
414
|
+
}): void;
|
|
415
|
+
/** A tool's defaults for a checkpoint, with that checkpoint's own overrides
|
|
416
|
+
* applied on top — per-model defaults beat per-tool ones. */
|
|
417
|
+
private seedParams;
|
|
425
418
|
/**
|
|
426
|
-
*
|
|
419
|
+
* Narrow a param spec for the template.
|
|
427
420
|
*
|
|
428
|
-
* `
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
* `downsamplingFactor` is 1 rather than YOLO's 5: these checkpoints were
|
|
433
|
-
* trained on native 40x patches, so the model wants full resolution and
|
|
434
|
-
* downsampling actively hurts.
|
|
421
|
+
* `*ngSwitchCase` does not narrow a discriminated union in Angular's template
|
|
422
|
+
* type checker the way a `switch` does in TypeScript, so the template asks for
|
|
423
|
+
* the variant it has already matched on.
|
|
435
424
|
*/
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
425
|
+
numberParam(p: ToolParamSpec): NumberParamSpec;
|
|
426
|
+
selectParam(p: ToolParamSpec): SelectParamSpec;
|
|
427
|
+
openToolParams(toolId: string): void;
|
|
428
|
+
/** The tool whose parameter dialog is open, for the generic dialog's header
|
|
429
|
+
* and field list. */
|
|
430
|
+
get openParamsTool(): ToolbarToolContribution | undefined;
|
|
431
|
+
resetToolParams(toolId: string): void;
|
|
432
|
+
/** Run a contributed tool over the current view. No prompt: these sweep the
|
|
433
|
+
* whole view rather than being pointed at something. Reuses the shared
|
|
434
|
+
* segmentation toast so progress reads the same as the SAM/cellpose tools. */
|
|
435
|
+
runTool(toolId: string): Promise<void>;
|
|
445
436
|
/** Shared driver for the box-prompt segment tools: wires the tool's status +
|
|
446
437
|
* download progress into the sticky `sam` toast, runs `op`, and reports the
|
|
447
438
|
* region count. Keeps the toast open until the run settles (bar hits 100%). */
|
|
@@ -485,6 +476,6 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
485
476
|
onSelectPlotType(type: PlotType): void;
|
|
486
477
|
/** Deactivate whatever tool is armed and clear every tool mode. */
|
|
487
478
|
private deactivateActiveTool;
|
|
488
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<VisualizerComponent, [null, null, null, null, null, null, null, null, null, null,
|
|
479
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<VisualizerComponent, [null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }]>;
|
|
489
480
|
static ɵcmp: i0.ɵɵComponentDeclaration<VisualizerComponent, "visualizer", never, { "toolbarTools": { "alias": "toolbarTools"; "required": false; }; "testMode": { "alias": "testMode"; "required": false; }; }, { "isStackEvent": "isStackEvent"; "isGrayscaleEvent": "isGrayscaleEvent"; }, never, ["*"], false, never>;
|
|
490
481
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jax-data-science/sci-image-visualizer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Browser-based scientific image visualization for Angular — gigapixel whole-slide (OpenSeadragon), 2D/3D (Plotly) and WebGPU (napari-js) rendering, with region/annotation editing and in-browser SAM segmentation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -34,14 +34,12 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"cellpose-js": "^0.
|
|
37
|
+
"cellpose-js": "^0.5.0",
|
|
38
38
|
"fast-png": "^6.4.0",
|
|
39
|
-
"jax-ai-js": "^0.2.0",
|
|
40
39
|
"napari-js": "^0.11.0",
|
|
41
40
|
"openseadragon": "^6.0.2",
|
|
42
41
|
"plotly.js-dist-min": "^3.0.1",
|
|
43
|
-
"tslib": "^2.3.0"
|
|
44
|
-
"yolo-segdetect-js": "^0.1.2"
|
|
42
|
+
"tslib": "^2.3.0"
|
|
45
43
|
},
|
|
46
44
|
"peerDependencies": {
|
|
47
45
|
"@angular/animations": "^17.3.0",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg
|
|
3
|
+
version="1.1"
|
|
4
|
+
viewBox="-5 -10 79.999863 79.999832"
|
|
5
|
+
id="svg2"
|
|
6
|
+
sodipodi:docname="cell-detection.svg"
|
|
7
|
+
width="79.999863"
|
|
8
|
+
height="79.999832"
|
|
9
|
+
inkscape:version="1.4.4 (dcaf3e7, 2026-05-05)"
|
|
10
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
11
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
|
14
|
+
<defs
|
|
15
|
+
id="defs2" />
|
|
16
|
+
<sodipodi:namedview
|
|
17
|
+
id="namedview2"
|
|
18
|
+
pagecolor="#ffffff"
|
|
19
|
+
bordercolor="#000000"
|
|
20
|
+
borderopacity="0.25"
|
|
21
|
+
inkscape:showpageshadow="2"
|
|
22
|
+
inkscape:pageopacity="0.0"
|
|
23
|
+
inkscape:pagecheckerboard="0"
|
|
24
|
+
inkscape:deskcolor="#d1d1d1"
|
|
25
|
+
inkscape:zoom="7.4740741"
|
|
26
|
+
inkscape:cx="40.004955"
|
|
27
|
+
inkscape:cy="47.56442"
|
|
28
|
+
inkscape:window-width="1024"
|
|
29
|
+
inkscape:window-height="1186"
|
|
30
|
+
inkscape:window-x="0"
|
|
31
|
+
inkscape:window-y="30"
|
|
32
|
+
inkscape:window-maximized="0"
|
|
33
|
+
inkscape:current-layer="svg2" />
|
|
34
|
+
<path
|
|
35
|
+
d="m 3.74574,-1.255 c 11.664,-11.66 30.57,-11.66 42.234,0 9.9609,9.9648 11.41,25.215 4.3516,36.719 l 5.4609,5.4609 c 2.1211,0.02344 4.2422,0.73828 6.0039,2.1602 l 9.4961,7.6562 c 4.6094,3.7148 4.9766,10.609 0.78906,14.797 l -1.543,1.543 c -4.1875,4.1875 -11.082,3.8203 -14.797,-0.78906 l -7.6562,-9.4961 c -1.4219,-1.7617 -2.1367,-3.8867 -2.1602,-6.0078 l -5.4609,-5.457 c -11.504,7.0586 -26.754,5.6094 -36.719,-4.3516 -11.66,-11.664 -11.66,-30.57 0,-42.234 z m 55.539,47.453 c -2.2852,-1.8477 -5.5977,-1.668 -7.6758,0.41016 -2.0781,2.07816 -2.2578,5.3867 -0.41016,7.6758 l 7.6562,9.4961 c 2.2227,2.7578 6.3477,2.9766 8.8555,0.47266 l 1.543,-1.543 c 2.5039,-2.5078 2.2852,-6.6328 -0.47266,-8.8555 z m -11.305,-7.4297 c -0.625,0.76172 -1.2891,1.5 -2,2.2109 -0.71094,0.70703 -1.4492,1.375 -2.2109,1.9961 l 3.2344,3.2344 c 0.45312,-0.875 1.043,-1.6992 1.7773,-2.4297 0.73047,-0.73438 1.5547,-1.3242 2.4336,-1.7773 z m -4.8281,-37.195 c -10.102,-10.098 -26.477,-10.098 -36.578,0 -10.098,10.102 -10.098,26.477 0,36.574 10.102,10.102 26.477,10.102 36.578,0 10.098,-10.098 10.098,-26.473 0,-36.574 z M 25.56964,-0.79 c 0.98828,-0.49609 2.1875,-0.09375 2.6836,0.89453 0.42578,0.85156 0.18359,1.8594 -0.52344,2.4375 0.92188,0.15234 1.8164,0.375 2.6797,0.66797 1.1055,-1.4023 2.7461,-2.3125 4.6016,-2.3086 1.1055,0 2,0.89844 1.9961,2 0,1.1055 -0.89453,2 -2,2 -0.24219,0 -0.50391,0.0625 -0.76172,0.19141 0.65625,0.4375 1.2812,0.91406 1.8672,1.4336 1.8555,-1.0742 4.1367,-1.2266 6.0391,-0.125 0.95312,0.55469 1.2773,1.7773 0.72656,2.7344 -0.55469,0.95312 -1.7812,1.2812 -2.7344,0.72656 -0.32812,-0.19141 -0.76953,-0.27344 -1.2578,-0.17578 0.42969,0.63672 0.82031,1.3086 1.1602,2.0039 2.0352,0.25 3.8711,1.4062 4.7656,3.3164 0.46484,1.0039 0.03516,2.1914 -0.96484,2.6602 -0.74609,0.34766 -1.6016,0.19531 -2.1797,-0.32031 0.05859,0.56641 0.08984,1.1406 0.08984,1.7227 0,0.26563 -0.0078,0.52734 -0.01953,0.78906 1.4531,1.1133 2.4023,2.7891 2.4023,4.6875 -0.0039,1.1016 -0.89844,1.9961 -2.0039,1.9961 -0.71875,0 -1.3477,-0.37891 -1.6992,-0.94922 -0.27734,0.66016 -0.59766,1.2969 -0.95703,1.9102 1.1133,1.0859 1.8125,2.5469 1.8086,4.1758 0,1.1016 -0.89844,1.9961 -2,1.9961 -1.1055,0 -2,-0.89844 -2,-2.0039 0,-0.29297 -0.08984,-0.61328 -0.28125,-0.91797 -0.64062,0.66016 -1.332,1.2656 -2.0742,1.8086 0.71094,0.96484 1.1367,2.1289 1.1367,3.3945 -0.0039,1.1055 -0.89844,2 -2.0039,2 -1.1055,-0.0039 -2,-0.89844 -1.9961,-2.0039 0,-0.45312 -0.21094,-0.96875 -0.69141,-1.3906 -1.3281,0.54688 -2.7422,0.92578 -4.2148,1.1133 -0.29297,1.082 -0.88281,2.0742 -1.7656,2.8398 -0.83984,0.71875 -2.1016,0.625 -2.8203,-0.21094 -0.67578,-0.78125 -0.63672,-1.9297 0.05078,-2.668 -1.25,-0.17969 -2.457,-0.5 -3.6016,-0.94141 -0.6875,1.3008 -1.8516,2.3047 -3.332,2.7891 -1.0508,0.34375 -2.1797,-0.22656 -2.5234,-1.2773 -0.3437,-1.05074 0.22656,-2.1797 1.2773,-2.5234 0.47266,-0.15625 0.83594,-0.45703 1.0469,-0.86719 -0.88281,-0.61719 -1.707,-1.3203 -2.457,-2.0938 -0.76172,0.96094 -1.8008,1.6992 -3.043,2.1055 -1.0508,0.34375 -2.1797,-0.23047 -2.5234,-1.2812 -0.34375,-1.0469 0.23047,-2.1797 1.2773,-2.5234 0.88672,-0.28906 1.4844,-0.97656 1.6367,-1.8906 -0.38672,-0.70312 -0.72266,-1.4336 -1.0078,-2.1953 -0.76562,0.33203 -1.6133,0.49219 -2.5,0.4375 -1.1016,-0.06641 -1.9414,-1.0156 -1.875,-2.1172 0.06641,-1.1016 1.0156,-1.9414 2.1172,-1.875 0.53906,0.03125 0.99609,-0.19531 1.2852,-0.64844 -0.05469,-0.54688 -0.08203,-1.1016 -0.08203,-1.6641 0,-0.56641 0.02734,-1.1289 0.08203,-1.6797 -1.293,-0.44531 -2.4258,-1.3086 -3.1406,-2.5547 -0.55078,-0.95703 -0.21875,-2.1797 0.73828,-2.7305 0.95703,-0.55078 2.1797,-0.21875 2.7305,0.73828 0.125,0.21875 0.31641,0.41797 0.56641,0.57422 0.27344,-0.76953 0.60547,-1.5117 0.98438,-2.2227 -1.3125,-1.4922 -1.918,-3.5078 -1.3828,-5.4844 0.28516,-1.0664 1.3828,-1.6992 2.4492,-1.4141 1.0664,0.28906 1.6992,1.3867 1.4102,2.4531 -0.07422,0.27344 -0.07031,0.59766 0.02734,0.92969 0.75391,-0.8125 1.5859,-1.5508 2.4844,-2.1992 -0.38281,-1.9414 0.10156,-3.9766 1.543,-5.4219 0.78125,-0.77734 2.0469,-0.77734 2.8281,0.0039 0.7812,0.781246 0.78125,2.0469 0,2.8281 -0.12109,0.11719 -0.22266,0.26562 -0.30469,0.4375 1.1016,-0.40234 2.2617,-0.6875 3.457,-0.85156 0.42188,-1.3945 1.3945,-2.5781 2.7734,-3.2656 z m -0.15625,26.992 c 0,-0.14453 0.01563,-0.28516 0.04688,-0.42188 -0.13672,0.02734 -0.27734,0.04297 -0.42188,0.04297 -0.20312,0 -0.37109,0.16797 -0.37109,0.37891 0,0.21094 0.16797,0.37891 0.37109,0.37891 0.20313,0 0.375,-0.16797 0.375,-0.37891 z m -6.1719,-8.5586 c 0,-0.21484 -0.17188,-0.37891 -0.375,-0.37891 -0.20313,0 -0.37109,0.16406 -0.37109,0.37891 0,0.21094 0.16797,0.375 0.37109,0.375 0.20312,0 0.375,-0.16406 0.375,-0.375 z m 7.8828,-7.1211 c 2.0938,-1.2109 4.7695,-0.48828 5.9766,1.6055 1.207,2.0898 0.49219,4.7656 -1.6016,5.9766 -0.95703,0.55469 -2.1797,0.22656 -2.7305,-0.73047 -0.55469,-0.95703 -0.22656,-2.1797 0.73047,-2.7305 0.17578,-0.10547 0.24219,-0.33594 0.13672,-0.51953 -0.10547,-0.17969 -0.33203,-0.23828 -0.50781,-0.13672 -0.95703,0.55078 -2.1797,0.22656 -2.7344,-0.73047 -0.55078,-0.95703 -0.22656,-2.1797 0.73047,-2.7344 z m 2.2891,15.68 c 0,2.4141 -1.957,4.3789 -4.375,4.3789 -2.418,0 -4.3711,-1.9648 -4.3711,-4.3789 0,-2.4141 1.9531,-4.3789 4.3711,-4.3789 1.1055,0 2,0.89844 2,2 0,0.14453 -0.01562,0.28906 -0.04687,0.42188 0.13672,-0.02734 0.27734,-0.04297 0.42187,-0.04297 1.1055,0 2,0.89453 2,2 z m -17.09,-7.1328 c 0,7.0391 5.6953,12.742 12.715,12.742 7.0195,0 12.719,-5.7031 12.719,-12.742 0,-7.0391 -5.6992,-12.742 -12.719,-12.742 -7.0195,0 -12.715,5.7031 -12.715,12.742 z m 10.918,-1.4258 c 0,2.4141 -1.957,4.375 -4.375,4.375 -2.418,0 -4.3711,-1.9609 -4.3711,-4.375 0,-2.4141 1.9531,-4.3789 4.3711,-4.3789 2.418,0 4.375,1.9648 4.375,4.3789 z"
|
|
36
|
+
id="path1" />
|
|
37
|
+
</svg>
|