@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.
Files changed (56) hide show
  1. package/dist/BufferManager.d.ts +37 -4
  2. package/dist/BufferManager.d.ts.map +1 -1
  3. package/dist/BufferManager.js +69 -24
  4. package/dist/BufferManager.js.map +1 -1
  5. package/dist/ClipPlanes.d.ts.map +1 -1
  6. package/dist/ClipPlanes.js +11 -15
  7. package/dist/ClipPlanes.js.map +1 -1
  8. package/dist/OMEZarrNVImage.d.ts +59 -3
  9. package/dist/OMEZarrNVImage.d.ts.map +1 -1
  10. package/dist/OMEZarrNVImage.js +267 -68
  11. package/dist/OMEZarrNVImage.js.map +1 -1
  12. package/dist/RegionCoalescer.d.ts +16 -0
  13. package/dist/RegionCoalescer.d.ts.map +1 -1
  14. package/dist/RegionCoalescer.js +43 -6
  15. package/dist/RegionCoalescer.js.map +1 -1
  16. package/dist/ResolutionSelector.d.ts +14 -2
  17. package/dist/ResolutionSelector.d.ts.map +1 -1
  18. package/dist/ResolutionSelector.js +28 -20
  19. package/dist/ResolutionSelector.js.map +1 -1
  20. package/dist/ViewportBounds.d.ts.map +1 -1
  21. package/dist/ViewportBounds.js +7 -5
  22. package/dist/ViewportBounds.js.map +1 -1
  23. package/dist/events.d.ts.map +1 -1
  24. package/dist/events.js.map +1 -1
  25. package/dist/index.d.ts +13 -11
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +18 -16
  28. package/dist/index.js.map +1 -1
  29. package/dist/normalize.d.ts +50 -0
  30. package/dist/normalize.d.ts.map +1 -0
  31. package/dist/normalize.js +95 -0
  32. package/dist/normalize.js.map +1 -0
  33. package/dist/types.d.ts +66 -1
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/types.js +66 -0
  36. package/dist/types.js.map +1 -1
  37. package/dist/utils/affine.d.ts +1 -1
  38. package/dist/utils/affine.d.ts.map +1 -1
  39. package/dist/utils/affine.js.map +1 -1
  40. package/dist/utils/coordinates.d.ts +1 -1
  41. package/dist/utils/coordinates.d.ts.map +1 -1
  42. package/dist/utils/coordinates.js +20 -26
  43. package/dist/utils/coordinates.js.map +1 -1
  44. package/package.json +3 -4
  45. package/src/BufferManager.ts +114 -53
  46. package/src/ClipPlanes.ts +131 -130
  47. package/src/OMEZarrNVImage.ts +863 -618
  48. package/src/RegionCoalescer.ts +92 -51
  49. package/src/ResolutionSelector.ts +94 -79
  50. package/src/ViewportBounds.ts +120 -118
  51. package/src/events.ts +36 -35
  52. package/src/index.ts +70 -69
  53. package/src/normalize.ts +119 -0
  54. package/src/types.ts +189 -94
  55. package/src/utils/affine.ts +65 -65
  56. 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
- import type { BufferManager } from "./BufferManager.js";
8
- import type { PopulateTrigger } from "./events.js";
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
- } as const;
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
  }