@fideus-labs/ngff-zarr 0.0.1 → 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.
- package/README.md +9 -2
- package/esm/io/from_ngff_zarr.d.ts +4 -1
- package/esm/io/from_ngff_zarr.d.ts.map +1 -1
- package/esm/io/from_ngff_zarr.js +94 -27
- package/esm/io/hcs.d.ts +18 -0
- package/esm/io/hcs.d.ts.map +1 -0
- package/esm/io/hcs.js +51 -0
- package/esm/io/itk_image_to_ngff_image.d.ts +25 -0
- package/esm/io/itk_image_to_ngff_image.d.ts.map +1 -0
- package/esm/io/itk_image_to_ngff_image.js +127 -0
- package/esm/io/ngff_image_to_itk_image.d.ts +30 -0
- package/esm/io/ngff_image_to_itk_image.d.ts.map +1 -0
- package/esm/io/ngff_image_to_itk_image.js +216 -0
- package/esm/io/to_multiscales.d.ts +18 -0
- package/esm/io/to_multiscales.d.ts.map +1 -0
- package/esm/io/to_multiscales.js +62 -0
- package/esm/io/to_ngff_image.d.ts +17 -0
- package/esm/io/to_ngff_image.d.ts.map +1 -0
- package/esm/io/to_ngff_image.js +136 -0
- package/esm/io/to_ngff_zarr.d.ts +3 -2
- package/esm/io/to_ngff_zarr.d.ts.map +1 -1
- package/esm/io/to_ngff_zarr.js +273 -26
- package/esm/methods/itkwasm.d.ts +6 -0
- package/esm/methods/itkwasm.d.ts.map +1 -0
- package/esm/methods/itkwasm.js +816 -0
- package/esm/mod.d.ts +9 -2
- package/esm/mod.d.ts.map +1 -1
- package/esm/mod.js +10 -2
- package/esm/schemas/coordinate_systems.d.ts +644 -0
- package/esm/schemas/coordinate_systems.d.ts.map +1 -0
- package/esm/schemas/coordinate_systems.js +140 -0
- package/esm/schemas/index.d.ts +9 -0
- package/esm/schemas/index.d.ts.map +1 -0
- package/esm/schemas/index.js +38 -0
- package/esm/schemas/methods.d.ts.map +1 -1
- package/esm/schemas/methods.js +2 -0
- package/esm/schemas/multiscales.d.ts.map +1 -1
- package/esm/schemas/multiscales.js +2 -0
- package/esm/schemas/ngff_image.d.ts +9 -2
- package/esm/schemas/ngff_image.d.ts.map +1 -1
- package/esm/schemas/ngff_image.js +11 -2
- package/esm/schemas/ome_zarr.d.ts +581 -0
- package/esm/schemas/ome_zarr.d.ts.map +1 -0
- package/esm/schemas/ome_zarr.js +208 -0
- package/esm/schemas/rfc4.d.ts +439 -0
- package/esm/schemas/rfc4.d.ts.map +1 -0
- package/esm/schemas/rfc4.js +129 -0
- package/esm/schemas/units.d.ts.map +1 -1
- package/esm/schemas/units.js +5 -0
- package/esm/schemas/zarr_metadata.d.ts +302 -9
- package/esm/schemas/zarr_metadata.d.ts.map +1 -1
- package/esm/schemas/zarr_metadata.js +22 -1
- package/esm/types/array_interface.d.ts +7 -0
- package/esm/types/array_interface.d.ts.map +1 -0
- package/esm/types/array_interface.js +1 -0
- package/esm/types/hcs.d.ts +70 -0
- package/esm/types/hcs.d.ts.map +1 -0
- package/esm/types/hcs.js +204 -0
- package/esm/types/methods.d.ts.map +1 -1
- package/esm/types/methods.js +2 -0
- package/esm/types/multiscales.d.ts.map +1 -1
- package/esm/types/ngff_image.d.ts +6 -3
- package/esm/types/ngff_image.d.ts.map +1 -1
- package/esm/types/ngff_image.js +13 -1
- package/esm/types/rfc4.d.ts +94 -0
- package/esm/types/rfc4.d.ts.map +1 -0
- package/esm/types/rfc4.js +135 -0
- package/esm/types/units.d.ts +1 -1
- package/esm/types/units.d.ts.map +1 -1
- package/esm/types/zarr_metadata.d.ts +14 -5
- package/esm/types/zarr_metadata.d.ts.map +1 -1
- package/esm/utils/create_queue.d.ts +6 -0
- package/esm/utils/create_queue.d.ts.map +1 -0
- package/esm/utils/create_queue.js +11 -0
- package/esm/utils/factory.d.ts +1 -1
- package/esm/utils/factory.d.ts.map +1 -1
- package/esm/utils/factory.js +16 -7
- package/esm/utils/method_metadata.d.ts +10 -0
- package/esm/utils/method_metadata.d.ts.map +1 -0
- package/esm/utils/method_metadata.js +37 -0
- package/esm/utils/validation.d.ts.map +1 -1
- package/package.json +7 -1
- package/script/io/from_ngff_zarr.d.ts +4 -1
- package/script/io/from_ngff_zarr.d.ts.map +1 -1
- package/script/io/from_ngff_zarr.js +94 -27
- package/script/io/hcs.d.ts +18 -0
- package/script/io/hcs.d.ts.map +1 -0
- package/script/io/hcs.js +55 -0
- package/script/io/itk_image_to_ngff_image.d.ts +25 -0
- package/script/io/itk_image_to_ngff_image.d.ts.map +1 -0
- package/script/io/itk_image_to_ngff_image.js +153 -0
- package/script/io/ngff_image_to_itk_image.d.ts +30 -0
- package/script/io/ngff_image_to_itk_image.d.ts.map +1 -0
- package/script/io/ngff_image_to_itk_image.js +242 -0
- package/script/io/to_multiscales.d.ts +18 -0
- package/script/io/to_multiscales.d.ts.map +1 -0
- package/script/io/to_multiscales.js +67 -0
- package/script/io/to_ngff_image.d.ts +17 -0
- package/script/io/to_ngff_image.d.ts.map +1 -0
- package/script/io/to_ngff_image.js +162 -0
- package/script/io/to_ngff_zarr.d.ts +3 -2
- package/script/io/to_ngff_zarr.d.ts.map +1 -1
- package/script/io/to_ngff_zarr.js +273 -26
- package/script/methods/itkwasm.d.ts +6 -0
- package/script/methods/itkwasm.d.ts.map +1 -0
- package/script/methods/itkwasm.js +842 -0
- package/script/mod.d.ts +9 -2
- package/script/mod.d.ts.map +1 -1
- package/script/mod.js +12 -3
- package/script/schemas/coordinate_systems.d.ts +644 -0
- package/script/schemas/coordinate_systems.d.ts.map +1 -0
- package/script/schemas/coordinate_systems.js +143 -0
- package/script/schemas/index.d.ts +9 -0
- package/script/schemas/index.d.ts.map +1 -0
- package/script/schemas/index.js +101 -0
- package/script/schemas/methods.d.ts.map +1 -1
- package/script/schemas/methods.js +2 -0
- package/script/schemas/multiscales.d.ts.map +1 -1
- package/script/schemas/multiscales.js +2 -0
- package/script/schemas/ngff_image.d.ts +9 -2
- package/script/schemas/ngff_image.d.ts.map +1 -1
- package/script/schemas/ngff_image.js +11 -2
- package/script/schemas/ome_zarr.d.ts +581 -0
- package/script/schemas/ome_zarr.d.ts.map +1 -0
- package/script/schemas/ome_zarr.js +211 -0
- package/script/schemas/rfc4.d.ts +439 -0
- package/script/schemas/rfc4.d.ts.map +1 -0
- package/script/schemas/rfc4.js +132 -0
- package/script/schemas/units.d.ts.map +1 -1
- package/script/schemas/units.js +5 -0
- package/script/schemas/zarr_metadata.d.ts +302 -9
- package/script/schemas/zarr_metadata.d.ts.map +1 -1
- package/script/schemas/zarr_metadata.js +23 -2
- package/script/types/array_interface.d.ts +7 -0
- package/script/types/array_interface.d.ts.map +1 -0
- package/script/types/array_interface.js +2 -0
- package/script/types/hcs.d.ts +70 -0
- package/script/types/hcs.d.ts.map +1 -0
- package/script/types/hcs.js +233 -0
- package/script/types/methods.d.ts.map +1 -1
- package/script/types/methods.js +2 -0
- package/script/types/multiscales.d.ts.map +1 -1
- package/script/types/ngff_image.d.ts +6 -3
- package/script/types/ngff_image.d.ts.map +1 -1
- package/script/types/ngff_image.js +13 -1
- package/script/types/rfc4.d.ts +94 -0
- package/script/types/rfc4.d.ts.map +1 -0
- package/script/types/rfc4.js +143 -0
- package/script/types/units.d.ts +1 -1
- package/script/types/units.d.ts.map +1 -1
- package/script/types/zarr_metadata.d.ts +14 -5
- package/script/types/zarr_metadata.d.ts.map +1 -1
- package/script/utils/create_queue.d.ts +6 -0
- package/script/utils/create_queue.d.ts.map +1 -0
- package/script/utils/create_queue.js +17 -0
- package/script/utils/factory.d.ts +1 -1
- package/script/utils/factory.d.ts.map +1 -1
- package/script/utils/factory.js +39 -7
- package/script/utils/method_metadata.d.ts +10 -0
- package/script/utils/method_metadata.d.ts.map +1 -0
- package/script/utils/method_metadata.js +40 -0
- package/script/utils/validation.d.ts.map +1 -1
- package/esm/schemas/lazy_array.d.ts +0 -8
- package/esm/schemas/lazy_array.d.ts.map +0 -1
- package/esm/schemas/lazy_array.js +0 -7
- package/esm/types/lazy_array.d.ts +0 -18
- package/esm/types/lazy_array.d.ts.map +0 -1
- package/esm/types/lazy_array.js +0 -27
- package/script/schemas/lazy_array.d.ts +0 -8
- package/script/schemas/lazy_array.d.ts.map +0 -1
- package/script/schemas/lazy_array.js +0 -10
- package/script/types/lazy_array.d.ts +0 -18
- package/script/types/lazy_array.d.ts.map +0 -1
- package/script/types/lazy_array.js +0 -31
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* Convert NgffImage to ITK-Wasm Image
|
|
5
|
+
*/
|
|
6
|
+
import * as zarr from "zarrita";
|
|
7
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
8
|
+
/**
|
|
9
|
+
* Convert the data type from zarr DataType to ITK-Wasm component type
|
|
10
|
+
*/
|
|
11
|
+
function dataTypeToComponentType(dataType) {
|
|
12
|
+
switch (dataType) {
|
|
13
|
+
case "uint8":
|
|
14
|
+
return "uint8";
|
|
15
|
+
case "int8":
|
|
16
|
+
return "int8";
|
|
17
|
+
case "uint16":
|
|
18
|
+
return "uint16";
|
|
19
|
+
case "int16":
|
|
20
|
+
return "int16";
|
|
21
|
+
case "uint32":
|
|
22
|
+
return "uint32";
|
|
23
|
+
case "int32":
|
|
24
|
+
return "int32";
|
|
25
|
+
case "uint64":
|
|
26
|
+
return "uint64";
|
|
27
|
+
case "int64":
|
|
28
|
+
return "int64";
|
|
29
|
+
case "float32":
|
|
30
|
+
return "float32";
|
|
31
|
+
case "float64":
|
|
32
|
+
return "float64";
|
|
33
|
+
default:
|
|
34
|
+
throw new Error(`Unsupported data type: ${dataType}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Move the channel dimension to the end (last position) if it exists
|
|
39
|
+
* This follows the ITK convention where vector/RGB components are the last dimension
|
|
40
|
+
*/
|
|
41
|
+
function moveChannelDimToLast(ngffImage) {
|
|
42
|
+
const dims = ngffImage.dims;
|
|
43
|
+
const cIndex = dims.indexOf("c");
|
|
44
|
+
if (cIndex === -1 || cIndex === dims.length - 1) {
|
|
45
|
+
// No channel dimension or already at the end
|
|
46
|
+
return ngffImage;
|
|
47
|
+
}
|
|
48
|
+
// Reorder dimensions to move 'c' to the end
|
|
49
|
+
const newDims = [...dims];
|
|
50
|
+
const cDim = newDims.splice(cIndex, 1)[0];
|
|
51
|
+
newDims.push(cDim);
|
|
52
|
+
// Note: We would need to transpose the zarr array data here
|
|
53
|
+
// For now, we'll assume the data is already in the correct order
|
|
54
|
+
// In a full implementation, you'd transpose the zarr array
|
|
55
|
+
return new NgffImage({
|
|
56
|
+
data: ngffImage.data, // TODO: transpose if needed
|
|
57
|
+
dims: newDims,
|
|
58
|
+
scale: ngffImage.scale,
|
|
59
|
+
translation: ngffImage.translation,
|
|
60
|
+
name: ngffImage.name,
|
|
61
|
+
axesUnits: ngffImage.axesUnits,
|
|
62
|
+
axesOrientations: ngffImage.axesOrientations,
|
|
63
|
+
computedCallbacks: ngffImage.computedCallbacks,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Convert an NgffImage to an ITK-Wasm Image, preserving spatial metadata.
|
|
68
|
+
*
|
|
69
|
+
* This function converts NgffImage objects to ITK-Wasm Image format while
|
|
70
|
+
* preserving spatial information like spacing, origin, and direction matrix.
|
|
71
|
+
* Optionally extracts specific time or channel slices.
|
|
72
|
+
*
|
|
73
|
+
* @param ngffImage - The NgffImage to convert
|
|
74
|
+
* @param options - Conversion options
|
|
75
|
+
* @returns Promise resolving to ITK-Wasm Image
|
|
76
|
+
*/
|
|
77
|
+
export async function ngffImageToItkImage(ngffImage, options = {}) {
|
|
78
|
+
const { tIndex, cIndex } = options;
|
|
79
|
+
let workingImage = ngffImage;
|
|
80
|
+
// Extract time slice if requested
|
|
81
|
+
if (tIndex !== undefined && workingImage.dims.includes("t")) {
|
|
82
|
+
const tDimIndex = workingImage.dims.indexOf("t");
|
|
83
|
+
const newDims = workingImage.dims.filter((dim) => dim !== "t");
|
|
84
|
+
const newScale = Object.fromEntries(Object.entries(workingImage.scale).filter(([dim]) => dim !== "t"));
|
|
85
|
+
const newTranslation = Object.fromEntries(Object.entries(workingImage.translation).filter(([dim]) => dim !== "t"));
|
|
86
|
+
// Extract the time slice from zarr array
|
|
87
|
+
const selection = new Array(workingImage.data.shape.length).fill(null);
|
|
88
|
+
selection[tDimIndex] = tIndex;
|
|
89
|
+
const sliceData = await zarr.get(workingImage.data, selection);
|
|
90
|
+
// Create new zarr array with reduced dimensions
|
|
91
|
+
const store = new Map();
|
|
92
|
+
const root = zarr.root(store);
|
|
93
|
+
const newShape = workingImage.data.shape.filter((_, i) => i !== tDimIndex);
|
|
94
|
+
const chunkShape = newShape.map((s) => Math.min(s, 256));
|
|
95
|
+
const newArray = await zarr.create(root.resolve("slice"), {
|
|
96
|
+
shape: newShape,
|
|
97
|
+
chunk_shape: chunkShape,
|
|
98
|
+
data_type: workingImage.data.dtype,
|
|
99
|
+
fill_value: 0,
|
|
100
|
+
});
|
|
101
|
+
// Write the slice data
|
|
102
|
+
const fullSelection = new Array(newShape.length).fill(null);
|
|
103
|
+
await zarr.set(newArray, fullSelection, sliceData);
|
|
104
|
+
workingImage = new NgffImage({
|
|
105
|
+
data: newArray,
|
|
106
|
+
dims: newDims,
|
|
107
|
+
scale: newScale,
|
|
108
|
+
translation: newTranslation,
|
|
109
|
+
name: workingImage.name,
|
|
110
|
+
axesUnits: workingImage.axesUnits
|
|
111
|
+
? Object.fromEntries(Object.entries(workingImage.axesUnits).filter(([dim]) => dim !== "t"))
|
|
112
|
+
: undefined,
|
|
113
|
+
axesOrientations: workingImage.axesOrientations
|
|
114
|
+
? Object.fromEntries(Object.entries(workingImage.axesOrientations).filter(([dim]) => dim !== "t"))
|
|
115
|
+
: undefined,
|
|
116
|
+
computedCallbacks: workingImage.computedCallbacks,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// Extract channel slice if requested
|
|
120
|
+
if (cIndex !== undefined && workingImage.dims.includes("c")) {
|
|
121
|
+
const cDimIndex = workingImage.dims.indexOf("c");
|
|
122
|
+
const newDims = workingImage.dims.filter((dim) => dim !== "c");
|
|
123
|
+
const newScale = Object.fromEntries(Object.entries(workingImage.scale).filter(([dim]) => dim !== "c"));
|
|
124
|
+
const newTranslation = Object.fromEntries(Object.entries(workingImage.translation).filter(([dim]) => dim !== "c"));
|
|
125
|
+
// Extract the channel slice from zarr array
|
|
126
|
+
const selection = new Array(workingImage.data.shape.length).fill(null);
|
|
127
|
+
selection[cDimIndex] = cIndex;
|
|
128
|
+
const sliceData = await zarr.get(workingImage.data, selection);
|
|
129
|
+
// Create new zarr array with reduced dimensions
|
|
130
|
+
const store = new Map();
|
|
131
|
+
const root = zarr.root(store);
|
|
132
|
+
const newShape = workingImage.data.shape.filter((_, i) => i !== cDimIndex);
|
|
133
|
+
const chunkShape = newShape.map((s) => Math.min(s, 256));
|
|
134
|
+
const newArray = await zarr.create(root.resolve("slice"), {
|
|
135
|
+
shape: newShape,
|
|
136
|
+
chunk_shape: chunkShape,
|
|
137
|
+
data_type: workingImage.data.dtype,
|
|
138
|
+
fill_value: 0,
|
|
139
|
+
});
|
|
140
|
+
// Write the slice data
|
|
141
|
+
const fullSelection = new Array(newShape.length).fill(null);
|
|
142
|
+
await zarr.set(newArray, fullSelection, sliceData);
|
|
143
|
+
workingImage = new NgffImage({
|
|
144
|
+
data: newArray,
|
|
145
|
+
dims: newDims,
|
|
146
|
+
scale: newScale,
|
|
147
|
+
translation: newTranslation,
|
|
148
|
+
name: workingImage.name,
|
|
149
|
+
axesUnits: workingImage.axesUnits
|
|
150
|
+
? Object.fromEntries(Object.entries(workingImage.axesUnits).filter(([dim]) => dim !== "c"))
|
|
151
|
+
: undefined,
|
|
152
|
+
axesOrientations: workingImage.axesOrientations
|
|
153
|
+
? Object.fromEntries(Object.entries(workingImage.axesOrientations).filter(([dim]) => dim !== "c"))
|
|
154
|
+
: undefined,
|
|
155
|
+
computedCallbacks: workingImage.computedCallbacks,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// Move channel dimension to last position (ITK convention)
|
|
159
|
+
workingImage = moveChannelDimToLast(workingImage);
|
|
160
|
+
const dims = workingImage.dims;
|
|
161
|
+
const data = workingImage.data;
|
|
162
|
+
// Identify ITK spatial dimensions
|
|
163
|
+
const itkDimensionNames = new Set(["x", "y", "z", "t"]);
|
|
164
|
+
const itkDims = dims.filter((dim) => itkDimensionNames.has(dim));
|
|
165
|
+
// Sort ITK dimensions: spatial first (x, y, z), then time
|
|
166
|
+
const sortedItkDims = itkDims.sort((a, b) => {
|
|
167
|
+
const order = ["x", "y", "z", "t"];
|
|
168
|
+
return order.indexOf(a) - order.indexOf(b);
|
|
169
|
+
});
|
|
170
|
+
// Create ITK spacing, origin, and size arrays
|
|
171
|
+
const spacing = sortedItkDims.map((dim) => workingImage.scale[dim] || 1.0);
|
|
172
|
+
const origin = sortedItkDims.map((dim) => workingImage.translation[dim] || 0.0);
|
|
173
|
+
const size = sortedItkDims.map((dim) => data.shape[dims.indexOf(dim)]);
|
|
174
|
+
const dimension = sortedItkDims.length;
|
|
175
|
+
// Determine component type and pixel type
|
|
176
|
+
const componentType = dataTypeToComponentType(data.dtype);
|
|
177
|
+
let components = 1;
|
|
178
|
+
let pixelType = "Scalar";
|
|
179
|
+
if (dims.includes("c")) {
|
|
180
|
+
components = data.shape[dims.indexOf("c")];
|
|
181
|
+
if (components === 3 && componentType === "uint8") {
|
|
182
|
+
pixelType = "RGB";
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
pixelType =
|
|
186
|
+
"VariableLengthVector";
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Create ImageType
|
|
190
|
+
const imageType = {
|
|
191
|
+
dimension,
|
|
192
|
+
componentType,
|
|
193
|
+
pixelType,
|
|
194
|
+
components,
|
|
195
|
+
};
|
|
196
|
+
// Read all data from zarr array
|
|
197
|
+
const selection = new Array(data.shape.length).fill(null);
|
|
198
|
+
const dataChunk = await zarr.get(data, selection);
|
|
199
|
+
// Create direction matrix (identity for now)
|
|
200
|
+
const direction = new Float64Array(dimension * dimension);
|
|
201
|
+
for (let i = 0; i < dimension; i++) {
|
|
202
|
+
direction[i * dimension + i] = 1.0;
|
|
203
|
+
}
|
|
204
|
+
// Create ITK-Wasm Image
|
|
205
|
+
const itkImage = {
|
|
206
|
+
imageType,
|
|
207
|
+
name: workingImage.name || "image",
|
|
208
|
+
origin,
|
|
209
|
+
spacing,
|
|
210
|
+
direction,
|
|
211
|
+
size,
|
|
212
|
+
metadata: new Map(),
|
|
213
|
+
data: dataChunk.data, // Cast to handle zarrita's data type
|
|
214
|
+
};
|
|
215
|
+
return itkImage;
|
|
216
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
2
|
+
import { Multiscales } from "../types/multiscales.js";
|
|
3
|
+
import { Methods } from "../types/methods.js";
|
|
4
|
+
export { toNgffImage, type ToNgffImageOptions } from "./to_ngff_image.js";
|
|
5
|
+
export interface ToMultiscalesOptions {
|
|
6
|
+
scaleFactors?: (Record<string, number> | number)[];
|
|
7
|
+
method?: Methods;
|
|
8
|
+
chunks?: number | number[] | Record<string, number>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generate multiple resolution scales for an NgffImage (simplified version for testing)
|
|
12
|
+
*
|
|
13
|
+
* @param image - Input NgffImage
|
|
14
|
+
* @param options - Configuration options
|
|
15
|
+
* @returns Multiscales object
|
|
16
|
+
*/
|
|
17
|
+
export declare function toMultiscales(image: NgffImage, options?: ToMultiscalesOptions): Promise<Multiscales>;
|
|
18
|
+
//# sourceMappingURL=to_multiscales.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to_multiscales.d.ts","sourceRoot":"","sources":["../../src/io/to_multiscales.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAW9C,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE1E,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;IACnD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrD;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,WAAW,CAAC,CAqEtB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Methods } from "../types/methods.js";
|
|
2
|
+
import { createAxis, createDataset, createMetadata, createMultiscales, } from "../utils/factory.js";
|
|
3
|
+
import { getMethodMetadata } from "../utils/method_metadata.js";
|
|
4
|
+
import { downsampleItkWasm } from "../methods/itkwasm.js";
|
|
5
|
+
// Re-export for convenience
|
|
6
|
+
export { toNgffImage } from "./to_ngff_image.js";
|
|
7
|
+
/**
|
|
8
|
+
* Generate multiple resolution scales for an NgffImage (simplified version for testing)
|
|
9
|
+
*
|
|
10
|
+
* @param image - Input NgffImage
|
|
11
|
+
* @param options - Configuration options
|
|
12
|
+
* @returns Multiscales object
|
|
13
|
+
*/
|
|
14
|
+
export async function toMultiscales(image, options = {}) {
|
|
15
|
+
const { scaleFactors = [2, 4], method = Methods.ITKWASM_GAUSSIAN, chunks: _chunks, } = options;
|
|
16
|
+
let images;
|
|
17
|
+
// Check if we should perform actual downsampling
|
|
18
|
+
if (method === Methods.ITKWASM_GAUSSIAN ||
|
|
19
|
+
method === Methods.ITKWASM_BIN_SHRINK ||
|
|
20
|
+
method === Methods.ITKWASM_LABEL_IMAGE) {
|
|
21
|
+
// Perform actual downsampling using ITK-Wasm
|
|
22
|
+
const smoothing = method === Methods.ITKWASM_GAUSSIAN
|
|
23
|
+
? "gaussian"
|
|
24
|
+
: method === Methods.ITKWASM_BIN_SHRINK
|
|
25
|
+
? "bin_shrink"
|
|
26
|
+
: "label_image";
|
|
27
|
+
images = await downsampleItkWasm(image, scaleFactors, smoothing);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Fallback: create only the base image (no actual downsampling)
|
|
31
|
+
images = [image];
|
|
32
|
+
}
|
|
33
|
+
// Create axes from image dimensions
|
|
34
|
+
const axes = image.dims.map((dim) => {
|
|
35
|
+
if (dim === "x" || dim === "y" || dim === "z") {
|
|
36
|
+
return createAxis(dim, "space", image.axesUnits?.[dim]);
|
|
37
|
+
}
|
|
38
|
+
else if (dim === "c") {
|
|
39
|
+
return createAxis(dim, "channel");
|
|
40
|
+
}
|
|
41
|
+
else if (dim === "t") {
|
|
42
|
+
return createAxis(dim, "time");
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
throw new Error(`Unsupported dimension: ${dim}`);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
// Create datasets for all images
|
|
49
|
+
const datasets = images.map((img, index) => {
|
|
50
|
+
return createDataset(`${index}`, img.dims.map((dim) => img.scale[dim]), img.dims.map((dim) => img.translation[dim]));
|
|
51
|
+
});
|
|
52
|
+
// Create metadata with method information
|
|
53
|
+
const methodMetadata = getMethodMetadata(method);
|
|
54
|
+
const metadata = createMetadata(axes, datasets, image.name);
|
|
55
|
+
// The 'type' field, part of the OME-Zarr specification, in metadata is used here to
|
|
56
|
+
// record the downsampling method applied to generate multiscale images for provenance.
|
|
57
|
+
metadata.type = method;
|
|
58
|
+
if (methodMetadata) {
|
|
59
|
+
metadata.metadata = methodMetadata;
|
|
60
|
+
}
|
|
61
|
+
return createMultiscales(images, metadata, scaleFactors, method);
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
2
|
+
export interface ToNgffImageOptions {
|
|
3
|
+
dims?: string[];
|
|
4
|
+
scale?: Record<string, number>;
|
|
5
|
+
translation?: Record<string, number>;
|
|
6
|
+
name?: string;
|
|
7
|
+
shape?: number[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Convert array data to NgffImage
|
|
11
|
+
*
|
|
12
|
+
* @param data - Input data as typed array or regular array
|
|
13
|
+
* @param options - Configuration options for NgffImage creation
|
|
14
|
+
* @returns NgffImage instance
|
|
15
|
+
*/
|
|
16
|
+
export declare function toNgffImage(data: ArrayLike<number> | number[][] | number[][][], options?: ToNgffImageOptions): Promise<NgffImage>;
|
|
17
|
+
//# sourceMappingURL=to_ngff_image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to_ngff_image.d.ts","sourceRoot":"","sources":["../../src/io/to_ngff_image.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,EACnD,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,SAAS,CAAC,CAqIpB"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as zarr from "zarrita";
|
|
2
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
3
|
+
/**
|
|
4
|
+
* Convert array data to NgffImage
|
|
5
|
+
*
|
|
6
|
+
* @param data - Input data as typed array or regular array
|
|
7
|
+
* @param options - Configuration options for NgffImage creation
|
|
8
|
+
* @returns NgffImage instance
|
|
9
|
+
*/
|
|
10
|
+
export async function toNgffImage(data, options = {}) {
|
|
11
|
+
const { dims = ["y", "x"], scale = {}, translation = {}, name = "image", shape: explicitShape, } = options;
|
|
12
|
+
// Determine data shape and create typed array
|
|
13
|
+
let typedData;
|
|
14
|
+
let shape;
|
|
15
|
+
if (Array.isArray(data)) {
|
|
16
|
+
// Handle multi-dimensional arrays
|
|
17
|
+
if (Array.isArray(data[0])) {
|
|
18
|
+
if (Array.isArray(data[0][0])) {
|
|
19
|
+
// 3D array
|
|
20
|
+
const d3 = data;
|
|
21
|
+
shape = [d3.length, d3[0].length, d3[0][0].length];
|
|
22
|
+
typedData = new Float32Array(shape[0] * shape[1] * shape[2]);
|
|
23
|
+
let idx = 0;
|
|
24
|
+
for (let i = 0; i < shape[0]; i++) {
|
|
25
|
+
for (let j = 0; j < shape[1]; j++) {
|
|
26
|
+
for (let k = 0; k < shape[2]; k++) {
|
|
27
|
+
typedData[idx++] = d3[i][j][k];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// 2D array
|
|
34
|
+
const d2 = data;
|
|
35
|
+
shape = [d2.length, d2[0].length];
|
|
36
|
+
typedData = new Float32Array(shape[0] * shape[1]);
|
|
37
|
+
let idx = 0;
|
|
38
|
+
for (let i = 0; i < shape[0]; i++) {
|
|
39
|
+
for (let j = 0; j < shape[1]; j++) {
|
|
40
|
+
typedData[idx++] = d2[i][j];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// 1D array
|
|
47
|
+
const d1 = data;
|
|
48
|
+
shape = [d1.length];
|
|
49
|
+
typedData = new Float32Array(d1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// ArrayLike (already a typed array)
|
|
54
|
+
// Use explicit shape if provided, otherwise infer from data length and dims
|
|
55
|
+
if (explicitShape) {
|
|
56
|
+
shape = [...explicitShape];
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Try to infer shape - this is a best guess
|
|
60
|
+
shape = [data.length];
|
|
61
|
+
}
|
|
62
|
+
// Preserve the original typed array type
|
|
63
|
+
if (data instanceof Uint8Array) {
|
|
64
|
+
typedData = data;
|
|
65
|
+
}
|
|
66
|
+
else if (data instanceof Uint16Array) {
|
|
67
|
+
typedData = data;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
typedData = new Float32Array(data);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Adjust shape to match dims length if not explicitly provided
|
|
74
|
+
if (!explicitShape) {
|
|
75
|
+
while (shape.length < dims.length) {
|
|
76
|
+
shape.unshift(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (shape.length !== dims.length) {
|
|
80
|
+
throw new Error(`Shape dimensionality (${shape.length}) must match dims length (${dims.length})`);
|
|
81
|
+
}
|
|
82
|
+
// Create in-memory zarr store and array
|
|
83
|
+
const store = new Map();
|
|
84
|
+
const root = zarr.root(store);
|
|
85
|
+
// Calculate appropriate chunk size
|
|
86
|
+
const chunkShape = shape.map((dim) => Math.min(dim, 256));
|
|
87
|
+
const zarrArray = await zarr.create(root.resolve("data"), {
|
|
88
|
+
shape,
|
|
89
|
+
chunk_shape: chunkShape,
|
|
90
|
+
data_type: "float32",
|
|
91
|
+
fill_value: 0,
|
|
92
|
+
});
|
|
93
|
+
// Write data to zarr array
|
|
94
|
+
await zarr.set(zarrArray, [], {
|
|
95
|
+
data: typedData,
|
|
96
|
+
shape,
|
|
97
|
+
stride: calculateStride(shape),
|
|
98
|
+
});
|
|
99
|
+
// Create scale and translation records with defaults
|
|
100
|
+
const fullScale = {};
|
|
101
|
+
const fullTranslation = {};
|
|
102
|
+
const spatialDims = new Set(["x", "y", "z"]);
|
|
103
|
+
for (const dim of dims) {
|
|
104
|
+
// Only set defaults for spatial dimensions
|
|
105
|
+
if (spatialDims.has(dim)) {
|
|
106
|
+
fullScale[dim] = scale[dim] ?? 1.0;
|
|
107
|
+
fullTranslation[dim] = translation[dim] ?? 0.0;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// For non-spatial dimensions, only include if explicitly provided
|
|
111
|
+
if (scale[dim] !== undefined) {
|
|
112
|
+
fullScale[dim] = scale[dim];
|
|
113
|
+
}
|
|
114
|
+
if (translation[dim] !== undefined) {
|
|
115
|
+
fullTranslation[dim] = translation[dim];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return new NgffImage({
|
|
120
|
+
data: zarrArray,
|
|
121
|
+
dims,
|
|
122
|
+
scale: fullScale,
|
|
123
|
+
translation: fullTranslation,
|
|
124
|
+
name,
|
|
125
|
+
axesUnits: undefined,
|
|
126
|
+
computedCallbacks: undefined,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function calculateStride(shape) {
|
|
130
|
+
const stride = new Array(shape.length);
|
|
131
|
+
stride[shape.length - 1] = 1;
|
|
132
|
+
for (let i = shape.length - 2; i >= 0; i--) {
|
|
133
|
+
stride[i] = stride[i + 1] * shape[i + 1];
|
|
134
|
+
}
|
|
135
|
+
return stride;
|
|
136
|
+
}
|
package/esm/io/to_ngff_zarr.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import * as zarr from "zarrita";
|
|
1
2
|
import type { Multiscales } from "../types/multiscales.js";
|
|
3
|
+
import type { MemoryStore } from "./from_ngff_zarr.js";
|
|
2
4
|
export interface ToNgffZarrOptions {
|
|
3
5
|
overwrite?: boolean;
|
|
4
6
|
version?: "0.4" | "0.5";
|
|
5
|
-
useTensorstore?: boolean;
|
|
6
7
|
chunksPerShard?: number | number[] | Record<string, number>;
|
|
7
8
|
}
|
|
8
|
-
export declare function toNgffZarr(
|
|
9
|
+
export declare function toNgffZarr(store: string | MemoryStore | zarr.FetchStore, multiscales: Multiscales, options?: ToNgffZarrOptions): Promise<void>;
|
|
9
10
|
//# sourceMappingURL=to_ngff_zarr.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to_ngff_zarr.d.ts","sourceRoot":"","sources":["../../src/io/to_ngff_zarr.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"to_ngff_zarr.d.ts","sourceRoot":"","sources":["../../src/io/to_ngff_zarr.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7D;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC,UAAU,EAC7C,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA0Ff"}
|