@@ -10,12 +10,14 @@ import {
1010 createMultiscales ,
1111} from "../utils/factory.ts" ;
1212import { getMethodMetadata } from "../utils/method_metadata.ts" ;
13+ import { downsampleItkwasm } from "../methods/itkwasm.ts" ;
1314
1415export interface ToNgffImageOptions {
1516 dims ?: string [ ] ;
1617 scale ?: Record < string , number > ;
1718 translation ?: Record < string , number > ;
1819 name ?: string ;
20+ shape ?: number [ ] ; // Explicit shape for typed arrays
1921}
2022
2123/**
@@ -34,10 +36,11 @@ export async function toNgffImage(
3436 scale = { } ,
3537 translation = { } ,
3638 name = "image" ,
39+ shape : explicitShape ,
3740 } = options ;
3841
3942 // Determine data shape and create typed array
40- let typedData : Float32Array ;
43+ let typedData : Float32Array | Uint8Array | Uint16Array ;
4144 let shape : number [ ] ;
4245
4346 if ( Array . isArray ( data ) ) {
@@ -78,18 +81,34 @@ export async function toNgffImage(
7881 }
7982 } else {
8083 // ArrayLike (already a typed array)
81- typedData = new Float32Array ( data as ArrayLike < number > ) ;
82- shape = [ typedData . length ] ;
84+ // Use explicit shape if provided, otherwise infer from data length and dims
85+ if ( explicitShape ) {
86+ shape = [ ...explicitShape ] ;
87+ } else {
88+ // Try to infer shape - this is a best guess
89+ shape = [ data . length ] ;
90+ }
91+
92+ // Preserve the original typed array type
93+ if ( data instanceof Uint8Array ) {
94+ typedData = data ;
95+ } else if ( data instanceof Uint16Array ) {
96+ typedData = data ;
97+ } else {
98+ typedData = new Float32Array ( data as ArrayLike < number > ) ;
99+ }
83100 }
84101
85- // Adjust shape to match dims length
86- while ( shape . length < dims . length ) {
87- shape . unshift ( 1 ) ;
102+ // Adjust shape to match dims length if not explicitly provided
103+ if ( ! explicitShape ) {
104+ while ( shape . length < dims . length ) {
105+ shape . unshift ( 1 ) ;
106+ }
88107 }
89108
90- if ( shape . length > dims . length ) {
109+ if ( shape . length !== dims . length ) {
91110 throw new Error (
92- `Data dimensionality (${ shape . length } ) exceeds dims length (${ dims . length } )` ,
111+ `Shape dimensionality (${ shape . length } ) must match dims length (${ dims . length } )` ,
93112 ) ;
94113 }
95114
@@ -109,7 +128,7 @@ export async function toNgffImage(
109128
110129 // Write data to zarr array
111130 await zarr . set ( zarrArray , [ ] , {
112- data : typedData ,
131+ data : typedData as Float32Array ,
113132 shape,
114133 stride : calculateStride ( shape ) ,
115134 } ) ;
@@ -147,19 +166,40 @@ export interface ToMultiscalesOptions {
147166 * @param options - Configuration options
148167 * @returns Multiscales object
149168 */
150- export function toMultiscales (
169+ export async function toMultiscales (
151170 image : NgffImage ,
152171 options : ToMultiscalesOptions = { } ,
153- ) : Multiscales {
172+ ) : Promise < Multiscales > {
154173 const {
155174 scaleFactors = [ 2 , 4 ] ,
156175 method = Methods . ITKWASM_GAUSSIAN ,
157176 chunks : _chunks ,
158177 } = options ;
159178
160- // For now, create only the base image (no actual downsampling)
161- // This is a simplified implementation for testing metadata functionality
162- const images = [ image ] ;
179+ let images : NgffImage [ ] ;
180+
181+ // Check if we should perform actual downsampling
182+ if (
183+ method === Methods . ITKWASM_GAUSSIAN ||
184+ method === Methods . ITKWASM_BIN_SHRINK ||
185+ method === Methods . ITKWASM_LABEL_IMAGE
186+ ) {
187+ // Perform actual downsampling using ITK-Wasm
188+ const smoothing = method === Methods . ITKWASM_GAUSSIAN
189+ ? "gaussian"
190+ : method === Methods . ITKWASM_BIN_SHRINK
191+ ? "bin_shrink"
192+ : "label_image" ;
193+
194+ images = await downsampleItkwasm (
195+ image ,
196+ scaleFactors as ( Record < string , number > | number ) [ ] ,
197+ smoothing ,
198+ ) ;
199+ } else {
200+ // Fallback: create only the base image (no actual downsampling)
201+ images = [ image ] ;
202+ }
163203
164204 // Create axes from image dimensions
165205 const axes = image . dims . map ( ( dim ) => {
@@ -178,14 +218,14 @@ export function toMultiscales(
178218 }
179219 } ) ;
180220
181- // Create datasets
182- const datasets = [
183- createDataset (
184- "0" ,
185- image . dims . map ( ( dim ) => image . scale [ dim ] ) ,
186- image . dims . map ( ( dim ) => image . translation [ dim ] ) ,
187- ) ,
188- ] ;
221+ // Create datasets for all images
222+ const datasets = images . map ( ( img , index ) => {
223+ return createDataset (
224+ ` ${ index } ` ,
225+ img . dims . map ( ( dim ) => img . scale [ dim ] ) ,
226+ img . dims . map ( ( dim ) => img . translation [ dim ] ) ,
227+ ) ;
228+ } ) ;
189229
190230 // Create metadata with method information
191231 const methodMetadata = getMethodMetadata ( method ) ;
0 commit comments