@fideus-labs/fidnii 0.1.0 → 0.3.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/dist/BufferManager.d.ts +37 -4
- package/dist/BufferManager.d.ts.map +1 -1
- package/dist/BufferManager.js +69 -24
- package/dist/BufferManager.js.map +1 -1
- package/dist/ClipPlanes.d.ts.map +1 -1
- package/dist/ClipPlanes.js +11 -15
- package/dist/ClipPlanes.js.map +1 -1
- package/dist/OMEZarrNVImage.d.ts +59 -3
- package/dist/OMEZarrNVImage.d.ts.map +1 -1
- package/dist/OMEZarrNVImage.js +267 -68
- package/dist/OMEZarrNVImage.js.map +1 -1
- package/dist/RegionCoalescer.d.ts +16 -0
- package/dist/RegionCoalescer.d.ts.map +1 -1
- package/dist/RegionCoalescer.js +43 -6
- package/dist/RegionCoalescer.js.map +1 -1
- package/dist/ResolutionSelector.d.ts +14 -2
- package/dist/ResolutionSelector.d.ts.map +1 -1
- package/dist/ResolutionSelector.js +28 -20
- package/dist/ResolutionSelector.js.map +1 -1
- package/dist/ViewportBounds.d.ts.map +1 -1
- package/dist/ViewportBounds.js +7 -5
- package/dist/ViewportBounds.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +13 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -16
- package/dist/index.js.map +1 -1
- package/dist/normalize.d.ts +50 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +95 -0
- package/dist/normalize.js.map +1 -0
- package/dist/types.d.ts +66 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +66 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/affine.d.ts +1 -1
- package/dist/utils/affine.d.ts.map +1 -1
- package/dist/utils/affine.js.map +1 -1
- package/dist/utils/coordinates.d.ts +1 -1
- package/dist/utils/coordinates.d.ts.map +1 -1
- package/dist/utils/coordinates.js +20 -26
- package/dist/utils/coordinates.js.map +1 -1
- package/package.json +3 -4
- package/src/BufferManager.ts +114 -53
- package/src/ClipPlanes.ts +131 -130
- package/src/OMEZarrNVImage.ts +863 -618
- package/src/RegionCoalescer.ts +92 -51
- package/src/ResolutionSelector.ts +94 -79
- package/src/ViewportBounds.ts +120 -118
- package/src/events.ts +36 -35
- package/src/index.ts +70 -69
- package/src/normalize.ts +119 -0
- package/src/types.ts +189 -94
- package/src/utils/affine.ts +65 -65
- package/src/utils/coordinates.ts +82 -80
package/src/types.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
-
import type { Multiscales } from "@fideus-labs/ngff-zarr"
|
|
5
|
-
import type { Niivue, NVImage } from "@niivue/niivue"
|
|
6
|
-
import { SLICE_TYPE } from "@niivue/niivue"
|
|
7
|
-
|
|
8
|
-
import type {
|
|
4
|
+
import type { Multiscales, NgffImage } from "@fideus-labs/ngff-zarr"
|
|
5
|
+
import type { Niivue, NVImage } from "@niivue/niivue"
|
|
6
|
+
import { SLICE_TYPE } from "@niivue/niivue"
|
|
7
|
+
|
|
8
|
+
import type { BufferManager } from "./BufferManager.js"
|
|
9
|
+
import type { PopulateTrigger } from "./events.js"
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* A single clip plane defined by a point and normal vector.
|
|
@@ -14,9 +15,9 @@ import type { PopulateTrigger } from "./events.js";
|
|
|
14
15
|
*/
|
|
15
16
|
export interface ClipPlane {
|
|
16
17
|
/** A point on the plane (center of volume projected to plane) [x, y, z] in world coordinates */
|
|
17
|
-
point: [number, number, number]
|
|
18
|
+
point: [number, number, number]
|
|
18
19
|
/** Unit normal vector pointing toward visible region [x, y, z] */
|
|
19
|
-
normal: [number, number, number]
|
|
20
|
+
normal: [number, number, number]
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -24,14 +25,14 @@ export interface ClipPlane {
|
|
|
24
25
|
* Each plane clips away the half-space on the negative side of its normal.
|
|
25
26
|
* Maximum 6 planes (NiiVue limit). Empty array = full volume visible.
|
|
26
27
|
*/
|
|
27
|
-
export type ClipPlanes = ClipPlane[]
|
|
28
|
+
export type ClipPlanes = ClipPlane[]
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Volume bounds in world space.
|
|
31
32
|
*/
|
|
32
33
|
export interface VolumeBounds {
|
|
33
|
-
min: [number, number, number]
|
|
34
|
-
max: [number, number, number]
|
|
34
|
+
min: [number, number, number]
|
|
35
|
+
max: [number, number, number]
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -40,9 +41,9 @@ export interface VolumeBounds {
|
|
|
40
41
|
*/
|
|
41
42
|
export interface PixelRegion {
|
|
42
43
|
/** Start indices [z, y, x] (inclusive) */
|
|
43
|
-
start: [number, number, number]
|
|
44
|
+
start: [number, number, number]
|
|
44
45
|
/** End indices [z, y, x] (exclusive) */
|
|
45
|
-
end: [number, number, number]
|
|
46
|
+
end: [number, number, number]
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/**
|
|
@@ -50,11 +51,11 @@ export interface PixelRegion {
|
|
|
50
51
|
*/
|
|
51
52
|
export interface ChunkAlignedRegion extends PixelRegion {
|
|
52
53
|
/** Chunk-aligned start indices [z, y, x] */
|
|
53
|
-
chunkAlignedStart: [number, number, number]
|
|
54
|
+
chunkAlignedStart: [number, number, number]
|
|
54
55
|
/** Chunk-aligned end indices [z, y, x] */
|
|
55
|
-
chunkAlignedEnd: [number, number, number]
|
|
56
|
+
chunkAlignedEnd: [number, number, number]
|
|
56
57
|
/** True if the original region didn't align with chunk boundaries */
|
|
57
|
-
needsClipping: boolean
|
|
58
|
+
needsClipping: boolean
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/**
|
|
@@ -62,11 +63,11 @@ export interface ChunkAlignedRegion extends PixelRegion {
|
|
|
62
63
|
*/
|
|
63
64
|
export interface ResolutionSelection {
|
|
64
65
|
/** Index into multiscales.images array */
|
|
65
|
-
levelIndex: number
|
|
66
|
+
levelIndex: number
|
|
66
67
|
/** Dimensions of the buffer [z, y, x] */
|
|
67
|
-
dimensions: [number, number, number]
|
|
68
|
+
dimensions: [number, number, number]
|
|
68
69
|
/** Total pixel count */
|
|
69
|
-
pixelCount: number
|
|
70
|
+
pixelCount: number
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
/**
|
|
@@ -93,9 +94,9 @@ export interface ResolutionSelection {
|
|
|
93
94
|
*/
|
|
94
95
|
export interface ChunkCache {
|
|
95
96
|
/** Look up a cached decoded chunk by key. */
|
|
96
|
-
get(key: string): unknown | undefined
|
|
97
|
+
get(key: string): unknown | undefined
|
|
97
98
|
/** Store a decoded chunk under the given key. */
|
|
98
|
-
set(key: string, value: unknown): void
|
|
99
|
+
set(key: string, value: unknown): void
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
/**
|
|
@@ -103,36 +104,36 @@ export interface ChunkCache {
|
|
|
103
104
|
*/
|
|
104
105
|
export interface OMEZarrNVImageOptions {
|
|
105
106
|
/** The OME-Zarr multiscales data */
|
|
106
|
-
multiscales: Multiscales
|
|
107
|
+
multiscales: Multiscales
|
|
107
108
|
/** Reference to the NiiVue instance for rendering updates */
|
|
108
|
-
niivue: Niivue
|
|
109
|
+
niivue: Niivue
|
|
109
110
|
/** Maximum number of pixels to use (default: 50,000,000) */
|
|
110
|
-
maxPixels?: number
|
|
111
|
+
maxPixels?: number
|
|
111
112
|
/** Debounce delay for clip plane data refetch in milliseconds (default: 300) */
|
|
112
|
-
clipPlaneDebounceMs?: number
|
|
113
|
+
clipPlaneDebounceMs?: number
|
|
113
114
|
/**
|
|
114
115
|
* Automatically add to NiiVue and start progressive loading (default: true).
|
|
115
116
|
* Set to false to manually control when populateVolume() is called.
|
|
116
117
|
* Listen to 'populateComplete' event to know when loading finishes.
|
|
117
118
|
*/
|
|
118
|
-
autoLoad?: boolean
|
|
119
|
+
autoLoad?: boolean
|
|
119
120
|
/**
|
|
120
121
|
* Maximum 3D render zoom level for scroll-wheel zoom (default: 10.0).
|
|
121
122
|
* NiiVue's built-in 3D zoom is hardcoded to [0.5, 2.0]. This option
|
|
122
123
|
* overrides the scroll-wheel zoom handler to allow zooming beyond that limit.
|
|
123
124
|
*/
|
|
124
|
-
max3DZoom?: number
|
|
125
|
+
max3DZoom?: number
|
|
125
126
|
/**
|
|
126
127
|
* Minimum 3D render zoom level for scroll-wheel zoom (default: 0.3).
|
|
127
128
|
* @see max3DZoom
|
|
128
129
|
*/
|
|
129
|
-
min3DZoom?: number
|
|
130
|
+
min3DZoom?: number
|
|
130
131
|
/**
|
|
131
132
|
* Enable viewport-aware resolution selection (default: true).
|
|
132
133
|
* When enabled, zoom/pan interactions constrain the fetch region to the
|
|
133
134
|
* visible viewport, allowing higher resolution within the same maxPixels budget.
|
|
134
135
|
*/
|
|
135
|
-
viewportAware?: boolean
|
|
136
|
+
viewportAware?: boolean
|
|
136
137
|
/**
|
|
137
138
|
* Maximum number of decoded-chunk cache entries (default: 200).
|
|
138
139
|
*
|
|
@@ -142,7 +143,7 @@ export interface OMEZarrNVImageOptions {
|
|
|
142
143
|
*
|
|
143
144
|
* Set to `0` to disable caching entirely.
|
|
144
145
|
*/
|
|
145
|
-
maxCacheEntries?: number
|
|
146
|
+
maxCacheEntries?: number
|
|
146
147
|
/**
|
|
147
148
|
* Optional pre-built decoded-chunk cache. When provided, overrides the
|
|
148
149
|
* internal LRU cache created from `maxCacheEntries`.
|
|
@@ -152,7 +153,18 @@ export interface OMEZarrNVImageOptions {
|
|
|
152
153
|
*
|
|
153
154
|
* @see {@link ChunkCache}
|
|
154
155
|
*/
|
|
155
|
-
cache?: ChunkCache
|
|
156
|
+
cache?: ChunkCache
|
|
157
|
+
/**
|
|
158
|
+
* Flip the y-axis in the NIfTI affine for 2D images (default: true).
|
|
159
|
+
*
|
|
160
|
+
* 2D images (e.g., PNGs converted to OME-Zarr) store pixel data with
|
|
161
|
+
* y=0 at the top (increasing downward). NiiVue expects a negative
|
|
162
|
+
* y-scale in the affine to render these right-side up. Set to `false`
|
|
163
|
+
* if your 2D data already has bottom-to-top y ordering.
|
|
164
|
+
*
|
|
165
|
+
* This option has no effect on 3D volumes (images with a `"z"` axis).
|
|
166
|
+
*/
|
|
167
|
+
flipY2D?: boolean
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
/**
|
|
@@ -160,11 +172,11 @@ export interface OMEZarrNVImageOptions {
|
|
|
160
172
|
*/
|
|
161
173
|
export interface RegionFetchResult {
|
|
162
174
|
/** The pixel data as a typed array */
|
|
163
|
-
data: TypedArray
|
|
175
|
+
data: TypedArray
|
|
164
176
|
/** Shape of the fetched data [z, y, x] */
|
|
165
|
-
shape: number[]
|
|
177
|
+
shape: number[]
|
|
166
178
|
/** Stride of the fetched data */
|
|
167
|
-
stride: number[]
|
|
179
|
+
stride: number[]
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
/**
|
|
@@ -178,7 +190,7 @@ export type ZarrDtype =
|
|
|
178
190
|
| "int16"
|
|
179
191
|
| "int32"
|
|
180
192
|
| "float32"
|
|
181
|
-
| "float64"
|
|
193
|
+
| "float64"
|
|
182
194
|
|
|
183
195
|
/**
|
|
184
196
|
* Union of all typed array types we support.
|
|
@@ -191,7 +203,7 @@ export type TypedArray =
|
|
|
191
203
|
| Int16Array
|
|
192
204
|
| Int32Array
|
|
193
205
|
| Float32Array
|
|
194
|
-
| Float64Array
|
|
206
|
+
| Float64Array
|
|
195
207
|
|
|
196
208
|
/**
|
|
197
209
|
* Typed arrays supported by NiiVue.
|
|
@@ -202,10 +214,10 @@ export type NiiVueTypedArray =
|
|
|
202
214
|
| Uint16Array
|
|
203
215
|
| Int16Array
|
|
204
216
|
| Float32Array
|
|
205
|
-
| Float64Array
|
|
217
|
+
| Float64Array
|
|
206
218
|
|
|
207
219
|
// Re-export SLICE_TYPE for convenience
|
|
208
|
-
export { SLICE_TYPE }
|
|
220
|
+
export { SLICE_TYPE }
|
|
209
221
|
|
|
210
222
|
/**
|
|
211
223
|
* The 2D slice types that use slab-based loading.
|
|
@@ -214,7 +226,7 @@ export { SLICE_TYPE };
|
|
|
214
226
|
export type SlabSliceType =
|
|
215
227
|
| typeof SLICE_TYPE.AXIAL
|
|
216
228
|
| typeof SLICE_TYPE.CORONAL
|
|
217
|
-
| typeof SLICE_TYPE.SAGITTAL
|
|
229
|
+
| typeof SLICE_TYPE.SAGITTAL
|
|
218
230
|
|
|
219
231
|
/**
|
|
220
232
|
* State for a per-slice-type slab buffer.
|
|
@@ -225,37 +237,37 @@ export type SlabSliceType =
|
|
|
225
237
|
*/
|
|
226
238
|
export interface SlabBufferState {
|
|
227
239
|
/** The NVImage instance for this slab */
|
|
228
|
-
nvImage: NVImage
|
|
240
|
+
nvImage: NVImage
|
|
229
241
|
/** Buffer manager for this slab's pixel data */
|
|
230
|
-
bufferManager: BufferManager
|
|
242
|
+
bufferManager: BufferManager
|
|
231
243
|
/** Current resolution level index for this slab */
|
|
232
|
-
levelIndex: number
|
|
244
|
+
levelIndex: number
|
|
233
245
|
/** Target resolution level index for this slab */
|
|
234
|
-
targetLevelIndex: number
|
|
246
|
+
targetLevelIndex: number
|
|
235
247
|
/** Start index of the currently loaded slab in the orthogonal axis (pixel coords at current level) */
|
|
236
|
-
slabStart: number
|
|
248
|
+
slabStart: number
|
|
237
249
|
/** End index of the currently loaded slab in the orthogonal axis (pixel coords at current level) */
|
|
238
|
-
slabEnd: number
|
|
250
|
+
slabEnd: number
|
|
239
251
|
/** Whether this slab is currently loading */
|
|
240
|
-
isLoading: boolean
|
|
252
|
+
isLoading: boolean
|
|
241
253
|
/** Data type of the slab */
|
|
242
|
-
dtype: ZarrDtype
|
|
254
|
+
dtype: ZarrDtype
|
|
243
255
|
/**
|
|
244
256
|
* The affine normalization scale applied to the slab NVImage header.
|
|
245
257
|
* NiiVue mm values = world * normalizationScale.
|
|
246
258
|
* This is 1/maxVoxelSize where maxVoxelSize = max(sx, sy, sz).
|
|
247
259
|
* Used to convert NiiVue 2D FOV coordinates back to physical world coords.
|
|
248
260
|
*/
|
|
249
|
-
normalizationScale: number
|
|
261
|
+
normalizationScale: number
|
|
250
262
|
/**
|
|
251
263
|
* Pending reload request queued while this slab was loading.
|
|
252
264
|
* Latest-wins semantics: only the most recent request is kept.
|
|
253
265
|
* Auto-drained when the current load completes.
|
|
254
266
|
*/
|
|
255
267
|
pendingReload: {
|
|
256
|
-
worldCoord: [number, number, number]
|
|
257
|
-
trigger: PopulateTrigger
|
|
258
|
-
} | null
|
|
268
|
+
worldCoord: [number, number, number]
|
|
269
|
+
trigger: PopulateTrigger
|
|
270
|
+
} | null
|
|
259
271
|
}
|
|
260
272
|
|
|
261
273
|
/**
|
|
@@ -263,25 +275,25 @@ export interface SlabBufferState {
|
|
|
263
275
|
*/
|
|
264
276
|
export interface AttachedNiivueState {
|
|
265
277
|
/** The Niivue instance */
|
|
266
|
-
nv: Niivue
|
|
278
|
+
nv: Niivue
|
|
267
279
|
/** The current slice type of this NV instance */
|
|
268
|
-
currentSliceType: SLICE_TYPE
|
|
280
|
+
currentSliceType: SLICE_TYPE
|
|
269
281
|
/** Previous onLocationChange callback (to chain) */
|
|
270
|
-
previousOnLocationChange?: (location: unknown) => void
|
|
282
|
+
previousOnLocationChange?: (location: unknown) => void
|
|
271
283
|
/** Previous onOptsChange callback (to chain) */
|
|
272
284
|
previousOnOptsChange?: (
|
|
273
285
|
propertyName: string,
|
|
274
286
|
newValue: unknown,
|
|
275
287
|
oldValue: unknown,
|
|
276
|
-
) => void
|
|
288
|
+
) => void
|
|
277
289
|
/** Previous onMouseUp callback (to chain, for viewport-aware mode) */
|
|
278
|
-
previousOnMouseUp?: (data: unknown) => void
|
|
290
|
+
previousOnMouseUp?: (data: unknown) => void
|
|
279
291
|
/** Previous onZoom3DChange callback (to chain, for viewport-aware mode) */
|
|
280
|
-
previousOnZoom3DChange?: (zoom: number) => void
|
|
292
|
+
previousOnZoom3DChange?: (zoom: number) => void
|
|
281
293
|
/** AbortController for viewport-aware event listeners (wheel, etc.) */
|
|
282
|
-
viewportAbortController?: AbortController
|
|
294
|
+
viewportAbortController?: AbortController
|
|
283
295
|
/** AbortController for the 3D zoom override wheel listener */
|
|
284
|
-
zoomOverrideAbortController?: AbortController
|
|
296
|
+
zoomOverrideAbortController?: AbortController
|
|
285
297
|
}
|
|
286
298
|
|
|
287
299
|
/**
|
|
@@ -295,7 +307,7 @@ export type TypedArrayConstructor =
|
|
|
295
307
|
| Int16ArrayConstructor
|
|
296
308
|
| Int32ArrayConstructor
|
|
297
309
|
| Float32ArrayConstructor
|
|
298
|
-
| Float64ArrayConstructor
|
|
310
|
+
| Float64ArrayConstructor
|
|
299
311
|
|
|
300
312
|
/**
|
|
301
313
|
* NIfTI data type codes.
|
|
@@ -306,13 +318,96 @@ export const NiftiDataType = {
|
|
|
306
318
|
INT32: 8,
|
|
307
319
|
FLOAT32: 16,
|
|
308
320
|
FLOAT64: 64,
|
|
321
|
+
RGB24: 128,
|
|
309
322
|
INT8: 256,
|
|
310
323
|
UINT16: 512,
|
|
311
324
|
UINT32: 768,
|
|
312
|
-
|
|
325
|
+
RGBA32: 2304,
|
|
326
|
+
} as const
|
|
313
327
|
|
|
314
328
|
export type NiftiDataTypeCode =
|
|
315
|
-
(typeof NiftiDataType)[keyof typeof NiftiDataType]
|
|
329
|
+
(typeof NiftiDataType)[keyof typeof NiftiDataType]
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Information about a channel (component) dimension in the image.
|
|
333
|
+
*/
|
|
334
|
+
export interface ChannelInfo {
|
|
335
|
+
/** Index of the `"c"` dimension in `ngffImage.dims` */
|
|
336
|
+
channelAxis: number
|
|
337
|
+
/** Number of components (e.g. 3 for RGB, 4 for RGBA) */
|
|
338
|
+
components: number
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Detect whether an NgffImage has a channel (`"c"`) dimension.
|
|
343
|
+
*
|
|
344
|
+
* @param ngffImage - The NgffImage to inspect
|
|
345
|
+
* @returns Channel information, or `null` if no `"c"` dimension exists
|
|
346
|
+
*/
|
|
347
|
+
export function getChannelInfo(ngffImage: NgffImage): ChannelInfo | null {
|
|
348
|
+
const channelAxis = ngffImage.dims.indexOf("c")
|
|
349
|
+
if (channelAxis === -1) return null
|
|
350
|
+
const components = ngffImage.data.shape[channelAxis]
|
|
351
|
+
return { channelAxis, components }
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Check whether an NgffImage represents an RGB or RGBA image.
|
|
356
|
+
*
|
|
357
|
+
* An image is considered RGB/RGBA when it has a `"c"` dimension with
|
|
358
|
+
* 3 or 4 components. Any dtype is supported — non-uint8 data is
|
|
359
|
+
* normalized to uint8 at load time (see {@link needsRGBNormalization}).
|
|
360
|
+
*
|
|
361
|
+
* @param ngffImage - The NgffImage to inspect
|
|
362
|
+
* @returns `true` if the image is RGB (3 components) or RGBA (4 components)
|
|
363
|
+
*/
|
|
364
|
+
export function isRGBImage(ngffImage: NgffImage): boolean {
|
|
365
|
+
const info = getChannelInfo(ngffImage)
|
|
366
|
+
if (!info) return false
|
|
367
|
+
return info.components === 3 || info.components === 4
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Check whether a multi-component RGB/RGBA image needs normalization
|
|
372
|
+
* to uint8 before NiiVue can render it.
|
|
373
|
+
*
|
|
374
|
+
* NiiVue only supports `DT_RGB24` (3×uint8) and `DT_RGBA32` (4×uint8)
|
|
375
|
+
* color rendering. Non-uint8 multi-component images must be normalized
|
|
376
|
+
* to uint8 using OMERO window metadata (or computed min/max).
|
|
377
|
+
*
|
|
378
|
+
* @param ngffImage - The NgffImage to inspect
|
|
379
|
+
* @param dtype - The parsed zarr dtype
|
|
380
|
+
* @returns `true` if the image is RGB/RGBA with a non-uint8 dtype
|
|
381
|
+
*/
|
|
382
|
+
export function needsRGBNormalization(
|
|
383
|
+
ngffImage: NgffImage,
|
|
384
|
+
dtype: ZarrDtype,
|
|
385
|
+
): boolean {
|
|
386
|
+
return isRGBImage(ngffImage) && dtype !== "uint8"
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get the NIfTI data type code for a multi-component image.
|
|
391
|
+
*
|
|
392
|
+
* Returns `RGB24` for 3 components and `RGBA32` for 4 components,
|
|
393
|
+
* regardless of the source dtype. Non-uint8 data is normalized to
|
|
394
|
+
* uint8 at load time before being stored in the NVImage buffer.
|
|
395
|
+
*
|
|
396
|
+
* @param channelInfo - Channel information from `getChannelInfo()`
|
|
397
|
+
* @returns The NIfTI data type code (`RGB24` or `RGBA32`)
|
|
398
|
+
* @throws If the component count is not 3 or 4
|
|
399
|
+
*/
|
|
400
|
+
export function getRGBNiftiDataType(
|
|
401
|
+
channelInfo: ChannelInfo,
|
|
402
|
+
): NiftiDataTypeCode {
|
|
403
|
+
if (channelInfo.components === 3) return NiftiDataType.RGB24
|
|
404
|
+
if (channelInfo.components === 4) return NiftiDataType.RGBA32
|
|
405
|
+
throw new Error(
|
|
406
|
+
`Unsupported multi-component image: ` +
|
|
407
|
+
`components=${channelInfo.components}. ` +
|
|
408
|
+
`Only 3 (RGB) or 4 (RGBA) components are supported.`,
|
|
409
|
+
)
|
|
410
|
+
}
|
|
316
411
|
|
|
317
412
|
/**
|
|
318
413
|
* Map zarr dtype to typed array constructor.
|
|
@@ -322,23 +417,23 @@ export function getTypedArrayConstructor(
|
|
|
322
417
|
): TypedArrayConstructor {
|
|
323
418
|
switch (dtype) {
|
|
324
419
|
case "uint8":
|
|
325
|
-
return Uint8Array
|
|
420
|
+
return Uint8Array
|
|
326
421
|
case "uint16":
|
|
327
|
-
return Uint16Array
|
|
422
|
+
return Uint16Array
|
|
328
423
|
case "uint32":
|
|
329
|
-
return Uint32Array
|
|
424
|
+
return Uint32Array
|
|
330
425
|
case "int8":
|
|
331
|
-
return Int8Array
|
|
426
|
+
return Int8Array
|
|
332
427
|
case "int16":
|
|
333
|
-
return Int16Array
|
|
428
|
+
return Int16Array
|
|
334
429
|
case "int32":
|
|
335
|
-
return Int32Array
|
|
430
|
+
return Int32Array
|
|
336
431
|
case "float32":
|
|
337
|
-
return Float32Array
|
|
432
|
+
return Float32Array
|
|
338
433
|
case "float64":
|
|
339
|
-
return Float64Array
|
|
434
|
+
return Float64Array
|
|
340
435
|
default:
|
|
341
|
-
throw new Error(`Unsupported dtype: ${dtype}`)
|
|
436
|
+
throw new Error(`Unsupported dtype: ${dtype}`)
|
|
342
437
|
}
|
|
343
438
|
}
|
|
344
439
|
|
|
@@ -349,18 +444,18 @@ export function getBytesPerPixel(dtype: ZarrDtype): number {
|
|
|
349
444
|
switch (dtype) {
|
|
350
445
|
case "uint8":
|
|
351
446
|
case "int8":
|
|
352
|
-
return 1
|
|
447
|
+
return 1
|
|
353
448
|
case "uint16":
|
|
354
449
|
case "int16":
|
|
355
|
-
return 2
|
|
450
|
+
return 2
|
|
356
451
|
case "uint32":
|
|
357
452
|
case "int32":
|
|
358
453
|
case "float32":
|
|
359
|
-
return 4
|
|
454
|
+
return 4
|
|
360
455
|
case "float64":
|
|
361
|
-
return 8
|
|
456
|
+
return 8
|
|
362
457
|
default:
|
|
363
|
-
throw new Error(`Unsupported dtype: ${dtype}`)
|
|
458
|
+
throw new Error(`Unsupported dtype: ${dtype}`)
|
|
364
459
|
}
|
|
365
460
|
}
|
|
366
461
|
|
|
@@ -370,23 +465,23 @@ export function getBytesPerPixel(dtype: ZarrDtype): number {
|
|
|
370
465
|
export function getNiftiDataType(dtype: ZarrDtype): NiftiDataTypeCode {
|
|
371
466
|
switch (dtype) {
|
|
372
467
|
case "uint8":
|
|
373
|
-
return NiftiDataType.UINT8
|
|
468
|
+
return NiftiDataType.UINT8
|
|
374
469
|
case "uint16":
|
|
375
|
-
return NiftiDataType.UINT16
|
|
470
|
+
return NiftiDataType.UINT16
|
|
376
471
|
case "uint32":
|
|
377
|
-
return NiftiDataType.UINT32
|
|
472
|
+
return NiftiDataType.UINT32
|
|
378
473
|
case "int8":
|
|
379
|
-
return NiftiDataType.INT8
|
|
474
|
+
return NiftiDataType.INT8
|
|
380
475
|
case "int16":
|
|
381
|
-
return NiftiDataType.INT16
|
|
476
|
+
return NiftiDataType.INT16
|
|
382
477
|
case "int32":
|
|
383
|
-
return NiftiDataType.INT32
|
|
478
|
+
return NiftiDataType.INT32
|
|
384
479
|
case "float32":
|
|
385
|
-
return NiftiDataType.FLOAT32
|
|
480
|
+
return NiftiDataType.FLOAT32
|
|
386
481
|
case "float64":
|
|
387
|
-
return NiftiDataType.FLOAT64
|
|
482
|
+
return NiftiDataType.FLOAT64
|
|
388
483
|
default:
|
|
389
|
-
throw new Error(`Unsupported dtype: ${dtype}`)
|
|
484
|
+
throw new Error(`Unsupported dtype: ${dtype}`)
|
|
390
485
|
}
|
|
391
486
|
}
|
|
392
487
|
|
|
@@ -396,34 +491,34 @@ export function getNiftiDataType(dtype: ZarrDtype): NiftiDataTypeCode {
|
|
|
396
491
|
*/
|
|
397
492
|
export function parseZarritaDtype(dtype: string): ZarrDtype {
|
|
398
493
|
// Remove endianness prefix if present
|
|
399
|
-
const normalized = dtype.replace(/^[|<>]/, "")
|
|
494
|
+
const normalized = dtype.replace(/^[|<>]/, "")
|
|
400
495
|
|
|
401
496
|
switch (normalized) {
|
|
402
497
|
case "u1":
|
|
403
498
|
case "uint8":
|
|
404
|
-
return "uint8"
|
|
499
|
+
return "uint8"
|
|
405
500
|
case "u2":
|
|
406
501
|
case "uint16":
|
|
407
|
-
return "uint16"
|
|
502
|
+
return "uint16"
|
|
408
503
|
case "u4":
|
|
409
504
|
case "uint32":
|
|
410
|
-
return "uint32"
|
|
505
|
+
return "uint32"
|
|
411
506
|
case "i1":
|
|
412
507
|
case "int8":
|
|
413
|
-
return "int8"
|
|
508
|
+
return "int8"
|
|
414
509
|
case "i2":
|
|
415
510
|
case "int16":
|
|
416
|
-
return "int16"
|
|
511
|
+
return "int16"
|
|
417
512
|
case "i4":
|
|
418
513
|
case "int32":
|
|
419
|
-
return "int32"
|
|
514
|
+
return "int32"
|
|
420
515
|
case "f4":
|
|
421
516
|
case "float32":
|
|
422
|
-
return "float32"
|
|
517
|
+
return "float32"
|
|
423
518
|
case "f8":
|
|
424
519
|
case "float64":
|
|
425
|
-
return "float64"
|
|
520
|
+
return "float64"
|
|
426
521
|
default:
|
|
427
|
-
throw new Error(`Unsupported zarrita dtype: ${dtype}`)
|
|
522
|
+
throw new Error(`Unsupported zarrita dtype: ${dtype}`)
|
|
428
523
|
}
|
|
429
524
|
}
|