@fideus-labs/ngff-zarr 0.0.1 → 0.2.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 +10 -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 +30 -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 +218 -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 +289 -26
- package/esm/methods/itkwasm.d.ts +6 -0
- package/esm/methods/itkwasm.d.ts.map +1 -0
- package/esm/methods/itkwasm.js +958 -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 +251 -0
- package/esm/schemas/coordinate_systems.d.ts.map +1 -0
- package/esm/schemas/coordinate_systems.js +139 -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 +617 -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 +334 -0
- package/esm/schemas/rfc4.d.ts.map +1 -0
- package/esm/schemas/rfc4.js +129 -0
- package/esm/schemas/units.d.ts +70 -5
- package/esm/schemas/units.d.ts.map +1 -1
- package/esm/schemas/units.js +4 -12
- package/esm/schemas/zarr_metadata.d.ts +10 -4
- 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 +30 -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 +244 -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 +289 -26
- package/script/methods/itkwasm.d.ts +6 -0
- package/script/methods/itkwasm.d.ts.map +1 -0
- package/script/methods/itkwasm.js +984 -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 +251 -0
- package/script/schemas/coordinate_systems.d.ts.map +1 -0
- package/script/schemas/coordinate_systems.js +142 -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 +617 -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 +334 -0
- package/script/schemas/rfc4.d.ts.map +1 -0
- package/script/schemas/rfc4.js +132 -0
- package/script/schemas/units.d.ts +70 -5
- package/script/schemas/units.d.ts.map +1 -1
- package/script/schemas/units.js +4 -12
- package/script/schemas/zarr_metadata.d.ts +10 -4
- 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
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
<!-- SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC -->
|
|
2
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
1
3
|
# ngff-zarr
|
|
2
4
|
|
|
3
5
|
[](https://pypi.org/project/ngff-zarr)
|
|
4
6
|
[](https://pypi.org/project/ngff-zarr)
|
|
5
|
-
[](https://github.com/thewtex/ngff-zarr/actions/workflows/python.yml)
|
|
8
|
+
[](https://github.com/thewtex/ngff-zarr/actions/workflows/typescript.yml)
|
|
9
|
+
[](https://github.com/thewtex/ngff-zarr/actions/workflows/mcp-ci.yml)
|
|
6
10
|
[](https://zenodo.org/badge/latestdoi/541840158)
|
|
7
11
|
[](https://ngff-zarr.readthedocs.io/en/latest/?badge=latest)
|
|
8
12
|
|
|
@@ -39,7 +43,10 @@ The main Python package provides:
|
|
|
39
43
|
- Optional OME-Zarr data model validation during reading
|
|
40
44
|
- Writes OME-Zarr v0.4 to v0.5
|
|
41
45
|
- [Sharded Zarr] stores
|
|
42
|
-
- Optional writing via [tensorstore]
|
|
46
|
+
- Optional writing via zarr-python 2, zarr-python 3, [tensorstore] or zarrita (TypeScript)
|
|
47
|
+
- [Anatomical orientation metadata](./docs/rfc4.md) (RFC-4)
|
|
48
|
+
- **OME-Zarr Zip (.ozx) file support** for single-file OME-Zarr datasets (RFC-9)
|
|
49
|
+
- **High Content Screening (HCS) support** for plate and well data
|
|
43
50
|
- **Model Context Protocol (MCP) server** for AI agent integration
|
|
44
51
|
|
|
45
52
|
📖 **Documentation**
|
|
@@ -63,6 +70,7 @@ usage instructions.
|
|
|
63
70
|
- [pydantic-ome-ngff](https://janeliascicomp.github.io/pydantic-ome-ngff/)
|
|
64
71
|
- [aicsimageio](https://allencellmodeling.github.io/aicsimageio/)
|
|
65
72
|
- [bfio](https://bfio.readthedocs.io/)
|
|
73
|
+
- [zod-ome-ngff](https://github.com/hms-dbmi/zod-ome-ngff)
|
|
66
74
|
|
|
67
75
|
## License
|
|
68
76
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import * as zarr from "zarrita";
|
|
1
2
|
import { Multiscales } from "../types/multiscales.js";
|
|
2
3
|
export interface FromNgffZarrOptions {
|
|
3
4
|
validate?: boolean;
|
|
5
|
+
version?: "0.4" | "0.5";
|
|
4
6
|
}
|
|
5
|
-
export
|
|
7
|
+
export type MemoryStore = Map<string, Uint8Array>;
|
|
8
|
+
export declare function fromNgffZarr(store: string | MemoryStore | zarr.FetchStore, options?: FromNgffZarrOptions): Promise<Multiscales>;
|
|
6
9
|
export declare function readArrayData(storePath: string, arrayPath: string, selection?: (number | null)[]): Promise<unknown>;
|
|
7
10
|
//# sourceMappingURL=from_ngff_zarr.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"from_ngff_zarr.d.ts","sourceRoot":"","sources":["../../src/io/from_ngff_zarr.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"from_ngff_zarr.d.ts","sourceRoot":"","sources":["../../src/io/from_ngff_zarr.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAMtD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAElD,wBAAsB,YAAY,CAEhC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC,UAAU,EAC7C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,WAAW,CAAC,CA6MtB;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAC5B,OAAO,CAAC,OAAO,CAAC,CAmClB"}
|
package/esm/io/from_ngff_zarr.js
CHANGED
|
@@ -1,45 +1,62 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
1
3
|
import * as dntShim from "../_dnt.shims.js";
|
|
2
4
|
import * as zarr from "zarrita";
|
|
3
5
|
import { Multiscales } from "../types/multiscales.js";
|
|
4
6
|
import { NgffImage } from "../types/ngff_image.js";
|
|
5
|
-
import { LazyArray } from "../types/lazy_array.js";
|
|
6
7
|
import { MetadataSchema } from "../schemas/zarr_metadata.js";
|
|
7
|
-
export async function fromNgffZarr(
|
|
8
|
+
export async function fromNgffZarr(
|
|
9
|
+
// Also accepts FileSystemStore, ZipFileStore objects in Node.js/Deno
|
|
10
|
+
store, options = {}) {
|
|
8
11
|
const validate = options.validate ?? false;
|
|
12
|
+
const version = options.version;
|
|
9
13
|
try {
|
|
10
14
|
// Determine the appropriate store type based on the path
|
|
11
|
-
let
|
|
12
|
-
if (
|
|
15
|
+
let resolvedStore;
|
|
16
|
+
if (store instanceof Map || store instanceof zarr.FetchStore) {
|
|
17
|
+
resolvedStore = store;
|
|
18
|
+
}
|
|
19
|
+
else if (store.startsWith("http://") || store.startsWith("https://")) {
|
|
13
20
|
// Use FetchStore for HTTP/HTTPS URLs
|
|
14
|
-
|
|
21
|
+
resolvedStore = new zarr.FetchStore(store);
|
|
15
22
|
}
|
|
16
23
|
else {
|
|
17
24
|
// For local paths, check if we're in a browser environment
|
|
18
25
|
if (typeof dntShim.dntGlobalThis !== "undefined") {
|
|
19
26
|
throw new Error("Local file paths are not supported in browser environments. Use HTTP/HTTPS URLs instead.");
|
|
20
27
|
}
|
|
21
|
-
// Use dynamic import for FileSystemStore in Node.js/Deno environments
|
|
28
|
+
// Use dynamic import for FileSystemStore, ZipFileStore in Node.js/Deno environments
|
|
22
29
|
try {
|
|
23
|
-
const { FileSystemStore } = await import("@zarrita/storage");
|
|
24
|
-
|
|
30
|
+
const { FileSystemStore, ZipFileStore } = await import("@zarrita/storage");
|
|
31
|
+
// @ts-ignore: Node/Deno workaround
|
|
32
|
+
if (store instanceof FileSystemStore || store instanceof ZipFileStore) {
|
|
33
|
+
// @ts-ignore: Node/Deno workaround
|
|
34
|
+
resolvedStore = store;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Normalize the path for cross-platform compatibility
|
|
38
|
+
const normalizedPath = store.replace(/^\/([A-Za-z]:)/, "$1");
|
|
39
|
+
// @ts-ignore: Node/Deno workaround
|
|
40
|
+
resolvedStore = new FileSystemStore(normalizedPath);
|
|
41
|
+
}
|
|
25
42
|
}
|
|
26
43
|
catch (error) {
|
|
27
44
|
throw new Error(`Failed to load FileSystemStore: ${error}. Use HTTP/HTTPS URLs for browser compatibility.`);
|
|
28
45
|
}
|
|
29
46
|
}
|
|
30
|
-
const root = zarr.root(store);
|
|
31
47
|
// Try to use consolidated metadata for better performance
|
|
32
|
-
let
|
|
48
|
+
let optimizedStore;
|
|
33
49
|
try {
|
|
34
|
-
|
|
50
|
+
// @ts-ignore: tryWithConsolidated typing
|
|
51
|
+
optimizedStore = await zarr.tryWithConsolidated(resolvedStore);
|
|
35
52
|
}
|
|
36
53
|
catch {
|
|
37
|
-
|
|
54
|
+
optimizedStore = resolvedStore;
|
|
38
55
|
}
|
|
39
|
-
const
|
|
56
|
+
const root = await zarr.open(optimizedStore, {
|
|
40
57
|
kind: "group",
|
|
41
58
|
});
|
|
42
|
-
const attrs =
|
|
59
|
+
const attrs = root.attrs;
|
|
43
60
|
if (!attrs || !attrs.multiscales) {
|
|
44
61
|
throw new Error("No multiscales metadata found in Zarr store");
|
|
45
62
|
}
|
|
@@ -54,24 +71,60 @@ export async function fromNgffZarr(storePath, options = {}) {
|
|
|
54
71
|
if (!result.success) {
|
|
55
72
|
throw new Error(`Invalid OME-Zarr metadata: ${result.error.message}`);
|
|
56
73
|
}
|
|
74
|
+
// Check version compatibility if specified
|
|
75
|
+
if (version) {
|
|
76
|
+
const metadataWithVersion = multiscalesMetadata;
|
|
77
|
+
if (metadataWithVersion.version !== version) {
|
|
78
|
+
throw new Error(`Expected OME-Zarr version ${version}, but found ${metadataWithVersion.version || "unknown"}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
57
81
|
}
|
|
58
82
|
const metadata = multiscalesMetadata;
|
|
59
83
|
// Extract omero metadata from root attributes if present
|
|
60
84
|
if (attrs.omero) {
|
|
61
|
-
|
|
85
|
+
const omeroData = attrs.omero;
|
|
86
|
+
// Handle backward compatibility for OMERO window metadata
|
|
87
|
+
if (omeroData.channels && Array.isArray(omeroData.channels)) {
|
|
88
|
+
for (const channel of omeroData.channels) {
|
|
89
|
+
if (channel.window && typeof channel.window === "object") {
|
|
90
|
+
const window = channel.window;
|
|
91
|
+
// Ensure both min/max and start/end are present for compatibility
|
|
92
|
+
if (window.min !== undefined && window.max !== undefined) {
|
|
93
|
+
// If only min/max present, use them for start/end
|
|
94
|
+
if (window.start === undefined) {
|
|
95
|
+
window.start = window.min;
|
|
96
|
+
}
|
|
97
|
+
if (window.end === undefined) {
|
|
98
|
+
window.end = window.max;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else if (window.start !== undefined && window.end !== undefined) {
|
|
102
|
+
// If only start/end present, use them for min/max
|
|
103
|
+
if (window.min === undefined) {
|
|
104
|
+
window.min = window.start;
|
|
105
|
+
}
|
|
106
|
+
if (window.max === undefined) {
|
|
107
|
+
window.max = window.end;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
metadata.omero = omeroData;
|
|
62
114
|
}
|
|
63
115
|
const images = [];
|
|
64
116
|
for (const dataset of metadata.datasets) {
|
|
65
117
|
const arrayPath = dataset.path;
|
|
66
|
-
const zarrArray = await zarr.open
|
|
118
|
+
const zarrArray = (await zarr.open(root.resolve(arrayPath), {
|
|
67
119
|
kind: "array",
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
120
|
+
}));
|
|
121
|
+
// Verify we have an array with the expected properties
|
|
122
|
+
if (!zarrArray ||
|
|
123
|
+
!("shape" in zarrArray) ||
|
|
124
|
+
!("dtype" in zarrArray) ||
|
|
125
|
+
!("chunks" in zarrArray)) {
|
|
126
|
+
throw new Error(`Invalid zarr array at path ${arrayPath}: missing shape property`);
|
|
127
|
+
}
|
|
75
128
|
const scale = {};
|
|
76
129
|
const translation = {};
|
|
77
130
|
for (const transform of dataset.coordinateTransformations) {
|
|
@@ -98,7 +151,7 @@ export async function fromNgffZarr(storePath, options = {}) {
|
|
|
98
151
|
return acc;
|
|
99
152
|
}, {});
|
|
100
153
|
const ngffImage = new NgffImage({
|
|
101
|
-
data:
|
|
154
|
+
data: zarrArray,
|
|
102
155
|
dims,
|
|
103
156
|
scale,
|
|
104
157
|
translation,
|
|
@@ -124,9 +177,23 @@ export async function readArrayData(storePath, arrayPath, selection) {
|
|
|
124
177
|
try {
|
|
125
178
|
const store = new zarr.FetchStore(storePath);
|
|
126
179
|
const root = zarr.root(store);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
180
|
+
// Try to open as zarr v2 first, then v3 if that fails
|
|
181
|
+
let zarrArray;
|
|
182
|
+
try {
|
|
183
|
+
zarrArray = await zarr.open.v2(root.resolve(arrayPath), {
|
|
184
|
+
kind: "array",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (v2Error) {
|
|
188
|
+
try {
|
|
189
|
+
zarrArray = await zarr.open.v3(root.resolve(arrayPath), {
|
|
190
|
+
kind: "array",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch (v3Error) {
|
|
194
|
+
throw new Error(`Failed to open zarr array ${arrayPath} as either v2 or v3 format. v2 error: ${v2Error}. v3 error: ${v3Error}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
130
197
|
if (selection) {
|
|
131
198
|
return await zarr.get(zarrArray, selection);
|
|
132
199
|
}
|
package/esm/io/hcs.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { HCSPlate } from "../types/hcs.js";
|
|
2
|
+
export interface FromHcsZarrOptions {
|
|
3
|
+
validate?: boolean;
|
|
4
|
+
wellCacheSize?: number;
|
|
5
|
+
imageCacheSize?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ToHcsZarrOptions {
|
|
8
|
+
compressionLevel?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Read an HCS plate from an OME-Zarr NGFF store.
|
|
12
|
+
*/
|
|
13
|
+
export declare function fromHcsZarr(store: string | object, options?: FromHcsZarrOptions): HCSPlate;
|
|
14
|
+
/**
|
|
15
|
+
* Write an HCS plate to an OME-Zarr NGFF store.
|
|
16
|
+
*/
|
|
17
|
+
export declare function toHcsZarr(plate: HCSPlate, store: string | object, _options?: ToHcsZarrOptions): void;
|
|
18
|
+
//# sourceMappingURL=hcs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hcs.d.ts","sourceRoot":"","sources":["../../src/io/hcs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,iBAAiB,CAAC;AAG/D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAE/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,OAAO,GAAE,kBAAuB,GAC/B,QAAQ,CAkCV;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,QAAQ,GAAE,gBAAqB,GAC9B,IAAI,CAaN"}
|
package/esm/io/hcs.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { HCSPlate as HCSPlateClass } from "../types/hcs.js";
|
|
2
|
+
/**
|
|
3
|
+
* Read an HCS plate from an OME-Zarr NGFF store.
|
|
4
|
+
*/
|
|
5
|
+
export function fromHcsZarr(store, options = {}) {
|
|
6
|
+
const { validate = false, wellCacheSize, imageCacheSize } = options;
|
|
7
|
+
if (validate) {
|
|
8
|
+
console.warn("HCS validation not yet implemented");
|
|
9
|
+
}
|
|
10
|
+
if (typeof store !== "string") {
|
|
11
|
+
throw new Error("Non-string store types not yet supported");
|
|
12
|
+
}
|
|
13
|
+
// For now, create a mock implementation
|
|
14
|
+
// This will be properly implemented when the zarrita API integration is complete
|
|
15
|
+
const plateMetadata = {
|
|
16
|
+
columns: [{ name: "1" }, { name: "2" }],
|
|
17
|
+
rows: [{ name: "A" }, { name: "B" }],
|
|
18
|
+
wells: [
|
|
19
|
+
{ path: "A/1", rowIndex: 0, columnIndex: 0 },
|
|
20
|
+
{ path: "A/2", rowIndex: 0, columnIndex: 1 },
|
|
21
|
+
{ path: "B/1", rowIndex: 1, columnIndex: 0 },
|
|
22
|
+
{ path: "B/2", rowIndex: 1, columnIndex: 1 },
|
|
23
|
+
],
|
|
24
|
+
version: "0.4",
|
|
25
|
+
acquisitions: [{ id: 0, name: "Test Acquisition" }],
|
|
26
|
+
field_count: 2,
|
|
27
|
+
name: "Test Plate",
|
|
28
|
+
};
|
|
29
|
+
return new HCSPlateClass({
|
|
30
|
+
store,
|
|
31
|
+
metadata: plateMetadata,
|
|
32
|
+
wellCacheSize,
|
|
33
|
+
imageCacheSize,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Write an HCS plate to an OME-Zarr NGFF store.
|
|
38
|
+
*/
|
|
39
|
+
export function toHcsZarr(plate, store, _options = {}) {
|
|
40
|
+
if (typeof store !== "string") {
|
|
41
|
+
throw new Error("Non-string store types not yet supported");
|
|
42
|
+
}
|
|
43
|
+
// Mock implementation for now
|
|
44
|
+
console.log(`HCS plate structure would be created at ${store}`);
|
|
45
|
+
console.log(`Plate: ${plate.name}`);
|
|
46
|
+
console.log(`Wells: ${plate.wells.length}`);
|
|
47
|
+
console.log(`Rows: ${plate.rows.length}, Columns: ${plate.columns.length}`);
|
|
48
|
+
if (plate.acquisitions) {
|
|
49
|
+
console.log(`Acquisitions: ${plate.acquisitions.length}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert ITK-Wasm Image to NgffImage
|
|
3
|
+
*/
|
|
4
|
+
import type { Image } from "itk-wasm";
|
|
5
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
6
|
+
export interface ItkImageToNgffImageOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Whether to add anatomical orientation metadata based on ITK LPS coordinate system
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
addAnatomicalOrientation?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Path prefix for the zarr array (e.g., "scale0/", "scale1/")
|
|
14
|
+
* @default "image"
|
|
15
|
+
*/
|
|
16
|
+
path?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert an ITK-Wasm Image to an NgffImage, preserving spatial metadata.
|
|
20
|
+
*
|
|
21
|
+
* This function converts ITK-Wasm Image objects to NgffImage format while
|
|
22
|
+
* preserving spatial information like spacing, origin, and optionally
|
|
23
|
+
* anatomical orientation based on the ITK LPS coordinate system.
|
|
24
|
+
*
|
|
25
|
+
* @param itkImage - The ITK-Wasm Image to convert
|
|
26
|
+
* @param options - Conversion options
|
|
27
|
+
* @returns Promise resolving to NgffImage
|
|
28
|
+
*/
|
|
29
|
+
export declare function itkImageToNgffImage(itkImage: Image, options?: ItkImageToNgffImageOptions): Promise<NgffImage>;
|
|
30
|
+
//# sourceMappingURL=itk_image_to_ngff_image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"itk_image_to_ngff_image.d.ts","sourceRoot":"","sources":["../../src/io/itk_image_to_ngff_image.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAOnD,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,KAAK,EACf,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,SAAS,CAAC,CAmHpB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* Convert ITK-Wasm Image to NgffImage
|
|
5
|
+
*/
|
|
6
|
+
import * as zarr from "zarrita";
|
|
7
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
8
|
+
import { itkLpsToAnatomicalOrientation } from "../types/rfc4.js";
|
|
9
|
+
// Import the get_strides function from zarrita utilities
|
|
10
|
+
import { _zarrita_internal_get_strides as getStrides } from "zarrita";
|
|
11
|
+
/**
|
|
12
|
+
* Convert an ITK-Wasm Image to an NgffImage, preserving spatial metadata.
|
|
13
|
+
*
|
|
14
|
+
* This function converts ITK-Wasm Image objects to NgffImage format while
|
|
15
|
+
* preserving spatial information like spacing, origin, and optionally
|
|
16
|
+
* anatomical orientation based on the ITK LPS coordinate system.
|
|
17
|
+
*
|
|
18
|
+
* @param itkImage - The ITK-Wasm Image to convert
|
|
19
|
+
* @param options - Conversion options
|
|
20
|
+
* @returns Promise resolving to NgffImage
|
|
21
|
+
*/
|
|
22
|
+
export async function itkImageToNgffImage(itkImage, options = {}) {
|
|
23
|
+
const { addAnatomicalOrientation = true, path = "image" } = options;
|
|
24
|
+
// Extract image properties from ITK-Wasm Image
|
|
25
|
+
const _data = itkImage.data;
|
|
26
|
+
// ITK stores size in physical space order [x, y, z], but the data buffer is in
|
|
27
|
+
// C-order (row-major) which means [z, y, x] indexing. Reverse to match data layout.
|
|
28
|
+
const shape = [...itkImage.size].reverse();
|
|
29
|
+
const spacing = itkImage.spacing;
|
|
30
|
+
const origin = itkImage.origin;
|
|
31
|
+
const ndim = shape.length;
|
|
32
|
+
// Determine dimension names based on shape and image type
|
|
33
|
+
// This logic matches the Python implementation
|
|
34
|
+
let dims;
|
|
35
|
+
// Check if this is a vector image (multi-component)
|
|
36
|
+
const imageType = itkImage.imageType;
|
|
37
|
+
const isVector = imageType.components > 1;
|
|
38
|
+
if (ndim === 3 && isVector) {
|
|
39
|
+
// 2D RGB/vector image: 2D spatial + components
|
|
40
|
+
dims = ["y", "x", "c"];
|
|
41
|
+
}
|
|
42
|
+
else if (ndim < 4) {
|
|
43
|
+
// Scalar images up to 3D: take the last ndim spatial dimensions
|
|
44
|
+
dims = ["z", "y", "x"].slice(-ndim);
|
|
45
|
+
}
|
|
46
|
+
else if (ndim < 5) {
|
|
47
|
+
// 3D RGB/vector or 4D scalar
|
|
48
|
+
if (isVector) {
|
|
49
|
+
dims = ["z", "y", "x", "c"];
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
dims = ["t", "z", "y", "x"];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (ndim < 6) {
|
|
56
|
+
// 4D RGB/vector
|
|
57
|
+
dims = ["t", "z", "y", "x", "c"];
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
throw new Error(`Unsupported number of dimensions: ${ndim}`);
|
|
61
|
+
}
|
|
62
|
+
// Identify spatial dimensions
|
|
63
|
+
const allSpatialDims = new Set(["x", "y", "z"]);
|
|
64
|
+
const spatialDims = dims.filter((dim) => allSpatialDims.has(dim));
|
|
65
|
+
// Create scale mapping from spacing
|
|
66
|
+
// ITK stores spacing/origin in physical space order (x, y, z),
|
|
67
|
+
// but we need to map them to array order (z, y, x).
|
|
68
|
+
// Reverse the arrays to convert from physical to array order, matching Python implementation.
|
|
69
|
+
const scale = {};
|
|
70
|
+
const reversedSpacing = spacing.slice().reverse();
|
|
71
|
+
spatialDims.forEach((dim, idx) => {
|
|
72
|
+
scale[dim] = reversedSpacing[idx];
|
|
73
|
+
});
|
|
74
|
+
// Create translation mapping from origin
|
|
75
|
+
const translation = {};
|
|
76
|
+
const reversedOrigin = origin.slice().reverse();
|
|
77
|
+
spatialDims.forEach((dim, idx) => {
|
|
78
|
+
translation[dim] = reversedOrigin[idx];
|
|
79
|
+
});
|
|
80
|
+
// Create Zarr array from ITK-Wasm data
|
|
81
|
+
const store = new Map();
|
|
82
|
+
const root = zarr.root(store);
|
|
83
|
+
// Determine appropriate chunk size
|
|
84
|
+
const chunkShape = shape.map((s) => Math.min(s, 256));
|
|
85
|
+
const zarrArray = await zarr.create(root.resolve(path), {
|
|
86
|
+
shape: shape,
|
|
87
|
+
chunk_shape: chunkShape,
|
|
88
|
+
data_type: imageType.componentType,
|
|
89
|
+
fill_value: 0,
|
|
90
|
+
});
|
|
91
|
+
// Write the ITK-Wasm data to the zarr array
|
|
92
|
+
// We use zarrita's set function to write the entire data efficiently
|
|
93
|
+
// Create a selection that covers the entire array (null means "all" for each dimension)
|
|
94
|
+
const selection = new Array(ndim).fill(null);
|
|
95
|
+
// Create a chunk object with the ITK-Wasm data in zarrita format
|
|
96
|
+
// ITK-Wasm stores data in column-major order with size [x, y, z],
|
|
97
|
+
// which has the same memory layout as C-order (row-major) with shape [z, y, x].
|
|
98
|
+
// We reversed the shape above, and now use C-order strides for that reversed shape.
|
|
99
|
+
const dataChunk = {
|
|
100
|
+
data: itkImage.data,
|
|
101
|
+
shape: shape,
|
|
102
|
+
stride: getStrides(shape, "C"), // C-order strides for the reversed shape
|
|
103
|
+
};
|
|
104
|
+
// Write all data to the zarr array using zarrita's set function
|
|
105
|
+
// This handles chunking and encoding automatically
|
|
106
|
+
await zarr.set(zarrArray, selection, dataChunk); // Add anatomical orientation if requested
|
|
107
|
+
let axesOrientations;
|
|
108
|
+
if (addAnatomicalOrientation) {
|
|
109
|
+
axesOrientations = {};
|
|
110
|
+
for (const dim of spatialDims) {
|
|
111
|
+
const orientation = itkLpsToAnatomicalOrientation(dim);
|
|
112
|
+
if (orientation !== undefined) {
|
|
113
|
+
axesOrientations[dim] = orientation;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return new NgffImage({
|
|
118
|
+
data: zarrArray,
|
|
119
|
+
dims,
|
|
120
|
+
scale,
|
|
121
|
+
translation,
|
|
122
|
+
name: "image",
|
|
123
|
+
axesUnits: undefined,
|
|
124
|
+
axesOrientations,
|
|
125
|
+
computedCallbacks: undefined,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert NgffImage to ITK-Wasm Image
|
|
3
|
+
*/
|
|
4
|
+
import type { Image } from "itk-wasm";
|
|
5
|
+
import { NgffImage } from "../types/ngff_image.js";
|
|
6
|
+
export interface NgffImageToItkImageOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Extract a specific time index from a time-series image
|
|
9
|
+
* If specified and 't' dimension exists, extracts the slice at this time index
|
|
10
|
+
*/
|
|
11
|
+
tIndex?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Extract a specific channel index from a multi-channel image
|
|
14
|
+
* If specified and 'c' dimension exists, extracts the slice at this channel index
|
|
15
|
+
*/
|
|
16
|
+
cIndex?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert an NgffImage to an ITK-Wasm Image, preserving spatial metadata.
|
|
20
|
+
*
|
|
21
|
+
* This function converts NgffImage objects to ITK-Wasm Image format while
|
|
22
|
+
* preserving spatial information like spacing, origin, and direction matrix.
|
|
23
|
+
* Optionally extracts specific time or channel slices.
|
|
24
|
+
*
|
|
25
|
+
* @param ngffImage - The NgffImage to convert
|
|
26
|
+
* @param options - Conversion options
|
|
27
|
+
* @returns Promise resolving to ITK-Wasm Image
|
|
28
|
+
*/
|
|
29
|
+
export declare function ngffImageToItkImage(ngffImage: NgffImage, options?: NgffImageToItkImageOptions): Promise<Image>;
|
|
30
|
+
//# sourceMappingURL=ngff_image_to_itk_image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngff_image_to_itk_image.d.ts","sourceRoot":"","sources":["../../src/io/ngff_image_to_itk_image.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,OAAO,KAAK,EAEV,KAAK,EAKN,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,KAAK,CAAC,CAmMhB"}
|