@niivue/nv-ohif 0.1.0-rc.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/README.md +210 -0
- package/dist/index.js +2952 -0
- package/dist/types/NiivueViewport.d.ts +14 -0
- package/dist/types/classifyDisplaySet.d.ts +7 -0
- package/dist/types/commands.d.ts +202 -0
- package/dist/types/dicomToNiivue.d.ts +21 -0
- package/dist/types/dicomWadoRs.d.ts +22 -0
- package/dist/types/displaySetToNiivue.d.ts +7 -0
- package/dist/types/getNiivueViewportModule.d.ts +4 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/niivueRegistry.d.ts +60 -0
- package/dist/types/ohif-types.d.ts +97 -0
- package/dist/types/reconstructP10.d.ts +35 -0
- package/dist/types/sopClassHandler.d.ts +16 -0
- package/dist/types/toolBridge.d.ts +16 -0
- package/dist/types/toolbar.d.ts +38 -0
- package/dist/types/volumeAnnotationOverlay.d.ts +20 -0
- package/dist/types/wsiSlideView.d.ts +30 -0
- package/dist/types/wsiThumbnail.d.ts +40 -0
- package/dist/types/wsiTileSource.d.ts +68 -0
- package/package.json +52 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OhifViewportProps } from './ohif-types';
|
|
2
|
+
/**
|
|
3
|
+
* The NiiVue viewport React component OHIF hangs a display set in. It routes each
|
|
4
|
+
* display set to the right NiiVue load path (see {@link classifyDisplaySet}):
|
|
5
|
+
* - a NIfTI/volume URL loads directly,
|
|
6
|
+
* - a volumetric DICOM series is fetched + converted with dcm2niix, then loaded,
|
|
7
|
+
* - whole-slide (SM) series render with NVSlide (JPEG / TILED_FULL; JPEG 2000 and
|
|
8
|
+
* TILED_SPARSE are declined with a note),
|
|
9
|
+
* - anything else shows an explanatory note.
|
|
10
|
+
*
|
|
11
|
+
* NiiVue's core is framework-agnostic, so this owns a plain <canvas> + a `NiiVue`
|
|
12
|
+
* instance directly (React 18) rather than depending on `@niivue/nvreact` (React 19).
|
|
13
|
+
*/
|
|
14
|
+
export declare function NiivueViewport(props: OhifViewportProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { OhifDisplaySet } from './ohif-types';
|
|
2
|
+
export type NiivueLoadKind = 'nifti' | 'dicom-volume' | 'wsi' | 'unsupported';
|
|
3
|
+
/**
|
|
4
|
+
* Decide which NiiVue load path a display set takes. Pure; drives the viewport's
|
|
5
|
+
* branching and is unit-tested against representative display-set shapes.
|
|
6
|
+
*/
|
|
7
|
+
export declare function classifyDisplaySet(ds: OhifDisplaySet): NiivueLoadKind;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { type AnnotationScreenShape, type VectorAnnotation } from '@niivue/niivue';
|
|
2
|
+
import { type NiivueViewportEntry } from './niivueRegistry';
|
|
3
|
+
import type { OhifDisplaySet, OhifExtensionParams } from './ohif-types';
|
|
4
|
+
export declare const NIIVUE_SLICE_TYPES: Record<string, number>;
|
|
5
|
+
export declare const NIIVUE_CLIP_PLANES: Record<string, [number, number, number]>;
|
|
6
|
+
export declare const OVERLAY_COLORMAP = "warm";
|
|
7
|
+
export declare const OVERLAY_OPACITY = 0.5;
|
|
8
|
+
export declare const NIIVUE_COLORMAPS: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
label: string;
|
|
11
|
+
}>;
|
|
12
|
+
export interface WindowLevelPreset {
|
|
13
|
+
id?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
window: string | number;
|
|
16
|
+
level: string | number;
|
|
17
|
+
}
|
|
18
|
+
export declare const FALLBACK_WL_PRESETS: Record<string, WindowLevelPreset[]>;
|
|
19
|
+
export declare function findOverlayCandidate(entry: Pick<NiivueViewportEntry, 'displaySets' | 'overlayUIDs'>, activeDisplaySets: ReadonlyArray<OhifDisplaySet>): OhifDisplaySet | undefined;
|
|
20
|
+
export declare function flashStatus(entry: NiivueViewportEntry, message: string, ms?: number): void;
|
|
21
|
+
export declare function baseModality(entry: Pick<NiivueViewportEntry, 'displaySets'>): string | undefined;
|
|
22
|
+
/** OHIF's window/level presets (customization first, built-in fallback). */
|
|
23
|
+
export declare function windowLevelPresets(servicesManager: OhifExtensionParams['servicesManager']): Record<string, WindowLevelPreset[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a preset for the base modality, by id then index (OHIF's own
|
|
26
|
+
* fallback order). Returns the [calMin, calMax] window it maps to.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveWindowLevel(presets: Record<string, WindowLevelPreset[]>, modality: string | undefined, presetId: string | undefined, presetIndex: number | undefined): [number, number] | undefined;
|
|
29
|
+
interface NiivueLike {
|
|
30
|
+
volumes: ReadonlyArray<{
|
|
31
|
+
calMin?: number;
|
|
32
|
+
calMax?: number;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
/** Read the base volume's window/level ({ window: width, level: center }). */
|
|
36
|
+
export declare function readBaseWindowLevel(nv: NiivueLike): {
|
|
37
|
+
window: number;
|
|
38
|
+
level: number;
|
|
39
|
+
} | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Assign the default viewport label before reflecting a new annotation to OHIF.
|
|
42
|
+
* The label is tool-aware ('Arrow #N' / 'Bidirectional #N' / 'ROI #N') and the
|
|
43
|
+
* number is one past the highest existing "<prefix> #N", so a label is never
|
|
44
|
+
* reused after a deletion. Returns true if it assigned text (so the caller can
|
|
45
|
+
* redraw).
|
|
46
|
+
*
|
|
47
|
+
* A measured line (Length) gets NO default text: its ruler already draws the mm
|
|
48
|
+
* reading, and a free-text label would cross / obscure the ruler.
|
|
49
|
+
*/
|
|
50
|
+
export declare function applyDefaultAnnotationText(annotation: VectorAnnotation, annotations: readonly VectorAnnotation[]): boolean;
|
|
51
|
+
export declare function reflectNiivueAnnotation(viewportId: string, servicesManager: OhifExtensionParams['servicesManager'], annotation: VectorAnnotation, existingUid?: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Push an OHIF measurement's label (edited in the panel) back onto the NiiVue
|
|
54
|
+
* annotation it reflects, so the free text shows on the viewport. No-op if the
|
|
55
|
+
* uid is not one of ours.
|
|
56
|
+
*/
|
|
57
|
+
export declare function applyOhifLabelToAnnotation(measurementUid: string, label: string): void;
|
|
58
|
+
/** Navigate the owning NiiVue viewport to a reflected OHIF measurement. */
|
|
59
|
+
export declare function jumpToNiivueMeasurement(measurementUid: string, servicesManager: OhifExtensionParams['servicesManager']): void;
|
|
60
|
+
/**
|
|
61
|
+
* Delete the NiiVue annotation backing an OHIF measurement removed from the
|
|
62
|
+
* panel, then re-render. No-op when the uid is not one of ours, or when WE are
|
|
63
|
+
* the ones removing it (removeNiivueAnnotation -> measurementService.remove
|
|
64
|
+
* echoes MEASUREMENT_REMOVED synchronously; removingUids marks those so we do
|
|
65
|
+
* not double-remove).
|
|
66
|
+
*/
|
|
67
|
+
export declare function applyOhifRemoveToAnnotation(measurementUid: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* The overlay shape provider: `nv.annotationScreenShapes` minus any annotation
|
|
70
|
+
* hidden via its OHIF measurement's visibility toggle. Core still projects every
|
|
71
|
+
* annotation each frame; we drop the hidden ones just before the overlay draws.
|
|
72
|
+
*/
|
|
73
|
+
export declare function visibleAnnotationScreenShapes(viewportId: string, shapes: readonly AnnotationScreenShape[]): readonly AnnotationScreenShape[];
|
|
74
|
+
/**
|
|
75
|
+
* Show or hide the NiiVue annotation backing an OHIF measurement whose panel
|
|
76
|
+
* visibility (eye icon) was toggled, then re-render. No-op when the uid is not
|
|
77
|
+
* one of ours or the state already matches.
|
|
78
|
+
*/
|
|
79
|
+
export declare function applyOhifVisibilityToAnnotation(measurementUid: string, isVisible: boolean): void;
|
|
80
|
+
/**
|
|
81
|
+
* Subscribe once per MeasurementService to OHIF events handled by NiiVue:
|
|
82
|
+
* label edits are pushed to annotation text, and panel jumps navigate to the
|
|
83
|
+
* owning annotation. The historical function name remains part of the API.
|
|
84
|
+
*/
|
|
85
|
+
export declare function subscribeOhifLabelSync(servicesManager: OhifExtensionParams['servicesManager']): (() => void) | undefined;
|
|
86
|
+
/** Remove one reflected annotation's OHIF panel row (annotationRemoved). */
|
|
87
|
+
/**
|
|
88
|
+
* Returns true when the row is gone (removed, or there was nothing / no uid to
|
|
89
|
+
* remove, or the host has no remove so recovery is impossible). Returns FALSE only
|
|
90
|
+
* when an available remove() THREW: the bookkeeping is preserved so the caller can
|
|
91
|
+
* retry on a later reconcile instead of orphaning the OHIF row (round-5 F1).
|
|
92
|
+
*/
|
|
93
|
+
export declare function removeNiivueAnnotation(viewportId: string, servicesManager: OhifExtensionParams['servicesManager'], annotationId: string): boolean;
|
|
94
|
+
/** Remove every reflected row for a viewport (annotation clear / series swap). */
|
|
95
|
+
export declare function clearNiivueAnnotations(viewportId: string, servicesManager: OhifExtensionParams['servicesManager']): void;
|
|
96
|
+
export declare function reconcileNiivueAnnotations(viewportId: string, servicesManager: OhifExtensionParams['servicesManager']): void;
|
|
97
|
+
export declare function syncNiivueWindowLevelToOhif(viewportId: string, servicesManager: OhifExtensionParams['servicesManager'], commandsManager: OhifExtensionParams['commandsManager']): {
|
|
98
|
+
window: number;
|
|
99
|
+
level: number;
|
|
100
|
+
} | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* getCommandsModule: OHIF commands operating on the active NiiVue viewport.
|
|
103
|
+
* Toolbar buttons (see toolbar.ts) reference these by name; they are also
|
|
104
|
+
* runnable from any OHIF surface via `commandsManager.runCommand(...)`.
|
|
105
|
+
*/
|
|
106
|
+
export declare function getNiivueCommandsModule({ servicesManager, commandsManager, }: OhifExtensionParams): {
|
|
107
|
+
actions: {
|
|
108
|
+
/** Switch the view: axial / coronal / sagittal / multiplanar / render. */
|
|
109
|
+
niivueSetSliceType: ({ sliceType }?: {
|
|
110
|
+
sliceType?: string;
|
|
111
|
+
}) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Activate the ruler (length) tool. Routes through OHIF's `setToolActiveToolbar`
|
|
114
|
+
* so OHIF's active-tool state and NiiVue agree: the tool bridge in
|
|
115
|
+
* NiivueViewport maps the active `Length` tool onto NiiVue's `measureLine`
|
|
116
|
+
* annotation (the same system as the ROI tools). Setting the annotation tool
|
|
117
|
+
* directly would be reset by that bridge the next time OHIF's active tool
|
|
118
|
+
* (e.g. WindowLevel) re-applies. On release the completed line annotation is
|
|
119
|
+
* reflected into OHIF's measurement panel (see the annotationAdded
|
|
120
|
+
* subscription in NiivueViewport). Falls back to enabling NiiVue's measureLine
|
|
121
|
+
* annotation directly when no commandsManager is available.
|
|
122
|
+
*/
|
|
123
|
+
niivueSetMeasurementMode: () => void;
|
|
124
|
+
/** Reset camera, pan, zoom, and crosshair to their defaults. */
|
|
125
|
+
niivueResetView: () => void;
|
|
126
|
+
/** Download the visible NiiVue volume or NVSlide canvas as a PNG. */
|
|
127
|
+
niivueSaveBitmap: () => Promise<void>;
|
|
128
|
+
/** Set (or clear, plane: 'none') the 3D render clip plane. */
|
|
129
|
+
niivueSetClipPlane: ({ plane }?: {
|
|
130
|
+
plane?: string;
|
|
131
|
+
}) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Toggle a colormapped overlay: with overlays loaded, remove them;
|
|
134
|
+
* otherwise load the study's next loadable series on top of the base
|
|
135
|
+
* (fetch + dcm2niix conversion for DICOM).
|
|
136
|
+
*/
|
|
137
|
+
niivueToggleOverlay: () => Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Apply a window/level (width + center) to the base volume as NiiVue
|
|
140
|
+
* calMin/calMax. Bridges OHIF's W/L model onto NiiVue's calibration range.
|
|
141
|
+
*/
|
|
142
|
+
niivueSetWindowLevel: ({ window, level, }?: {
|
|
143
|
+
window?: number;
|
|
144
|
+
level?: number;
|
|
145
|
+
}) => void;
|
|
146
|
+
/**
|
|
147
|
+
* Apply one of OHIF's modality window/level presets (resolved from the
|
|
148
|
+
* `cornerstone.windowLevelPresets` customization, keyed by the base series'
|
|
149
|
+
* modality) to the base volume.
|
|
150
|
+
*/
|
|
151
|
+
niivueSetWindowLevelPreset: ({ presetId, presetIndex, }?: {
|
|
152
|
+
presetId?: string;
|
|
153
|
+
presetIndex?: number;
|
|
154
|
+
}) => void;
|
|
155
|
+
/** Recompute the base volume's robust (2-98%) auto window. */
|
|
156
|
+
niivueAutoWindowLevel: () => void;
|
|
157
|
+
/** Set the base volume's colormap (e.g. gray / hot / viridis). */
|
|
158
|
+
niivueSetColormap: ({ colormap }?: {
|
|
159
|
+
colormap?: string;
|
|
160
|
+
}) => void;
|
|
161
|
+
/** Toggle the colormap legend (colorbar) on the viewport. */
|
|
162
|
+
niivueToggleColorbar: () => void;
|
|
163
|
+
/** Toggle nearest-neighbor vs smooth (linear) volume interpolation. */
|
|
164
|
+
niivueToggleInterpolation: () => void;
|
|
165
|
+
/**
|
|
166
|
+
* Toggle the crosshair on/off. Overrides OHIF's cornerstone Crosshairs
|
|
167
|
+
* button on a NiiVue viewport. `crosshairWidth = 0` hides the 2D crosshair
|
|
168
|
+
* (its width is the marker radius); `is3DCrosshairVisible` follows for the
|
|
169
|
+
* 3D render tile. Neither setter redraws on its own, so drawScene() here.
|
|
170
|
+
*/
|
|
171
|
+
niivueToggleCrosshair: () => void;
|
|
172
|
+
};
|
|
173
|
+
definitions: {
|
|
174
|
+
niivueSetSliceType: ({ sliceType }?: {
|
|
175
|
+
sliceType?: string;
|
|
176
|
+
}) => void;
|
|
177
|
+
niivueSetMeasurementMode: () => void;
|
|
178
|
+
niivueResetView: () => void;
|
|
179
|
+
niivueSaveBitmap: () => Promise<void>;
|
|
180
|
+
niivueSetClipPlane: ({ plane }?: {
|
|
181
|
+
plane?: string;
|
|
182
|
+
}) => void;
|
|
183
|
+
niivueToggleOverlay: () => Promise<void>;
|
|
184
|
+
niivueSetWindowLevel: ({ window, level, }?: {
|
|
185
|
+
window?: number;
|
|
186
|
+
level?: number;
|
|
187
|
+
}) => void;
|
|
188
|
+
niivueSetWindowLevelPreset: ({ presetId, presetIndex, }?: {
|
|
189
|
+
presetId?: string;
|
|
190
|
+
presetIndex?: number;
|
|
191
|
+
}) => void;
|
|
192
|
+
niivueAutoWindowLevel: () => void;
|
|
193
|
+
niivueSetColormap: ({ colormap }?: {
|
|
194
|
+
colormap?: string;
|
|
195
|
+
}) => void;
|
|
196
|
+
niivueToggleColorbar: () => void;
|
|
197
|
+
niivueToggleInterpolation: () => void;
|
|
198
|
+
niivueToggleCrosshair: () => void;
|
|
199
|
+
};
|
|
200
|
+
defaultContext: string;
|
|
201
|
+
};
|
|
202
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OhifDisplaySet } from './ohif-types';
|
|
2
|
+
export interface DicomConvertOptions {
|
|
3
|
+
/** Extra request headers (e.g. an Authorization header from OHIF's auth service). */
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
/** Called as instances are fetched, then once more when conversion starts. */
|
|
6
|
+
onProgress?: (phase: 'fetching' | 'converting', loaded: number, total: number) => void;
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
/** Max concurrent instance fetches. Default 6. */
|
|
9
|
+
concurrency?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Fetch every instance of a DICOMweb display set as a reconstructed DICOM P10 File.
|
|
13
|
+
* Fetches run with bounded concurrency; progress is reported per instance.
|
|
14
|
+
*/
|
|
15
|
+
export declare function fetchDicomInstanceFiles(ds: OhifDisplaySet, options?: DicomConvertOptions): Promise<File[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Convert a DICOMweb display set to a single NIfTI File via dcm2niix. Returns the
|
|
18
|
+
* primary NIfTI output (largest `.nii`/`.nii.gz`), or null if nothing converted.
|
|
19
|
+
* dcm2niix is dynamically imported so its WASM only loads on a DICOM series.
|
|
20
|
+
*/
|
|
21
|
+
export declare function convertDisplaySetToNifti(ds: OhifDisplaySet, options?: DicomConvertOptions): Promise<File | null>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn a cornerstone `wadors:`/`dicomweb:` frame imageId into the WADO-RS
|
|
3
|
+
* retrieve-instance URL. Returns null if the id is not an http(s) DICOMweb
|
|
4
|
+
* instance reference.
|
|
5
|
+
*/
|
|
6
|
+
export declare function retrieveInstanceUrlFromImageId(imageId: string): string | null;
|
|
7
|
+
/** Extract the boundary token from a multipart/related Content-Type header. */
|
|
8
|
+
export declare function multipartBoundary(contentType: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Recover the boundary from a multipart body's opening delimiter line
|
|
11
|
+
* (`--<boundary>\r\n`). The browser `fetch` API commonly exposes the response
|
|
12
|
+
* Content-Type as bare `multipart/related` with the `boundary` parameter
|
|
13
|
+
* stripped, so we fall back to reading it off the body.
|
|
14
|
+
*/
|
|
15
|
+
export declare function boundaryFromBody(bytes: Uint8Array): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Split a multipart/related body into its part bodies (raw bytes, headers
|
|
18
|
+
* stripped). If the response is actually single-part `application/dicom`
|
|
19
|
+
* (some servers ignore the multipart Accept), the whole body is returned as
|
|
20
|
+
* one part.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseMultipartRelated(body: ArrayBuffer | Uint8Array, contentType: string): Uint8Array[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ImageFromUrlOptions } from '@niivue/niivue';
|
|
2
|
+
import type { OhifDisplaySet } from './ohif-types';
|
|
3
|
+
/**
|
|
4
|
+
* Extract a NiiVue load spec from an OHIF display set, or null if this display set is
|
|
5
|
+
* not a Phase-1 (NIfTI/volume-URL) case.
|
|
6
|
+
*/
|
|
7
|
+
export declare function displaySetToNiivue(displaySet: OhifDisplaySet): ImageFromUrlOptions | null;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OhifViewportModuleEntry } from './ohif-types';
|
|
2
|
+
export declare const NIIVUE_VIEWPORT_NAME = "niivue";
|
|
3
|
+
/** getViewportModule: register the NiiVue viewport component with OHIF. */
|
|
4
|
+
export declare function getNiivueViewportModule(): OhifViewportModuleEntry[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getNiivueCommandsModule, NIIVUE_CLIP_PLANES, NIIVUE_COLORMAPS, NIIVUE_SLICE_TYPES } from './commands';
|
|
2
|
+
import { displaySetToNiivue } from './displaySetToNiivue';
|
|
3
|
+
import { getNiivueViewportModule, NIIVUE_VIEWPORT_NAME } from './getNiivueViewportModule';
|
|
4
|
+
import { NiivueViewport } from './NiivueViewport';
|
|
5
|
+
import type { OhifDisplaySet, OhifExtension, OhifSopClassHandlerEntry, OhifToolbarButton, OhifViewportModuleEntry, OhifViewportProps } from './ohif-types';
|
|
6
|
+
import { getNiivueSopClassHandlerModule, NIIVUE_SOP_CLASS_HANDLER_NAME } from './sopClassHandler';
|
|
7
|
+
import { getNiivueToolbarModule, NIIVUE_CLIP_SECTION, NIIVUE_COLORBAR_BUTTON, NIIVUE_COLORMAP_SECTION, NIIVUE_INTERPOLATION_BUTTON, NIIVUE_OVERLAY_BUTTON, NIIVUE_RESET_BUTTON, NIIVUE_TOOLBAR_BUTTONS, NIIVUE_TOOLBAR_SECTIONS, NIIVUE_VIEWS_SECTION, NIIVUE_WL_SECTION, niivueToolbarCustomization } from './toolbar';
|
|
8
|
+
export declare const NIIVUE_OHIF_EXTENSION_ID = "@niivue/nv-ohif";
|
|
9
|
+
declare const niivueOhifExtension: OhifExtension;
|
|
10
|
+
export default niivueOhifExtension;
|
|
11
|
+
export type { OhifDisplaySet, OhifExtension, OhifSopClassHandlerEntry, OhifToolbarButton, OhifViewportModuleEntry, OhifViewportProps, };
|
|
12
|
+
export { displaySetToNiivue, getNiivueCommandsModule, getNiivueSopClassHandlerModule, getNiivueToolbarModule, getNiivueViewportModule, NIIVUE_CLIP_PLANES, NIIVUE_CLIP_SECTION, NIIVUE_COLORBAR_BUTTON, NIIVUE_COLORMAP_SECTION, NIIVUE_COLORMAPS, NIIVUE_INTERPOLATION_BUTTON, NIIVUE_OVERLAY_BUTTON, NIIVUE_RESET_BUTTON, NIIVUE_SLICE_TYPES, NIIVUE_SOP_CLASS_HANDLER_NAME, NIIVUE_TOOLBAR_BUTTONS, NIIVUE_TOOLBAR_SECTIONS, NIIVUE_VIEWPORT_NAME, NIIVUE_VIEWS_SECTION, NIIVUE_WL_SECTION, NiivueViewport, niivueToolbarCustomization, };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type NiiVue from '@niivue/niivue';
|
|
2
|
+
import type { OhifDisplaySet, OhifServicesManager } from './ohif-types';
|
|
3
|
+
import type { WsiSlideView } from './wsiSlideView';
|
|
4
|
+
/**
|
|
5
|
+
* Per-viewport state shared between the React viewport and the OHIF
|
|
6
|
+
* commands / toolbar evaluators (which live outside React). The viewport
|
|
7
|
+
* registers on attach and keeps `displaySets` / `setStatus` current; commands
|
|
8
|
+
* mutate the overlay/clip state they own.
|
|
9
|
+
*/
|
|
10
|
+
export interface NiivueViewportEntry {
|
|
11
|
+
viewportId: string;
|
|
12
|
+
nv: NiiVue;
|
|
13
|
+
/** Display sets currently hung in the viewport (the base load). */
|
|
14
|
+
displaySets: ReadonlyArray<OhifDisplaySet>;
|
|
15
|
+
/** displaySetInstanceUIDs loaded as overlays (niivueToggleOverlay). */
|
|
16
|
+
overlayUIDs: string[];
|
|
17
|
+
/** Guard against concurrent overlay loads. */
|
|
18
|
+
overlayLoading: boolean;
|
|
19
|
+
/** Current clip plane preset name ('none' when off). See commands.ts. */
|
|
20
|
+
clipPlane: string;
|
|
21
|
+
/**
|
|
22
|
+
* Last known base-volume window/level ({ window: width, level: center }).
|
|
23
|
+
* Tracks both directions: forward commands set it; the viewport's
|
|
24
|
+
* pointer-release observer updates it from a manual contrast drag and pushes
|
|
25
|
+
* the change to OHIF (see commands.ts syncNiivueWindowLevelToOhif).
|
|
26
|
+
*/
|
|
27
|
+
windowLevel?: {
|
|
28
|
+
window: number;
|
|
29
|
+
level: number;
|
|
30
|
+
};
|
|
31
|
+
/** Visible NVSlide view when this viewport is showing a whole-slide series. */
|
|
32
|
+
slideView?: WsiSlideView;
|
|
33
|
+
/** Viewport-provided sink so commands can surface progress text (null = clear). */
|
|
34
|
+
setStatus?: (message: string | null) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function registerNiivue(viewportId: string, nv: NiiVue): void;
|
|
37
|
+
export declare function unregisterNiivue(viewportId: string): void;
|
|
38
|
+
/** Merge viewport-owned fields into an entry (no-op when not registered). */
|
|
39
|
+
export declare function updateNiivueViewport(viewportId: string, patch: Partial<Pick<NiivueViewportEntry, 'displaySets' | 'setStatus' | 'slideView' | 'windowLevel' | 'overlayUIDs' | 'overlayLoading'>>): void;
|
|
40
|
+
export declare function getNiivueEntry(viewportId: string | undefined): NiivueViewportEntry | undefined;
|
|
41
|
+
export declare function ohifServices(servicesManager: OhifServicesManager | undefined): Record<string, unknown> | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* The entry for a viewport id, falling back to the sole registered entry
|
|
44
|
+
* (covers layouts where a non-NiiVue viewport holds focus next to a single
|
|
45
|
+
* NiiVue viewport).
|
|
46
|
+
*/
|
|
47
|
+
export declare function getNiivueEntryForViewport(viewportId: string | undefined): NiivueViewportEntry | undefined;
|
|
48
|
+
/** The instance for a viewport id (same fallback as the entry lookup). */
|
|
49
|
+
export declare function getNiivueForViewport(viewportId: string | undefined): NiiVue | undefined;
|
|
50
|
+
/** The entry a toolbar command should act on: the active viewport's. */
|
|
51
|
+
export declare function getActiveNiivueEntry(servicesManager: OhifServicesManager | undefined): NiivueViewportEntry | undefined;
|
|
52
|
+
/** The NiiVue instance a toolbar command should act on: the active viewport's. */
|
|
53
|
+
export declare function getActiveNiivue(servicesManager: OhifServicesManager | undefined): NiiVue | undefined;
|
|
54
|
+
export declare function refreshToolbar(servicesManager: OhifServicesManager | undefined, viewportId: string): void;
|
|
55
|
+
interface CommandsManagerLike {
|
|
56
|
+
runCommand?: (name: string, options?: Record<string, unknown>) => unknown;
|
|
57
|
+
}
|
|
58
|
+
export declare function ohifCommandsManager(commandsManager: CommandsManagerLike | undefined): CommandsManagerLike | undefined;
|
|
59
|
+
export declare function authHeaders(servicesManager: OhifServicesManager | undefined): Record<string, string>;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export interface OhifDisplaySet {
|
|
2
|
+
displaySetInstanceUID?: string;
|
|
3
|
+
SeriesInstanceUID?: string;
|
|
4
|
+
SeriesDescription?: string;
|
|
5
|
+
Modality?: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
instances?: ReadonlyArray<Record<string, unknown>>;
|
|
8
|
+
imageIds?: ReadonlyArray<string>;
|
|
9
|
+
getThumbnailSrc?: (options?: {
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}) => Promise<string | null>;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface OhifServicesManager {
|
|
15
|
+
services: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface OhifExtensionManager {
|
|
18
|
+
getModuleEntry: (id: string) => unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface OhifCommandsManager {
|
|
21
|
+
runCommand: (name: string, options?: Record<string, unknown>) => unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface OhifViewportProps {
|
|
24
|
+
displaySets: ReadonlyArray<OhifDisplaySet>;
|
|
25
|
+
viewportId: string;
|
|
26
|
+
viewportOptions?: {
|
|
27
|
+
orientation?: string;
|
|
28
|
+
viewportType?: string;
|
|
29
|
+
};
|
|
30
|
+
servicesManager?: OhifServicesManager;
|
|
31
|
+
extensionManager?: OhifExtensionManager;
|
|
32
|
+
commandsManager?: OhifCommandsManager;
|
|
33
|
+
children?: unknown;
|
|
34
|
+
}
|
|
35
|
+
export interface OhifViewportModuleEntry {
|
|
36
|
+
name: string;
|
|
37
|
+
component: (props: OhifViewportProps) => unknown;
|
|
38
|
+
}
|
|
39
|
+
export interface OhifSopClassHandlerEntry {
|
|
40
|
+
name: string;
|
|
41
|
+
sopClassUids: string[];
|
|
42
|
+
getDisplaySetsFromSeries: (instances: ReadonlyArray<Record<string, unknown>>) => ReadonlyArray<OhifDisplaySet>;
|
|
43
|
+
}
|
|
44
|
+
export interface OhifExtensionParams {
|
|
45
|
+
servicesManager?: OhifServicesManager;
|
|
46
|
+
extensionManager?: OhifExtensionManager;
|
|
47
|
+
commandsManager?: OhifCommandsManager;
|
|
48
|
+
}
|
|
49
|
+
export interface OhifToolbarButtonCommand {
|
|
50
|
+
commandName: string;
|
|
51
|
+
commandOptions?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
export interface OhifToolbarButton {
|
|
54
|
+
id: string;
|
|
55
|
+
uiType: string;
|
|
56
|
+
props: {
|
|
57
|
+
icon?: string;
|
|
58
|
+
label?: string;
|
|
59
|
+
tooltip?: string;
|
|
60
|
+
buttonSection?: boolean;
|
|
61
|
+
commands?: string | OhifToolbarButtonCommand | OhifToolbarButtonCommand[];
|
|
62
|
+
evaluate?: string | Record<string, unknown>;
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export interface OhifToolbarEvaluation {
|
|
67
|
+
disabled?: boolean;
|
|
68
|
+
disabledText?: string;
|
|
69
|
+
isActive?: boolean;
|
|
70
|
+
className?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface OhifToolbarModuleEntry {
|
|
73
|
+
name: string;
|
|
74
|
+
evaluate?: (state: {
|
|
75
|
+
viewportId?: string;
|
|
76
|
+
button?: OhifToolbarButton;
|
|
77
|
+
[key: string]: unknown;
|
|
78
|
+
}) => OhifToolbarEvaluation | undefined;
|
|
79
|
+
}
|
|
80
|
+
export interface OhifCommandsModule {
|
|
81
|
+
actions: Record<string, (...args: never[]) => unknown>;
|
|
82
|
+
definitions: Record<string, (...args: never[]) => unknown>;
|
|
83
|
+
defaultContext?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface OhifCustomizationModuleEntry {
|
|
86
|
+
name: string;
|
|
87
|
+
value: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
export interface OhifExtension {
|
|
90
|
+
id: string;
|
|
91
|
+
version?: string;
|
|
92
|
+
getViewportModule: (context: OhifExtensionParams) => OhifViewportModuleEntry[];
|
|
93
|
+
getSopClassHandlerModule?: (context: OhifExtensionParams) => OhifSopClassHandlerEntry[];
|
|
94
|
+
getCommandsModule?: (context: OhifExtensionParams) => OhifCommandsModule;
|
|
95
|
+
getToolbarModule?: (context: OhifExtensionParams) => OhifToolbarModuleEntry[];
|
|
96
|
+
getCustomizationModule?: (context: OhifExtensionParams) => OhifCustomizationModuleEntry[];
|
|
97
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
interface JsonElement {
|
|
2
|
+
vr?: string;
|
|
3
|
+
Value?: unknown[];
|
|
4
|
+
BulkDataURI?: string;
|
|
5
|
+
InlineBinary?: string;
|
|
6
|
+
}
|
|
7
|
+
type JsonDataset = Record<string, JsonElement>;
|
|
8
|
+
/** Frames pixel URL (absolute) from a cornerstone `wadors:` imageId. */
|
|
9
|
+
export declare function framesUrlFromImageId(imageId: string): string | null;
|
|
10
|
+
/** Series `/metadata` URL derived from an instance frames URL. */
|
|
11
|
+
export declare function seriesMetadataUrlFromFramesUrl(framesUrl: string): string | null;
|
|
12
|
+
/** SOP Instance UID embedded in a frames/instance URL. */
|
|
13
|
+
export declare function sopFromFramesUrl(framesUrl: string): string | null;
|
|
14
|
+
export declare function assemblePart10(DicomDict: DcmjsDicomDictCtor, metadata: JsonDataset, pixelBytes: Uint8Array, transferSyntaxUID?: string): ArrayBuffer;
|
|
15
|
+
export interface DcmjsDicomDict {
|
|
16
|
+
meta: JsonDataset;
|
|
17
|
+
dict: JsonDataset;
|
|
18
|
+
write(options?: {
|
|
19
|
+
allowInvalidVRLength?: boolean;
|
|
20
|
+
fragmentMultiframe?: boolean;
|
|
21
|
+
}): ArrayBuffer;
|
|
22
|
+
}
|
|
23
|
+
export type DcmjsDicomDictCtor = new (meta: JsonDataset) => DcmjsDicomDict;
|
|
24
|
+
export interface ReconstructOptions {
|
|
25
|
+
headers?: Record<string, string>;
|
|
26
|
+
onProgress?: (loaded: number, total: number) => void;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
concurrency?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Reconstruct P10 `File`s for every instance identified by `framesUrls`, using one
|
|
32
|
+
* shared series-metadata fetch plus a per-instance pixel fetch.
|
|
33
|
+
*/
|
|
34
|
+
export declare function reconstructInstanceFiles(framesUrls: string[], options?: ReconstructOptions): Promise<File[]>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OhifSopClassHandlerEntry } from './ohif-types';
|
|
2
|
+
export declare const NIIVUE_SOP_CLASS_HANDLER_NAME = "niivue-wsi";
|
|
3
|
+
export declare const NIIVUE_SOP_CLASS_HANDLER_ID = "@niivue/nv-ohif.sopClassHandlerModule.niivue-wsi";
|
|
4
|
+
/**
|
|
5
|
+
* Build the NiiVue display set for a whole-slide (SM) series. Unlike OHIF's
|
|
6
|
+
* built-in `DicomMicroscopySopClassHandler`, this does NOT set
|
|
7
|
+
* `viewportType: WHOLE_SLIDE` — that field forces OHIF's own microscopy
|
|
8
|
+
* viewport and would override the mode's viewport routing. Omitting it lets the
|
|
9
|
+
* series land in the NiiVue viewport, which renders it with NVSlide.
|
|
10
|
+
*
|
|
11
|
+
* A mode that wants NiiVue to own whole-slide imaging registers this handler in
|
|
12
|
+
* its `sopClassHandlers` (and `displaySetsToDisplay`) INSTEAD of OHIF's
|
|
13
|
+
* `wsiSopClassHandler`; otherwise both handlers claim the SM SOP class and two
|
|
14
|
+
* competing display sets are produced.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getNiivueSopClassHandlerModule(): OhifSopClassHandlerEntry[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type AnnotationTool } from '@niivue/niivue';
|
|
2
|
+
/**
|
|
3
|
+
* Map an OHIF measurement tool to a NiiVue vector-annotation tool. Returns null
|
|
4
|
+
* for tools that are not annotation-backed (handled as drag modes instead).
|
|
5
|
+
* Setting `nv.annotationTool` to the result + `nv.annotationIsEnabled = true`
|
|
6
|
+
* makes a left-drag on a 2D slice draw the shape; the measure* variants also
|
|
7
|
+
* compute ROI stats (area/mean) and fire `annotationAdded` with them.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ohifToolToAnnotationTool(tool: string | undefined): AnnotationTool | null;
|
|
10
|
+
/**
|
|
11
|
+
* OHIF measurement tools NiiVue cannot back yet (no core primitive). Activating
|
|
12
|
+
* one shows a brief 'not supported' status and keeps safe crosshair navigation.
|
|
13
|
+
*/
|
|
14
|
+
export declare const UNSUPPORTED_MEASUREMENT_TOOLS: ReadonlySet<string>;
|
|
15
|
+
/** Map an OHIF primary tool name to NiiVue's matching left-drag mode. */
|
|
16
|
+
export declare function ohifToolToDragMode(tool: string | undefined): number;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { OhifToolbarButton, OhifToolbarModuleEntry } from './ohif-types';
|
|
2
|
+
export declare const NIIVUE_VIEWS_SECTION = "NiivueViews";
|
|
3
|
+
export declare const NIIVUE_CLIP_SECTION = "NiivueClip";
|
|
4
|
+
export declare const NIIVUE_WL_SECTION = "NiivueWindowLevel";
|
|
5
|
+
export declare const NIIVUE_COLORMAP_SECTION = "NiivueColormap";
|
|
6
|
+
export declare const NIIVUE_RESET_BUTTON = "NiivueReset";
|
|
7
|
+
export declare const NIIVUE_OVERLAY_BUTTON = "NiivueOverlay";
|
|
8
|
+
export declare const NIIVUE_COLORBAR_BUTTON = "NiivueColorbar";
|
|
9
|
+
export declare const NIIVUE_INTERPOLATION_BUTTON = "NiivueInterpolation";
|
|
10
|
+
export declare const NIIVUE_RULER_BUTTON = "NiivueRuler";
|
|
11
|
+
export declare const NIIVUE_CAPTURE_BUTTON = "NiivueCapture";
|
|
12
|
+
export declare const NIIVUE_CROSSHAIR_BUTTON = "NiivueCrosshair";
|
|
13
|
+
/**
|
|
14
|
+
* Toolbar button definitions: a "Views" dropdown (axial / coronal / sagittal /
|
|
15
|
+
* multiplanar / 3D render), a clip-plane dropdown, a window/level dropdown
|
|
16
|
+
* (auto + OHIF's modality presets), an overlay toggle, and a reset-view button,
|
|
17
|
+
* all running the commands in commands.ts. Registered with the toolbar service
|
|
18
|
+
* via the `niivue.toolbarButtons` customization (see below) or directly.
|
|
19
|
+
*/
|
|
20
|
+
export declare const NIIVUE_TOOLBAR_BUTTONS: OhifToolbarButton[];
|
|
21
|
+
export declare const NIIVUE_TOOLBAR_SECTIONS: Record<string, string[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Customization pack (auto-registered at default scope via the extension's
|
|
24
|
+
* customizationModule). A mode composes it by reference:
|
|
25
|
+
* toolbarButtons: [..., { $reference: 'niivue.toolbarButtons' }]
|
|
26
|
+
* toolbarSections: [..., { $reference: 'niivue.toolbarSections' },
|
|
27
|
+
* { primary: [...ids, 'NiivueViews', 'NiivueClip',
|
|
28
|
+
* 'NiivueOverlay', 'NiivueReset'] }]
|
|
29
|
+
*/
|
|
30
|
+
export declare const niivueToolbarCustomization: {
|
|
31
|
+
'niivue.toolbarButtons': OhifToolbarButton[];
|
|
32
|
+
'niivue.toolbarSections': Record<string, string[]>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* getToolbarModule: evaluators the buttons above reference. OHIF calls these
|
|
36
|
+
* against the active viewport to derive enabled/active state.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getNiivueToolbarModule(): OhifToolbarModuleEntry[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AnnotationScreenShape, UIKitOverlayFrame, UIKitOverlayRenderer } from '@niivue/niivue';
|
|
2
|
+
import { type UIKitFont } from '@niivue/uikit';
|
|
3
|
+
/**
|
|
4
|
+
* Draws NiiVue's vector annotations (ellipse / rectangle / circle / line / arrow
|
|
5
|
+
* ROIs) as @niivue/uikit shapes through the controller's overlay hook, so the
|
|
6
|
+
* ROIs render in UIKit instead of NiiVue's built-in on-canvas annotation drawing
|
|
7
|
+
* (which the caller disables with `nv.isAnnotationDrawn = false`). Reads the
|
|
8
|
+
* current screen projection from `nv.annotationScreenShapes` each frame so the
|
|
9
|
+
* shapes track pan / zoom / slice changes, rebuilding geometry only when the
|
|
10
|
+
* projection or dpr changes.
|
|
11
|
+
*/
|
|
12
|
+
export declare class VolumeAnnotationOverlay implements UIKitOverlayRenderer {
|
|
13
|
+
private readonly getShapes;
|
|
14
|
+
private readonly lines;
|
|
15
|
+
private readonly labels;
|
|
16
|
+
private lastSig;
|
|
17
|
+
constructor(font: UIKitFont, getShapes: () => readonly AnnotationScreenShape[]);
|
|
18
|
+
drawOverlay(frame: UIKitOverlayFrame): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { NVSlide } from '@niivue/niivue';
|
|
2
|
+
export interface WsiSlideViewOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Called when the measurement (ruler) changes: a formatted length string
|
|
5
|
+
* while measuring, or null when the ruler is cleared. Lets the host reflect
|
|
6
|
+
* the reading into its own status UI.
|
|
7
|
+
*/
|
|
8
|
+
onMeasure?: (text: string | null) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface WsiSlideView {
|
|
11
|
+
setTool(tool: string | undefined): void;
|
|
12
|
+
resetView(): void;
|
|
13
|
+
saveBitmap(filename?: string): Promise<void>;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Mount a standalone NVSlide deep-zoom view on a canvas: WebGL2 + SlideRenderer,
|
|
18
|
+
* an on-demand render loop (redraw only when tiles stream in or the user
|
|
19
|
+
* interacts), and pointer pan / wheel zoom. This is independent of NiiVue's
|
|
20
|
+
* volume renderer; the caller uses it for DICOM-WSI (SM) display sets.
|
|
21
|
+
*
|
|
22
|
+
* When the active tool is `Length`, clicks place a two-point ruler (a UIKit
|
|
23
|
+
* overlay drawn over the slide) that measures in real physical units recovered
|
|
24
|
+
* from the slide's DICOM pixel spacing. Endpoints are stored in slide
|
|
25
|
+
* coordinates so the ruler tracks the tissue through pan and zoom.
|
|
26
|
+
*
|
|
27
|
+
* Returns a handle whose `dispose()` tears down every listener, the RAF, and
|
|
28
|
+
* the GL resources.
|
|
29
|
+
*/
|
|
30
|
+
export declare function mountWsiSlideView(canvas: HTMLCanvasElement, slide: NVSlide, options?: WsiSlideViewOptions): WsiSlideView;
|