🦕 TypeScript / JavaScript Interface¶
NGFF-Zarr provides a TypeScript implementation for working with OME-Zarr data structures in Deno, Node.js, and browser environments. The TypeScript API mirrors the Python interface, providing a familiar and consistent experience across languages.
✨ Features¶
🦕 Deno-first: Built for Deno with first-class TypeScript support
📦 Universal compatibility: Works in Deno, Node.js, and browsers
🔍 Type-safe: Full TypeScript support with Zod schema validation
🗂️ OME-Zarr support: Read and write OME-Zarr v0.4 and v0.5
🧪 Well-tested: Comprehensive test suite with browser validation
🏗️ Mirrors Python API: Familiar interfaces for Python users
📖 Lazy loading: Efficient handling of large datasets
🌐 Web ready: No filesystem dependencies, works with remote stores
📦 Installation¶
JSR (Deno and Node.js)¶
The package is published to JSR (JavaScript Registry) for use with Deno and modern Node.js:
Deno:
import * as ngffZarr from "jsr:@fideus-labs/ngff-zarr";
Node.js with JSR support:
npx jsr add @fideus-labs/ngff-zarr
import * as ngffZarr from "@fideus-labs/ngff-zarr";
npm (Node.js and Bundlers)¶
For traditional Node.js projects and bundlers like webpack, Vite, or esbuild:
npm install @fideus-labs/ngff-zarr
import * as ngffZarr from "@fideus-labs/ngff-zarr";
Browser (CDN)¶
For direct browser usage via CDN:
<script type="module">
import * as ngffZarr from "https://esm.sh/@fideus-labs/ngff-zarr";
// Your code here
</script>
🚀 Quick Start¶
Reading OME-Zarr Files¶
Read an OME-Zarr file and access the multiscale data:
import { fromNgffZarr } from "@fideus-labs/ngff-zarr";
// Read from a local file (Deno/Node.js)
const multiscales = await fromNgffZarr("path/to/image.ome.zarr");
// Read from a remote URL (works in all environments)
const remoteMultiscales = await fromNgffZarr(
"https://example.com/data.ome.zarr"
);
// Access the image data
console.log(`Loaded ${multiscales.images.length} scale levels`);
console.log(`Image shape: ${multiscales.images[0].data.shape}`);
console.log(`Data type: ${multiscales.images[0].data.dtype}`);
// Access metadata
console.log(`Axes: ${JSON.stringify(multiscales.metadata.axes)}`);
console.log(`Version: ${multiscales.metadata.version}`);
Validating OME-Zarr Metadata¶
Enable validation to ensure OME-Zarr files conform to the specification:
import { fromNgffZarr } from "@fideus-labs/ngff-zarr";
// Validate during reading
const multiscales = await fromNgffZarr("image.ome.zarr", {
validate: true,
});
// Specify expected version
const multiscalesV5 = await fromNgffZarr("image.ome.zarr", {
validate: true,
version: "0.5",
});
Creating and Writing OME-Zarr Files¶
Create a simple OME-Zarr file from scratch:
import {
createAxis,
createDataset,
createMetadata,
createMultiscales,
createNgffImage,
toNgffZarr,
} from "@fideus-labs/ngff-zarr";
// Create image data (256x256 grayscale)
const data = new Uint8Array(256 * 256);
for (let i = 0; i < data.length; i++) {
data[i] = Math.floor(Math.random() * 256);
}
// Create an NgffImage with metadata
const image = createNgffImage(
data.buffer,
[256, 256], // shape
"uint8", // dtype
["y", "x"], // dimension names
{ y: 1.0, x: 1.0 }, // scale (pixel spacing)
{ y: 0.0, x: 0.0 } // translation (origin)
);
// Create OME-Zarr metadata
const axes = [
createAxis("y", "space", "micrometer"),
createAxis("x", "space", "micrometer"),
];
const datasets = [
createDataset(
"0", // path
[1.0, 1.0], // scale
[0.0, 0.0] // translation
),
];
const metadata = createMetadata(axes, datasets, "my_image");
// Create multiscales container
const multiscales = createMultiscales([image], metadata);
// Write to OME-Zarr
await toNgffZarr("output.ome.zarr", multiscales);
Generating Multiscale Pyramids¶
Create multiscale image pyramids with downsampling:
import {
createNgffImage,
toMultiscales,
toNgffZarr,
Methods,
} from "@fideus-labs/ngff-zarr";
// Create base image
const data = new Uint8Array(512 * 512);
const image = createNgffImage(
data.buffer,
[512, 512],
"uint8",
["y", "x"],
{ y: 1.0, x: 1.0 },
{ y: 0.0, x: 0.0 }
);
// Generate multiscale pyramid with 2x and 4x downsampling
const multiscales = await toMultiscales(image, {
scaleFactors: [2, 4],
method: Methods.ITKWASM_GAUSSIAN,
chunks: 128,
});
// Write the pyramid
await toNgffZarr("pyramid.ome.zarr", multiscales);
🌍 Platform Support¶
Deno¶
Full native support with TypeScript:
import * as ngffZarr from "@fideus-labs/ngff-zarr";
const multiscales = await ngffZarr.fromNgffZarr("./data.ome.zarr");
Node.js¶
Compatible with Node.js 18+ (ESM and CommonJS):
// ESM
import { fromNgffZarr } from "@fideus-labs/ngff-zarr";
// CommonJS
const { fromNgffZarr } = require("@fideus-labs/ngff-zarr");
Browser¶
Works in modern browsers with ES modules:
<!DOCTYPE html>
<html>
<head>
<title>OME-Zarr in Browser</title>
</head>
<body>
<script type="module">
import { fromNgffZarr } from "https://esm.sh/@fideus-labs/ngff-zarr";
// Load from remote URL
const multiscales = await fromNgffZarr(
"https://example.com/data.ome.zarr"
);
console.log("Loaded:", multiscales.images.length, "scales");
</script>
</body>
</html>
Browser Limitations:
Cannot read from local filesystem (use HTTP URLs instead)
FileSystemStore is not available in browsers
Use FetchStore for remote data access
📚 API Reference¶
Core Types¶
NgffImage¶
Represents a single-scale image with associated metadata:
interface NgffImage {
data: DaskArray; // Lazy array data
dims: string[]; // Dimension names ["t", "c", "z", "y", "x"]
scale: Record<string, number>; // Pixel spacing per dimension
translation: Record<string, number>; // Origin offset
name?: string; // Optional image name
axesUnits?: Record<string, Units>; // Optional units per axis
}
Example:
import { createNgffImage } from "@fideus-labs/ngff-zarr";
const image = createNgffImage(
arrayBuffer,
[100, 100],
"uint16",
["y", "x"],
{ y: 0.5, x: 0.5 },
{ y: 0.0, x: 0.0 }
);
Multiscales¶
Container for multiple resolution levels:
interface Multiscales {
images: NgffImage[]; // Array of scale levels
metadata: Metadata; // OME-Zarr metadata
scaleFactors?: (number | Record<string, number>)[]; // Scale factors
method?: Methods; // Downsampling method
chunks?: Record<string, number>; // Chunk sizes
}
Metadata¶
OME-Zarr metadata structure:
interface Metadata {
axes: Axis[]; // Dimension definitions
datasets: Dataset[]; // Scale level paths and transforms
coordinateTransformations?: CoordinateTransformation[];
name?: string;
version?: "0.4" | "0.5";
type?: string; // Downsampling method type
metadata?: Record<string, unknown>;
}
Axis¶
Dimension axis definition:
interface Axis {
name: string; // "t", "c", "z", "y", "x"
type?: "time" | "channel" | "space";
unit?: Units; // UDUNITS-2 identifier
}
I/O Functions¶
fromNgffZarr()¶
Read an OME-Zarr file:
async function fromNgffZarr(
store: string | MemoryStore | FetchStore,
options?: {
validate?: boolean;
version?: "0.4" | "0.5";
}
): Promise<Multiscales>
Parameters:
store: Path to OME-Zarr (string), URL (string), or Zarr store objectoptions.validate: Enable metadata validation (default: false)options.version: Expected OME-Zarr version
Returns: Multiscales object with all scale levels
Example:
// Basic reading
const ms = await fromNgffZarr("data.ome.zarr");
// With validation
const validatedMs = await fromNgffZarr("data.ome.zarr", {
validate: true,
version: "0.5",
});
// From URL
const remoteMs = await fromNgffZarr("https://example.com/data.ome.zarr");
toNgffZarr()¶
Write a Multiscales object to OME-Zarr:
async function toNgffZarr(
store: string,
multiscales: Multiscales,
options?: {
version?: "0.4" | "0.5";
chunksPerShard?: number | number[] | Record<string, number>;
}
): Promise<void>
Parameters:
store: Output path for OME-Zarrmultiscales: Multiscales object to writeoptions.version: OME-Zarr version (default: “0.4”)options.chunksPerShard: Sharding configuration (v0.5 only)
Example:
// Basic writing
await toNgffZarr("output.ome.zarr", multiscales);
// With version specification
await toNgffZarr("output.ome.zarr", multiscales, { version: "0.5" });
// With sharding (v0.5)
await toNgffZarr("output.ome.zarr", multiscales, {
version: "0.5",
chunksPerShard: { z: 2, y: 2, x: 2 },
});
toMultiscales()¶
Generate multiscale pyramid from a single image:
async function toMultiscales(
image: NgffImage,
options?: {
scaleFactors?: (number | Record<string, number>)[];
method?: Methods;
chunks?: number | number[] | Record<string, number>;
}
): Promise<Multiscales>
Parameters:
image: Base NgffImage to downsampleoptions.scaleFactors: Downsampling factors (default: [2, 4])options.method: Downsampling method (default: ITKWASM_GAUSSIAN)options.chunks: Chunk sizes for output
Returns: Multiscales with generated pyramid levels
Example:
// Basic pyramid generation
const ms = await toMultiscales(image);
// Custom scale factors
const ms2 = await toMultiscales(image, {
scaleFactors: [2, 4, 8],
method: Methods.ITKWASM_GAUSSIAN,
});
// With custom chunks
const ms3 = await toMultiscales(image, {
scaleFactors: [{ x: 2, y: 2 }, { x: 4, y: 4 }],
chunks: 256,
});
Factory Functions¶
createNgffImage()¶
Create an NgffImage from raw data:
function createNgffImage(
buffer: ArrayBuffer,
shape: number[],
dtype: string,
dims: string[],
scale: Record<string, number>,
translation: Record<string, number>,
name?: string
): NgffImage
createAxis()¶
Create an axis definition:
function createAxis(
name: string,
type: "time" | "channel" | "space",
unit?: Units
): Axis
createDataset()¶
Create a dataset entry:
function createDataset(
path: string,
scale: number[],
translation: number[]
): Dataset
createMetadata()¶
Create OME-Zarr metadata:
function createMetadata(
axes: Axis[],
datasets: Dataset[],
name?: string
): Metadata
createMultiscales()¶
Create a Multiscales container:
function createMultiscales(
images: NgffImage[],
metadata: Metadata,
scaleFactors?: (number | Record<string, number>)[],
method?: Methods
): Multiscales
Validation¶
Schema Validation with Zod¶
The package includes Zod schemas for runtime validation:
import {
MetadataSchema,
NgffImageSchema,
MultiscalesSchema,
validateMetadata,
} from "@fideus-labs/ngff-zarr";
// Validate metadata
const metadata = { axes: [...], datasets: [...] };
const validated = MetadataSchema.parse(metadata);
// Safe parsing (returns result object)
const result = MetadataSchema.safeParse(metadata);
if (result.success) {
console.log("Valid metadata:", result.data);
} else {
console.error("Validation errors:", result.error.issues);
}
// Utility function
const validMetadata = validateMetadata(metadata);
Downsampling Methods¶
Available downsampling methods via the Methods enum:
enum Methods {
ITKWASM_GAUSSIAN = "itkwasm_gaussian", // Gaussian smoothing (default)
ITKWASM_BIN_SHRINK = "itkwasm_bin_shrink", // Bin shrinking
ITKWASM_LABEL_IMAGE = "itkwasm_label_image", // Label-aware downsampling
}
Example:
import { toMultiscales, Methods } from "@fideus-labs/ngff-zarr";
const pyramid = await toMultiscales(image, {
method: Methods.ITKWASM_GAUSSIAN,
scaleFactors: [2, 4],
});
💡 Examples¶
Example 1: Convert Image Format¶
Read an image and convert to OME-Zarr:
import {
itkImageToNgffImage,
toMultiscales,
toNgffZarr,
} from "@fideus-labs/ngff-zarr";
// Load image using itk-wasm
const itkImage = await loadImageFromFile("input.png");
// Convert to NgffImage
const ngffImage = await itkImageToNgffImage(itkImage);
// Generate pyramid
const multiscales = await toMultiscales(ngffImage);
// Write to OME-Zarr
await toNgffZarr("output.ome.zarr", multiscales);
Example 2: Process Remote Data¶
Work with remote OME-Zarr files:
import { fromNgffZarr } from "@fideus-labs/ngff-zarr";
// Read from S3 or other HTTP-accessible storage
const multiscales = await fromNgffZarr(
"https://s3.amazonaws.com/bucket/data.ome.zarr"
);
// Access the highest resolution
const fullRes = multiscales.images[0];
console.log(`Shape: ${fullRes.data.shape}`);
console.log(`Spacing: ${JSON.stringify(fullRes.scale)}`);
// Access a lower resolution
const lowRes = multiscales.images[multiscales.images.length - 1];
console.log(`Low-res shape: ${lowRes.data.shape}`);
Example 3: Metadata Inspection¶
Examine OME-Zarr metadata:
import { fromNgffZarr } from "@fideus-labs/ngff-zarr";
const multiscales = await fromNgffZarr("data.ome.zarr");
// Inspect axes
multiscales.metadata.axes.forEach(axis => {
console.log(`Axis ${axis.name}: type=${axis.type}, unit=${axis.unit}`);
});
// Inspect datasets
multiscales.metadata.datasets.forEach((dataset, i) => {
console.log(`Scale ${i}: path=${dataset.path}`);
dataset.coordinateTransformations.forEach(transform => {
if (transform.type === "scale") {
console.log(` Scale: ${transform.scale}`);
}
});
});
// Check version
console.log(`OME-Zarr version: ${multiscales.metadata.version}`);
Example 4: Custom Chunk Sizes¶
Control chunking for optimal performance:
import {
createNgffImage,
toMultiscales,
toNgffZarr,
} from "@fideus-labs/ngff-zarr";
const image = createNgffImage(
buffer,
[1024, 1024, 1024], // Large 3D volume
"uint16",
["z", "y", "x"],
{ z: 1.0, y: 0.5, x: 0.5 },
{ z: 0.0, y: 0.0, x: 0.0 }
);
// Use smaller chunks for better streaming
const multiscales = await toMultiscales(image, {
chunks: { z: 64, y: 128, x: 128 },
scaleFactors: [2, 4, 8],
});
await toNgffZarr("large_volume.ome.zarr", multiscales);
Example 5: TypeScript Type Safety¶
Leverage TypeScript’s type system:
import type {
NgffImage,
Multiscales,
Metadata,
Axis,
} from "@fideus-labs/ngff-zarr";
import { fromNgffZarr, validateMetadata } from "@fideus-labs/ngff-zarr";
// Type-safe function
async function processImage(path: string): Promise<Multiscales> {
const multiscales: Multiscales = await fromNgffZarr(path);
// TypeScript knows the structure
const axes: Axis[] = multiscales.metadata.axes;
const firstImage: NgffImage = multiscales.images[0];
return multiscales;
}
// Type-safe metadata validation
function ensureValidMetadata(metadata: unknown): Metadata {
return validateMetadata(metadata);
}
Example 6: JavaScript Usage¶
Pure JavaScript usage without TypeScript:
// JavaScript (Node.js or browser)
import { fromNgffZarr, toNgffZarr, createNgffImage } from "@fideus-labs/ngff-zarr";
// Read OME-Zarr
const multiscales = await fromNgffZarr("data.ome.zarr");
// Create new image
const data = new Uint8Array(100 * 100);
const image = createNgffImage(
data.buffer,
[100, 100],
"uint8",
["y", "x"],
{ y: 1.0, x: 1.0 },
{ y: 0.0, x: 0.0 }
);
// Write to OME-Zarr
await toNgffZarr("output.ome.zarr", image);
🔧 Advanced Usage¶
Working with Different Store Types¶
import * as zarr from "zarrita";
import { fromNgffZarr } from "@fideus-labs/ngff-zarr";
// Memory store
const memoryStore = new Map<string, Uint8Array>();
const ms1 = await fromNgffZarr(memoryStore);
// Fetch store (HTTP/HTTPS)
const fetchStore = new zarr.FetchStore("https://example.com/data.ome.zarr");
const ms2 = await fromNgffZarr(fetchStore);
// File system store (Node.js/Deno only)
import { FileSystemStore } from "@zarrita/storage";
const fsStore = new FileSystemStore("/path/to/data.ome.zarr");
const ms3 = await fromNgffZarr(fsStore);
Converting Between OME-Zarr Versions¶
import { fromNgffZarr, toNgffZarr } from "@fideus-labs/ngff-zarr";
// Convert from v0.4 to v0.5
const multiscales = await fromNgffZarr("data_v04.ome.zarr");
await toNgffZarr("data_v05.ome.zarr", multiscales, { version: "0.5" });
// Convert from v0.5 to v0.4
const multiscalesV5 = await fromNgffZarr("data_v05.ome.zarr");
await toNgffZarr("data_v04.ome.zarr", multiscalesV5, { version: "0.4" });
High Content Screening (HCS)¶
Work with plate and well data:
import { fromHcsZarr } from "@fideus-labs/ngff-zarr";
// Read HCS plate
const plate = await fromHcsZarr("plate.ome.zarr");
console.log(`Plate: ${plate.metadata.name}`);
console.log(`Wells: ${plate.metadata.wells.length}`);
// Access specific well
const well = plate.getWell("A", "1");
if (well) {
console.log(`Well A/1 has ${well.images.length} field(s)`);
}
🆚 Comparison with Python¶
The TypeScript API closely mirrors the Python interface:
Python |
TypeScript |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSON Schema validation |
JSON Schema validation |
Key Differences¶
Naming conventions: Python uses snake_case, TypeScript uses camelCase
Data handling: Python uses Dask arrays, TypeScript uses array metadata
Async: TypeScript I/O operations are async by default
🐛 Troubleshooting¶
Browser CORS Issues¶
When accessing remote OME-Zarr files in the browser, ensure CORS headers are set:
// This may fail due to CORS
const ms = await fromNgffZarr("https://example.com/data.ome.zarr");
// Solution: Ensure server sends proper CORS headers
// Access-Control-Allow-Origin: *
File System Access in Browser¶
Browsers cannot access local filesystem:
// ❌ Won't work in browser
const ms = await fromNgffZarr("/path/to/local/file.ome.zarr");
// ✅ Use HTTP URLs instead
const ms = await fromNgffZarr("http://localhost:8000/file.ome.zarr");
Memory Management¶
For large datasets, zarrita handles lazy loading automatically:
// Data is loaded lazily - metadata read immediately
const multiscales = await fromNgffZarr("large_file.ome.zarr");
// Actual array data loaded on access
const shape = multiscales.images[0].data.shape; // Fast
// Actual data retrieval would happen when reading chunks
📚 External Resources¶
🤝 Contributing¶
Contributions are welcome! See the development documentation for details on:
Setting up the development environment
Running tests
Building the npm package
Browser testing with Playwright