@@ -9,31 +9,59 @@ type Slice = ReturnType<typeof zarr.slice>;
9
9
const X_AXIS_NAME = "x" ;
10
10
const Y_AXIS_NAME = "y" ;
11
11
const RGBA_CHANNEL_AXIS_NAME = "_c" ;
12
- const SUPPORTED_DTYPES = [ "Uint8" , "Uint16" , "Uint32" , "Float32" , "Int8" , "Int16" , "Int32" , "Float64" ] as const ;
13
12
14
- export class ZarrPixelSource < S extends Array < string > = Array < string > > implements viv . PixelSource < S > {
15
- #arr: zarr . Array < zarr . NumberDataType , zarr . Readable > ;
16
- readonly labels : viv . Labels < S > ;
13
+ type VivPixelData = {
14
+ data : zarr . TypedArray < Lowercase < viv . SupportedDtype > > ;
15
+ width : number ;
16
+ height : number ;
17
+ } ;
18
+
19
+ export class ZarrPixelSource implements viv . PixelSource < Array < string > > {
20
+ readonly labels : viv . Labels < Array < string > > ;
17
21
readonly tileSize : number ;
18
22
readonly dtype : viv . SupportedDtype ;
23
+ readonly #arr: zarr . Array < zarr . NumberDataType | zarr . BigintDataType , zarr . Readable > ;
24
+ readonly #transform: (
25
+ arr : zarr . TypedArray < zarr . NumberDataType | zarr . BigintDataType > ,
26
+ ) => zarr . TypedArray < Lowercase < viv . SupportedDtype > > ;
19
27
20
28
#pendingId: undefined | number = undefined ;
21
29
#pending: Array < {
22
- resolve : ( data : viv . PixelData ) => void ;
30
+ resolve : ( data : VivPixelData ) => void ;
23
31
reject : ( err : unknown ) => void ;
24
32
request : {
25
33
selection : Array < number | zarr . Slice > ;
26
34
signal ?: AbortSignal ;
27
35
} ;
28
36
} > = [ ] ;
29
37
30
- constructor ( arr : zarr . Array < zarr . DataType , zarr . Readable > , options : { labels : viv . Labels < S > ; tileSize : number } ) {
31
- const dtype = capitalize ( arr . dtype ) ;
32
- assert ( arr . is ( "number" ) && isSupportedDtype ( dtype ) , `Unsupported viv dtype: ${ dtype } ` ) ;
33
- this . dtype = dtype ;
38
+ constructor (
39
+ arr : zarr . Array < zarr . DataType , zarr . Readable > ,
40
+ options : { labels : viv . Labels < Array < string > > ; tileSize : number } ,
41
+ ) {
42
+ assert ( arr . is ( "number" ) || arr . is ( "bigint" ) , `Unsupported viv dtype: ${ arr . dtype } ` ) ;
34
43
this . #arr = arr ;
35
44
this . labels = options . labels ;
36
45
this . tileSize = options . tileSize ;
46
+ /**
47
+ * Some `zarrita` data types are not supported by Viv and require casting.
48
+ *
49
+ * Note how the casted type in the transform function is type-cast to `zarr.TypedArray<typeof arr.dtype>`.
50
+ * This ensures that the function body is correct based on whatever type narrowing we do in the if/else
51
+ * blocks based on dtype.
52
+ *
53
+ * TODO: Maybe we should add a console warning?
54
+ */
55
+ if ( arr . dtype === "uint64" || arr . dtype === "int64" ) {
56
+ this . dtype = "Uint32" ;
57
+ this . #transform = ( x ) => Uint32Array . from ( x as zarr . TypedArray < typeof arr . dtype > , ( bint ) => Number ( bint ) ) ;
58
+ } else if ( arr . dtype === "float16" ) {
59
+ this . dtype = "Float32" ;
60
+ this . #transform = ( x ) => new Float32Array ( x as zarr . TypedArray < typeof arr . dtype > ) ;
61
+ } else {
62
+ this . dtype = capitalize ( arr . dtype ) ;
63
+ this . #transform = ( x ) => x as zarr . TypedArray < typeof arr . dtype > ;
64
+ }
37
65
}
38
66
39
67
get #width( ) {
@@ -51,7 +79,7 @@ export class ZarrPixelSource<S extends Array<string> = Array<string>> implements
51
79
}
52
80
53
81
async getRaster ( options : {
54
- selection : viv . PixelSourceSelection < S > | Array < number > ;
82
+ selection : viv . PixelSourceSelection < Array < string > > | Array < number > ;
55
83
signal ?: AbortSignal ;
56
84
} ) : Promise < viv . PixelData > {
57
85
const { selection, signal } = options ;
@@ -71,7 +99,7 @@ export class ZarrPixelSource<S extends Array<string> = Array<string>> implements
71
99
async getTile ( options : {
72
100
x : number ;
73
101
y : number ;
74
- selection : viv . PixelSourceSelection < S > | Array < number > ;
102
+ selection : viv . PixelSourceSelection < Array < string > > | Array < number > ;
75
103
signal ?: AbortSignal ;
76
104
} ) : Promise < viv . PixelData > {
77
105
const { x, y, selection, signal } = options ;
@@ -88,9 +116,10 @@ export class ZarrPixelSource<S extends Array<string> = Array<string>> implements
88
116
}
89
117
90
118
async #fetchData( request : { selection : Array < number | Slice > ; signal ?: AbortSignal } ) : Promise < viv . PixelData > {
91
- const { promise, resolve, reject } = Promise . withResolvers < viv . PixelData > ( ) ;
119
+ const { promise, resolve, reject } = Promise . withResolvers < VivPixelData > ( ) ;
92
120
this . #pending. push ( { request, resolve, reject } ) ;
93
121
this . #pendingId = this . #pendingId ?? requestAnimationFrame ( ( ) => this . #fetchPending( ) ) ;
122
+ // @ts -expect-error - The missing generic ArrayBuffer type from Viv makes VivPixelData and viv.PixelData incompatible, even though they are.
94
123
return promise ;
95
124
}
96
125
@@ -104,13 +133,8 @@ export class ZarrPixelSource<S extends Array<string> = Array<string>> implements
104
133
zarr
105
134
. get ( this . #arr, request . selection , { opts : { signal : request . signal } } )
106
135
. then ( ( { data, shape } ) => {
107
- if ( data instanceof BigInt64Array || data instanceof BigUint64Array ) {
108
- // We need to cast data these typed arrays to something that is viv compatible.
109
- // See the comment in the constructor for more information.
110
- data = Uint32Array . from ( data , ( bint ) => Number ( bint ) ) ;
111
- }
112
136
resolve ( {
113
- data : data as viv . SupportedTypedArray ,
137
+ data : this . #transform ( data ) ,
114
138
width : shape [ 1 ] ,
115
139
height : shape [ 0 ] ,
116
140
} ) ;
@@ -154,8 +178,3 @@ function capitalize<T extends string>(s: T): Capitalize<T> {
154
178
// @ts -expect-error - TypeScript can't verify that the return type is correct
155
179
return s [ 0 ] . toUpperCase ( ) + s . slice ( 1 ) ;
156
180
}
157
-
158
- function isSupportedDtype ( dtype : string ) : dtype is viv . SupportedDtype {
159
- // @ts -expect-error - TypeScript can't verify that the return type is correct
160
- return SUPPORTED_DTYPES . includes ( dtype ) ;
161
- }
0 commit comments