@fideus-labs/fidnii 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE.txt +9 -0
  2. package/README.md +180 -0
  3. package/dist/BufferManager.d.ts +86 -0
  4. package/dist/BufferManager.d.ts.map +1 -0
  5. package/dist/BufferManager.js +146 -0
  6. package/dist/BufferManager.js.map +1 -0
  7. package/dist/ClipPlanes.d.ts +180 -0
  8. package/dist/ClipPlanes.d.ts.map +1 -0
  9. package/dist/ClipPlanes.js +513 -0
  10. package/dist/ClipPlanes.js.map +1 -0
  11. package/dist/OMEZarrNVImage.d.ts +545 -0
  12. package/dist/OMEZarrNVImage.d.ts.map +1 -0
  13. package/dist/OMEZarrNVImage.js +1799 -0
  14. package/dist/OMEZarrNVImage.js.map +1 -0
  15. package/dist/RegionCoalescer.d.ts +75 -0
  16. package/dist/RegionCoalescer.d.ts.map +1 -0
  17. package/dist/RegionCoalescer.js +151 -0
  18. package/dist/RegionCoalescer.js.map +1 -0
  19. package/dist/ResolutionSelector.d.ts +88 -0
  20. package/dist/ResolutionSelector.d.ts.map +1 -0
  21. package/dist/ResolutionSelector.js +224 -0
  22. package/dist/ResolutionSelector.js.map +1 -0
  23. package/dist/ViewportBounds.d.ts +50 -0
  24. package/dist/ViewportBounds.d.ts.map +1 -0
  25. package/dist/ViewportBounds.js +325 -0
  26. package/dist/ViewportBounds.js.map +1 -0
  27. package/dist/events.d.ts +122 -0
  28. package/dist/events.d.ts.map +1 -0
  29. package/dist/events.js +12 -0
  30. package/dist/events.js.map +1 -0
  31. package/dist/index.d.ts +48 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +59 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/types.d.ts +273 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +126 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils/affine.d.ts +72 -0
  40. package/dist/utils/affine.d.ts.map +1 -0
  41. package/dist/utils/affine.js +173 -0
  42. package/dist/utils/affine.js.map +1 -0
  43. package/dist/utils/coordinates.d.ts +80 -0
  44. package/dist/utils/coordinates.d.ts.map +1 -0
  45. package/dist/utils/coordinates.js +207 -0
  46. package/dist/utils/coordinates.js.map +1 -0
  47. package/package.json +61 -0
  48. package/src/BufferManager.ts +176 -0
  49. package/src/ClipPlanes.ts +640 -0
  50. package/src/OMEZarrNVImage.ts +2286 -0
  51. package/src/RegionCoalescer.ts +217 -0
  52. package/src/ResolutionSelector.ts +325 -0
  53. package/src/ViewportBounds.ts +369 -0
  54. package/src/events.ts +146 -0
  55. package/src/index.ts +153 -0
  56. package/src/types.ts +429 -0
  57. package/src/utils/affine.ts +218 -0
  58. package/src/utils/coordinates.ts +271 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,+BAA+B;AAI/B,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAyM5C,uCAAuC;AACvC,OAAO,EAAE,UAAU,EAAE,CAAC;AA4FtB;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;CACH,CAAC;AAKX;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAAgB;IAEhB,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,OAAO,UAAU,CAAC;QACpB,KAAK,QAAQ;YACX,OAAO,WAAW,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,WAAW,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,SAAS,CAAC;QACnB,KAAK,OAAO;YACV,OAAO,UAAU,CAAC;QACpB,KAAK,OAAO;YACV,OAAO,UAAU,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,YAAY,CAAC;QACtB,KAAK,SAAS;YACZ,OAAO,YAAY,CAAC;QACtB;YACE,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgB;IAC/C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,MAAM;YACT,OAAO,CAAC,CAAC;QACX,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO;YACV,OAAO,CAAC,CAAC;QACX,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC;QACX,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC;QACX;YACE,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgB;IAC/C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,OAAO,aAAa,CAAC,KAAK,CAAC;QAC7B,KAAK,QAAQ;YACX,OAAO,aAAa,CAAC,MAAM,CAAC;QAC9B,KAAK,QAAQ;YACX,OAAO,aAAa,CAAC,MAAM,CAAC;QAC9B,KAAK,MAAM;YACT,OAAO,aAAa,CAAC,IAAI,CAAC;QAC5B,KAAK,OAAO;YACV,OAAO,aAAa,CAAC,KAAK,CAAC;QAC7B,KAAK,OAAO;YACV,OAAO,aAAa,CAAC,KAAK,CAAC;QAC7B,KAAK,SAAS;YACZ,OAAO,aAAa,CAAC,OAAO,CAAC;QAC/B,KAAK,SAAS;YACZ,OAAO,aAAa,CAAC,OAAO,CAAC;QAC/B;YACE,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,sCAAsC;IACtC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAE/C,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,IAAI,CAAC;QACV,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,IAAI,CAAC;QACV,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,IAAI,CAAC;QACV,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,IAAI,CAAC;QACV,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,IAAI,CAAC;QACV,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,IAAI,CAAC;QACV,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB;YACE,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
@@ -0,0 +1,72 @@
1
+ import { mat4 } from "gl-matrix";
2
+ import type { NgffImage } from "@fideus-labs/ngff-zarr";
3
+ /**
4
+ * Create a 4x4 affine transformation matrix from OME-Zarr scale and translation.
5
+ *
6
+ * The affine matrix transforms from pixel indices to world coordinates.
7
+ * NIfTI uses a column-major 4x4 matrix stored as a flat array of 16 elements.
8
+ *
9
+ * For OME-Zarr, the transformation is:
10
+ * world = scale * pixel + translation
11
+ *
12
+ * The matrix form is:
13
+ * | sx 0 0 tx |
14
+ * | 0 sy 0 ty |
15
+ * | 0 0 sz tz |
16
+ * | 0 0 0 1 |
17
+ *
18
+ * @param scale - Scale factors { x, y, z }
19
+ * @param translation - Translation offsets { x, y, z }
20
+ * @returns 4x4 affine matrix as a flat Float32Array (column-major)
21
+ */
22
+ export declare function createAffineFromOMEZarr(scale: Record<string, number>, translation: Record<string, number>): mat4;
23
+ /**
24
+ * Create an affine matrix from an NgffImage.
25
+ *
26
+ * @param ngffImage - The NgffImage containing scale and translation
27
+ * @returns 4x4 affine matrix
28
+ */
29
+ export declare function createAffineFromNgffImage(ngffImage: NgffImage): mat4;
30
+ /**
31
+ * Convert an affine matrix to a flat array for NIfTI header.
32
+ * NIfTI uses srow_x, srow_y, srow_z which are the first 3 rows of the affine.
33
+ *
34
+ * @param affine - The 4x4 affine matrix
35
+ * @returns Object with srow_x, srow_y, srow_z arrays
36
+ */
37
+ export declare function affineToNiftiSrows(affine: mat4): {
38
+ srow_x: [number, number, number, number];
39
+ srow_y: [number, number, number, number];
40
+ srow_z: [number, number, number, number];
41
+ };
42
+ /**
43
+ * Get pixel dimensions (voxel sizes) from an affine matrix.
44
+ *
45
+ * @param affine - The 4x4 affine matrix
46
+ * @returns Pixel dimensions [x, y, z]
47
+ */
48
+ export declare function getPixelDimensions(affine: mat4): [number, number, number];
49
+ /**
50
+ * Update affine matrix for a cropped/subsampled region.
51
+ *
52
+ * When we load a subregion or at a different resolution, we need to update
53
+ * the affine to reflect the new origin and voxel sizes.
54
+ *
55
+ * @param originalAffine - Original affine matrix
56
+ * @param regionStart - Start pixel indices [z, y, x] of the region
57
+ * @param scaleFactor - Scale factor applied (> 1 means downsampled)
58
+ * @returns Updated affine matrix
59
+ */
60
+ export declare function updateAffineForRegion(originalAffine: mat4, regionStart: [number, number, number], scaleFactor: [number, number, number]): mat4;
61
+ /**
62
+ * Calculate the world-space bounding box from an affine and dimensions.
63
+ *
64
+ * @param affine - The 4x4 affine matrix
65
+ * @param dimensions - Volume dimensions [z, y, x]
66
+ * @returns Bounding box { min: [x,y,z], max: [x,y,z] }
67
+ */
68
+ export declare function calculateWorldBounds(affine: mat4, dimensions: [number, number, number]): {
69
+ min: [number, number, number];
70
+ max: [number, number, number];
71
+ };
72
+ //# sourceMappingURL=affine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affine.d.ts","sourceRoot":"","sources":["../../src/utils/affine.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,IAAI,CA6CN;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,GAAG;IAChD,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C,CAUA;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAOzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,IAAI,EACpB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACrC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACpC,IAAI,CA4BN;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,IAAI,EACZ,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACnC;IAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAuClE"}
@@ -0,0 +1,173 @@
1
+ // SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
2
+ // SPDX-License-Identifier: MIT
3
+ import { mat4 } from "gl-matrix";
4
+ /**
5
+ * Create a 4x4 affine transformation matrix from OME-Zarr scale and translation.
6
+ *
7
+ * The affine matrix transforms from pixel indices to world coordinates.
8
+ * NIfTI uses a column-major 4x4 matrix stored as a flat array of 16 elements.
9
+ *
10
+ * For OME-Zarr, the transformation is:
11
+ * world = scale * pixel + translation
12
+ *
13
+ * The matrix form is:
14
+ * | sx 0 0 tx |
15
+ * | 0 sy 0 ty |
16
+ * | 0 0 sz tz |
17
+ * | 0 0 0 1 |
18
+ *
19
+ * @param scale - Scale factors { x, y, z }
20
+ * @param translation - Translation offsets { x, y, z }
21
+ * @returns 4x4 affine matrix as a flat Float32Array (column-major)
22
+ */
23
+ export function createAffineFromOMEZarr(scale, translation) {
24
+ const affine = mat4.create();
25
+ // NIfTI expects the matrix in a specific orientation
26
+ // The affine maps from (i, j, k) voxel indices to (x, y, z) world coordinates
27
+ // For OME-Zarr with [z, y, x] ordering, we need to handle the axis mapping
28
+ // Extract scale and translation for each axis
29
+ const sx = scale.x ?? scale.X ?? 1;
30
+ const sy = scale.y ?? scale.Y ?? 1;
31
+ const sz = scale.z ?? scale.Z ?? 1;
32
+ const tx = translation.x ?? translation.X ?? 0;
33
+ const ty = translation.y ?? translation.Y ?? 0;
34
+ const tz = translation.z ?? translation.Z ?? 0;
35
+ // Build affine matrix
36
+ // NIfTI convention: first index (i) -> x, second (j) -> y, third (k) -> z
37
+ // OME-Zarr stores data as [z, y, x], so we need to account for this
38
+ // Column 0: x direction (from third array index in [z,y,x])
39
+ affine[0] = sx;
40
+ affine[1] = 0;
41
+ affine[2] = 0;
42
+ affine[3] = 0;
43
+ // Column 1: y direction (from second array index in [z,y,x])
44
+ affine[4] = 0;
45
+ affine[5] = sy;
46
+ affine[6] = 0;
47
+ affine[7] = 0;
48
+ // Column 2: z direction (from first array index in [z,y,x])
49
+ affine[8] = 0;
50
+ affine[9] = 0;
51
+ affine[10] = sz;
52
+ affine[11] = 0;
53
+ // Column 3: translation
54
+ affine[12] = tx;
55
+ affine[13] = ty;
56
+ affine[14] = tz;
57
+ affine[15] = 1;
58
+ return affine;
59
+ }
60
+ /**
61
+ * Create an affine matrix from an NgffImage.
62
+ *
63
+ * @param ngffImage - The NgffImage containing scale and translation
64
+ * @returns 4x4 affine matrix
65
+ */
66
+ export function createAffineFromNgffImage(ngffImage) {
67
+ return createAffineFromOMEZarr(ngffImage.scale, ngffImage.translation);
68
+ }
69
+ /**
70
+ * Convert an affine matrix to a flat array for NIfTI header.
71
+ * NIfTI uses srow_x, srow_y, srow_z which are the first 3 rows of the affine.
72
+ *
73
+ * @param affine - The 4x4 affine matrix
74
+ * @returns Object with srow_x, srow_y, srow_z arrays
75
+ */
76
+ export function affineToNiftiSrows(affine) {
77
+ // gl-matrix uses column-major order
78
+ // Row 0 (srow_x): elements 0, 4, 8, 12
79
+ // Row 1 (srow_y): elements 1, 5, 9, 13
80
+ // Row 2 (srow_z): elements 2, 6, 10, 14
81
+ return {
82
+ srow_x: [affine[0], affine[4], affine[8], affine[12]],
83
+ srow_y: [affine[1], affine[5], affine[9], affine[13]],
84
+ srow_z: [affine[2], affine[6], affine[10], affine[14]],
85
+ };
86
+ }
87
+ /**
88
+ * Get pixel dimensions (voxel sizes) from an affine matrix.
89
+ *
90
+ * @param affine - The 4x4 affine matrix
91
+ * @returns Pixel dimensions [x, y, z]
92
+ */
93
+ export function getPixelDimensions(affine) {
94
+ // The pixel dimensions are the lengths of the column vectors
95
+ const dx = Math.sqrt(affine[0] ** 2 + affine[1] ** 2 + affine[2] ** 2);
96
+ const dy = Math.sqrt(affine[4] ** 2 + affine[5] ** 2 + affine[6] ** 2);
97
+ const dz = Math.sqrt(affine[8] ** 2 + affine[9] ** 2 + affine[10] ** 2);
98
+ return [dx, dy, dz];
99
+ }
100
+ /**
101
+ * Update affine matrix for a cropped/subsampled region.
102
+ *
103
+ * When we load a subregion or at a different resolution, we need to update
104
+ * the affine to reflect the new origin and voxel sizes.
105
+ *
106
+ * @param originalAffine - Original affine matrix
107
+ * @param regionStart - Start pixel indices [z, y, x] of the region
108
+ * @param scaleFactor - Scale factor applied (> 1 means downsampled)
109
+ * @returns Updated affine matrix
110
+ */
111
+ export function updateAffineForRegion(originalAffine, regionStart, scaleFactor) {
112
+ const result = mat4.clone(originalAffine);
113
+ // Scale the voxel dimensions
114
+ // Column 0 (x direction)
115
+ result[0] *= scaleFactor[2]; // x scale factor
116
+ result[1] *= scaleFactor[2];
117
+ result[2] *= scaleFactor[2];
118
+ // Column 1 (y direction)
119
+ result[4] *= scaleFactor[1]; // y scale factor
120
+ result[5] *= scaleFactor[1];
121
+ result[6] *= scaleFactor[1];
122
+ // Column 2 (z direction)
123
+ result[8] *= scaleFactor[0]; // z scale factor
124
+ result[9] *= scaleFactor[0];
125
+ result[10] *= scaleFactor[0];
126
+ // Update translation for region offset
127
+ // New origin = original_origin + regionStart * original_voxel_size
128
+ const originalPixelDims = getPixelDimensions(originalAffine);
129
+ result[12] += regionStart[2] * originalPixelDims[0]; // x offset
130
+ result[13] += regionStart[1] * originalPixelDims[1]; // y offset
131
+ result[14] += regionStart[0] * originalPixelDims[2]; // z offset
132
+ return result;
133
+ }
134
+ /**
135
+ * Calculate the world-space bounding box from an affine and dimensions.
136
+ *
137
+ * @param affine - The 4x4 affine matrix
138
+ * @param dimensions - Volume dimensions [z, y, x]
139
+ * @returns Bounding box { min: [x,y,z], max: [x,y,z] }
140
+ */
141
+ export function calculateWorldBounds(affine, dimensions) {
142
+ // Calculate all 8 corners of the volume in world space
143
+ const [dimZ, dimY, dimX] = dimensions;
144
+ const corners = [
145
+ [0, 0, 0],
146
+ [dimX, 0, 0],
147
+ [0, dimY, 0],
148
+ [0, 0, dimZ],
149
+ [dimX, dimY, 0],
150
+ [dimX, 0, dimZ],
151
+ [0, dimY, dimZ],
152
+ [dimX, dimY, dimZ],
153
+ ];
154
+ let minX = Infinity, minY = Infinity, minZ = Infinity;
155
+ let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
156
+ for (const [i, j, k] of corners) {
157
+ // Apply affine: world = affine * [i, j, k, 1]^T
158
+ const wx = affine[0] * i + affine[4] * j + affine[8] * k + affine[12];
159
+ const wy = affine[1] * i + affine[5] * j + affine[9] * k + affine[13];
160
+ const wz = affine[2] * i + affine[6] * j + affine[10] * k + affine[14];
161
+ minX = Math.min(minX, wx);
162
+ minY = Math.min(minY, wy);
163
+ minZ = Math.min(minZ, wz);
164
+ maxX = Math.max(maxX, wx);
165
+ maxY = Math.max(maxY, wy);
166
+ maxZ = Math.max(maxZ, wz);
167
+ }
168
+ return {
169
+ min: [minX, minY, minZ],
170
+ max: [maxX, maxY, maxZ],
171
+ };
172
+ }
173
+ //# sourceMappingURL=affine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affine.js","sourceRoot":"","sources":["../../src/utils/affine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { mat4 } from "gl-matrix";
2
+ import type { NgffImage } from "@fideus-labs/ngff-zarr";
3
+ /**
4
+ * Convert a world coordinate to pixel indices.
5
+ *
6
+ * @param worldCoord - World coordinate [x, y, z]
7
+ * @param ngffImage - The NgffImage containing scale and translation
8
+ * @returns Pixel indices [z, y, x]
9
+ */
10
+ export declare function worldToPixel(worldCoord: [number, number, number], ngffImage: NgffImage): [number, number, number];
11
+ /**
12
+ * Convert pixel indices to world coordinates.
13
+ *
14
+ * @param pixelCoord - Pixel indices [z, y, x]
15
+ * @param ngffImage - The NgffImage containing scale and translation
16
+ * @returns World coordinate [x, y, z]
17
+ */
18
+ export declare function pixelToWorld(pixelCoord: [number, number, number], ngffImage: NgffImage): [number, number, number];
19
+ /**
20
+ * Convert world coordinate to pixel using an affine matrix.
21
+ *
22
+ * @param worldCoord - World coordinate [x, y, z]
23
+ * @param affine - 4x4 affine matrix (pixel to world)
24
+ * @returns Pixel indices [z, y, x]
25
+ */
26
+ export declare function worldToPixelAffine(worldCoord: [number, number, number], affine: mat4): [number, number, number];
27
+ /**
28
+ * Convert pixel indices to world using an affine matrix.
29
+ *
30
+ * @param pixelCoord - Pixel indices [z, y, x]
31
+ * @param affine - 4x4 affine matrix (pixel to world)
32
+ * @returns World coordinate [x, y, z]
33
+ */
34
+ export declare function pixelToWorldAffine(pixelCoord: [number, number, number], affine: mat4): [number, number, number];
35
+ /**
36
+ * Convert normalized volume coordinates (0-1) to world coordinates.
37
+ *
38
+ * @param normalizedCoord - Normalized coordinate [x, y, z] in range 0-1
39
+ * @param ngffImage - The NgffImage
40
+ * @returns World coordinate [x, y, z]
41
+ */
42
+ export declare function normalizedToWorld(normalizedCoord: [number, number, number], ngffImage: NgffImage): [number, number, number];
43
+ /**
44
+ * Convert world coordinates to normalized volume coordinates (0-1).
45
+ *
46
+ * @param worldCoord - World coordinate [x, y, z]
47
+ * @param ngffImage - The NgffImage
48
+ * @returns Normalized coordinate [x, y, z] in range 0-1
49
+ */
50
+ export declare function worldToNormalized(worldCoord: [number, number, number], ngffImage: NgffImage): [number, number, number];
51
+ /**
52
+ * Clamp pixel coordinates to valid range for a volume.
53
+ *
54
+ * @param pixelCoord - Pixel indices [z, y, x]
55
+ * @param shape - Volume shape [z, y, x]
56
+ * @returns Clamped pixel indices [z, y, x]
57
+ */
58
+ export declare function clampPixelCoord(pixelCoord: [number, number, number], shape: [number, number, number]): [number, number, number];
59
+ /**
60
+ * Round pixel coordinates to integers.
61
+ *
62
+ * @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
63
+ * @returns Rounded pixel indices [z, y, x]
64
+ */
65
+ export declare function roundPixelCoord(pixelCoord: [number, number, number]): [number, number, number];
66
+ /**
67
+ * Floor pixel coordinates to integers (for region start).
68
+ *
69
+ * @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
70
+ * @returns Floored pixel indices [z, y, x]
71
+ */
72
+ export declare function floorPixelCoord(pixelCoord: [number, number, number]): [number, number, number];
73
+ /**
74
+ * Ceil pixel coordinates to integers (for region end).
75
+ *
76
+ * @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
77
+ * @returns Ceiled pixel indices [z, y, x]
78
+ */
79
+ export declare function ceilPixelCoord(pixelCoord: [number, number, number]): [number, number, number];
80
+ //# sourceMappingURL=coordinates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinates.d.ts","sourceRoot":"","sources":["../../src/utils/coordinates.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAQ,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,SAAS,EAAE,SAAS,GACnB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAqB1B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,SAAS,EAAE,SAAS,GACnB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAoB1B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,IAAI,GACX,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAgB1B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,IAAI,GACX,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAY1B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACzC,SAAS,EAAE,SAAS,GACnB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CA6B1B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,SAAS,EAAE,SAAS,GACnB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CA8B1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM1B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACnC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM1B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACnC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM1B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACnC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM1B"}
@@ -0,0 +1,207 @@
1
+ // SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
2
+ // SPDX-License-Identifier: MIT
3
+ import { mat4, vec4 } from "gl-matrix";
4
+ /**
5
+ * Convert a world coordinate to pixel indices.
6
+ *
7
+ * @param worldCoord - World coordinate [x, y, z]
8
+ * @param ngffImage - The NgffImage containing scale and translation
9
+ * @returns Pixel indices [z, y, x]
10
+ */
11
+ export function worldToPixel(worldCoord, ngffImage) {
12
+ const scale = ngffImage.scale;
13
+ const translation = ngffImage.translation;
14
+ // world = scale * pixel + translation
15
+ // pixel = (world - translation) / scale
16
+ const sx = scale.x ?? scale.X ?? 1;
17
+ const sy = scale.y ?? scale.Y ?? 1;
18
+ const sz = scale.z ?? scale.Z ?? 1;
19
+ const tx = translation.x ?? translation.X ?? 0;
20
+ const ty = translation.y ?? translation.Y ?? 0;
21
+ const tz = translation.z ?? translation.Z ?? 0;
22
+ const px = (worldCoord[0] - tx) / sx;
23
+ const py = (worldCoord[1] - ty) / sy;
24
+ const pz = (worldCoord[2] - tz) / sz;
25
+ // Return in [z, y, x] order to match OME-Zarr array indexing
26
+ return [pz, py, px];
27
+ }
28
+ /**
29
+ * Convert pixel indices to world coordinates.
30
+ *
31
+ * @param pixelCoord - Pixel indices [z, y, x]
32
+ * @param ngffImage - The NgffImage containing scale and translation
33
+ * @returns World coordinate [x, y, z]
34
+ */
35
+ export function pixelToWorld(pixelCoord, ngffImage) {
36
+ const scale = ngffImage.scale;
37
+ const translation = ngffImage.translation;
38
+ // world = scale * pixel + translation
39
+ const sx = scale.x ?? scale.X ?? 1;
40
+ const sy = scale.y ?? scale.Y ?? 1;
41
+ const sz = scale.z ?? scale.Z ?? 1;
42
+ const tx = translation.x ?? translation.X ?? 0;
43
+ const ty = translation.y ?? translation.Y ?? 0;
44
+ const tz = translation.z ?? translation.Z ?? 0;
45
+ // pixelCoord is [z, y, x]
46
+ const wx = sx * pixelCoord[2] + tx;
47
+ const wy = sy * pixelCoord[1] + ty;
48
+ const wz = sz * pixelCoord[0] + tz;
49
+ return [wx, wy, wz];
50
+ }
51
+ /**
52
+ * Convert world coordinate to pixel using an affine matrix.
53
+ *
54
+ * @param worldCoord - World coordinate [x, y, z]
55
+ * @param affine - 4x4 affine matrix (pixel to world)
56
+ * @returns Pixel indices [z, y, x]
57
+ */
58
+ export function worldToPixelAffine(worldCoord, affine) {
59
+ // Invert the affine to go from world to pixel
60
+ const inverseAffine = mat4.create();
61
+ mat4.invert(inverseAffine, affine);
62
+ const worldVec = vec4.fromValues(worldCoord[0], worldCoord[1], worldCoord[2], 1);
63
+ const pixelVec = vec4.create();
64
+ vec4.transformMat4(pixelVec, worldVec, inverseAffine);
65
+ // Return in [z, y, x] order
66
+ return [pixelVec[2], pixelVec[1], pixelVec[0]];
67
+ }
68
+ /**
69
+ * Convert pixel indices to world using an affine matrix.
70
+ *
71
+ * @param pixelCoord - Pixel indices [z, y, x]
72
+ * @param affine - 4x4 affine matrix (pixel to world)
73
+ * @returns World coordinate [x, y, z]
74
+ */
75
+ export function pixelToWorldAffine(pixelCoord, affine) {
76
+ // pixelCoord is [z, y, x], affine expects [x, y, z]
77
+ const pixelVec = vec4.fromValues(pixelCoord[2], // x
78
+ pixelCoord[1], // y
79
+ pixelCoord[0], // z
80
+ 1);
81
+ const worldVec = vec4.create();
82
+ vec4.transformMat4(worldVec, pixelVec, affine);
83
+ return [worldVec[0], worldVec[1], worldVec[2]];
84
+ }
85
+ /**
86
+ * Convert normalized volume coordinates (0-1) to world coordinates.
87
+ *
88
+ * @param normalizedCoord - Normalized coordinate [x, y, z] in range 0-1
89
+ * @param ngffImage - The NgffImage
90
+ * @returns World coordinate [x, y, z]
91
+ */
92
+ export function normalizedToWorld(normalizedCoord, ngffImage) {
93
+ const shape = ngffImage.data.shape;
94
+ const dims = ngffImage.dims;
95
+ // Find z, y, x indices in dims
96
+ const zIdx = dims.indexOf("z");
97
+ const yIdx = dims.indexOf("y");
98
+ const xIdx = dims.indexOf("x");
99
+ let dimX, dimY, dimZ;
100
+ if (zIdx === -1 || yIdx === -1 || xIdx === -1) {
101
+ const n = shape.length;
102
+ dimZ = shape[n - 3] || 1;
103
+ dimY = shape[n - 2] || 1;
104
+ dimX = shape[n - 1] || 1;
105
+ }
106
+ else {
107
+ dimZ = shape[zIdx];
108
+ dimY = shape[yIdx];
109
+ dimX = shape[xIdx];
110
+ }
111
+ // Convert normalized to pixel
112
+ const pixelCoord = [
113
+ normalizedCoord[2] * dimZ, // z
114
+ normalizedCoord[1] * dimY, // y
115
+ normalizedCoord[0] * dimX, // x
116
+ ];
117
+ return pixelToWorld(pixelCoord, ngffImage);
118
+ }
119
+ /**
120
+ * Convert world coordinates to normalized volume coordinates (0-1).
121
+ *
122
+ * @param worldCoord - World coordinate [x, y, z]
123
+ * @param ngffImage - The NgffImage
124
+ * @returns Normalized coordinate [x, y, z] in range 0-1
125
+ */
126
+ export function worldToNormalized(worldCoord, ngffImage) {
127
+ const shape = ngffImage.data.shape;
128
+ const dims = ngffImage.dims;
129
+ // Find z, y, x indices in dims
130
+ const zIdx = dims.indexOf("z");
131
+ const yIdx = dims.indexOf("y");
132
+ const xIdx = dims.indexOf("x");
133
+ let dimX, dimY, dimZ;
134
+ if (zIdx === -1 || yIdx === -1 || xIdx === -1) {
135
+ const n = shape.length;
136
+ dimZ = shape[n - 3] || 1;
137
+ dimY = shape[n - 2] || 1;
138
+ dimX = shape[n - 1] || 1;
139
+ }
140
+ else {
141
+ dimZ = shape[zIdx];
142
+ dimY = shape[yIdx];
143
+ dimX = shape[xIdx];
144
+ }
145
+ // Convert world to pixel
146
+ const pixelCoord = worldToPixel(worldCoord, ngffImage);
147
+ // Convert pixel to normalized
148
+ return [
149
+ pixelCoord[2] / dimX, // x normalized
150
+ pixelCoord[1] / dimY, // y normalized
151
+ pixelCoord[0] / dimZ, // z normalized
152
+ ];
153
+ }
154
+ /**
155
+ * Clamp pixel coordinates to valid range for a volume.
156
+ *
157
+ * @param pixelCoord - Pixel indices [z, y, x]
158
+ * @param shape - Volume shape [z, y, x]
159
+ * @returns Clamped pixel indices [z, y, x]
160
+ */
161
+ export function clampPixelCoord(pixelCoord, shape) {
162
+ return [
163
+ Math.max(0, Math.min(pixelCoord[0], shape[0] - 1)),
164
+ Math.max(0, Math.min(pixelCoord[1], shape[1] - 1)),
165
+ Math.max(0, Math.min(pixelCoord[2], shape[2] - 1)),
166
+ ];
167
+ }
168
+ /**
169
+ * Round pixel coordinates to integers.
170
+ *
171
+ * @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
172
+ * @returns Rounded pixel indices [z, y, x]
173
+ */
174
+ export function roundPixelCoord(pixelCoord) {
175
+ return [
176
+ Math.round(pixelCoord[0]),
177
+ Math.round(pixelCoord[1]),
178
+ Math.round(pixelCoord[2]),
179
+ ];
180
+ }
181
+ /**
182
+ * Floor pixel coordinates to integers (for region start).
183
+ *
184
+ * @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
185
+ * @returns Floored pixel indices [z, y, x]
186
+ */
187
+ export function floorPixelCoord(pixelCoord) {
188
+ return [
189
+ Math.floor(pixelCoord[0]),
190
+ Math.floor(pixelCoord[1]),
191
+ Math.floor(pixelCoord[2]),
192
+ ];
193
+ }
194
+ /**
195
+ * Ceil pixel coordinates to integers (for region end).
196
+ *
197
+ * @param pixelCoord - Pixel indices [z, y, x] (may be fractional)
198
+ * @returns Ceiled pixel indices [z, y, x]
199
+ */
200
+ export function ceilPixelCoord(pixelCoord) {
201
+ return [
202
+ Math.ceil(pixelCoord[0]),
203
+ Math.ceil(pixelCoord[1]),
204
+ Math.ceil(pixelCoord[2]),
205
+ ];
206
+ }
207
+ //# sourceMappingURL=coordinates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinates.js","sourceRoot":"","sources":["../../src/utils/coordinates.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@fideus-labs/fidnii",
3
+ "version": "0.1.0",
4
+ "description": "Render OME-Zarr images in NiiVue with progressive multi-resolution loading",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "dependencies": {
19
+ "@fideus-labs/ngff-zarr": "^0.7.2",
20
+ "@itk-wasm/downsample": "^1.8.1",
21
+ "lru-cache": "^11.1.0",
22
+ "@niivue/niivue": "^0.67.0",
23
+ "gl-matrix": "^3.4.4",
24
+ "nifti-reader-js": "^0.8.0",
25
+ "zarrita": "^0.6.1",
26
+ "zod": "^3.25.76"
27
+ },
28
+ "devDependencies": {
29
+ "@fideus-labs/fizarrita": "^1.2.0",
30
+ "@fideus-labs/worker-pool": "^1.0.0",
31
+ "@playwright/test": "^1.58.1",
32
+ "@types/node": "^20.19.30",
33
+ "comlink": "^4.4.2",
34
+ "fflate": "^0.8.2",
35
+ "typescript": "^5.9.3",
36
+ "vite": "^5.4.21"
37
+ },
38
+ "peerDependencies": {
39
+ "@niivue/niivue": ">=0.67.0"
40
+ },
41
+ "keywords": [
42
+ "niivue",
43
+ "ome-zarr",
44
+ "ngff",
45
+ "medical-imaging",
46
+ "webgl"
47
+ ],
48
+ "author": "Fideus Labs LLC",
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/fideus-labs/fidnii.git"
53
+ },
54
+ "scripts": {
55
+ "build": "tsc",
56
+ "dev": "vite",
57
+ "preview": "vite preview",
58
+ "test": "playwright test",
59
+ "test:ui": "playwright test --ui"
60
+ }
61
+ }