@aics/vole-core 3.12.4 → 3.13.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 +17 -12
- package/es/View3d.js +7 -2
- package/es/VolumeRenderSettings.js +11 -0
- package/es/loaders/TiffLoader.js +3 -1
- package/es/types/NaiveSurfaceNets.d.ts +1 -1
- package/es/types/RayMarchedAtlasVolume.d.ts +1 -1
- package/es/types/ThreeJsPanel.d.ts +2 -2
- package/es/types/TrackballControls.d.ts +1 -1
- package/es/types/VolumeDrawable.d.ts +1 -1
- package/es/types/VolumeRenderImpl.d.ts +1 -1
- package/es/types/index.d.ts +1 -1
- package/es/types/workers/VolumeLoaderContext.d.ts +9 -13
- package/es/types/workers/types.d.ts +25 -16
- package/es/workers/VolumeLoadWorker.js +54 -32
- package/es/workers/VolumeLoaderContext.js +52 -51
- package/es/workers/types.js +17 -7
- package/package.json +13 -13
- package/es/test/ChunkPrefetchIterator.test.js +0 -208
- package/es/test/RequestQueue.test.js +0 -442
- package/es/test/SubscribableRequestQueue.test.js +0 -244
- package/es/test/VolumeCache.test.js +0 -118
- package/es/test/VolumeRenderSettings.test.js +0 -71
- package/es/test/lut.test.js +0 -671
- package/es/test/num_utils.test.js +0 -140
- package/es/test/volume.test.js +0 -98
- package/es/test/zarr_utils.test.js +0 -358
- package/es/types/test/ChunkPrefetchIterator.test.d.ts +0 -1
- package/es/types/test/RequestQueue.test.d.ts +0 -1
- package/es/types/test/SubscribableRequestQueue.test.d.ts +0 -1
- package/es/types/test/VolumeCache.test.d.ts +0 -1
- package/es/types/test/VolumeRenderSettings.test.d.ts +0 -1
- package/es/types/test/lut.test.d.ts +0 -1
- package/es/types/test/num_utils.test.d.ts +0 -1
- package/es/types/test/volume.test.d.ts +0 -1
- package/es/types/test/zarr_utils.test.d.ts +0 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ There are several ways to deliver volume data to the viewer:
|
|
|
16
16
|
- Load raw TypedArrays of 3d volume data ( see `RawArrayLoader` and `Volume.setChannelDataFromVolume` ).
|
|
17
17
|
- (legacy) Load texture atlases as .png files or Uint8Arrays containing volume slices tiled across a 2d image ( see `JsonImageInfoLoader` and `Volume.setChannelDataFromAtlas` ).
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## Example
|
|
20
20
|
|
|
21
21
|
See [`public/index.ts`](./public/index.ts) for a working example. (`npm install; npm run dev` will run that code)
|
|
22
22
|
|
|
@@ -59,19 +59,20 @@ view3D.addVolume(volume);
|
|
|
59
59
|
loader.loadVolumeData(volume);
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
## React example
|
|
63
63
|
|
|
64
|
-
See [vole-app](https://github.com/allen-cell-animated/
|
|
64
|
+
See [vole-app](https://github.com/allen-cell-animated/vole-app) for a complete application that wraps View3D in a React component.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
## Acknowledgements
|
|
67
67
|
|
|
68
68
|
The ray marched volume shader is a heavily modified version of one that has its origins in [Bisque](http://bioimage.ucsb.edu/bisque).
|
|
69
69
|
The core path tracing implementation was adapted from ExposureRender.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
### BisQue license
|
|
72
72
|
|
|
73
73
|
Center for Bio-Image Informatics, University of California at Santa Barbara
|
|
74
74
|
|
|
75
|
+
```text
|
|
75
76
|
Copyright (c) 2007-2017 by the Regents of the University of California
|
|
76
77
|
All rights reserved
|
|
77
78
|
|
|
@@ -106,14 +107,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
106
107
|
The views and conclusions contained in the software and documentation
|
|
107
108
|
are those of the authors and should not be interpreted as representing
|
|
108
109
|
official policies, either expressed or implied, of the Regents of the University of California.
|
|
110
|
+
```
|
|
109
111
|
|
|
110
112
|
## Exposure Render license
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
```text
|
|
115
|
+
Copyright (c) 2011, T. Kroes <t.kroes@tudelft.nl>
|
|
116
|
+
All rights reserved.
|
|
117
|
+
|
|
118
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
119
|
+
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
120
|
+
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
121
|
+
- Neither the name of the TU Delft nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
118
122
|
|
|
119
|
-
|
|
123
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
124
|
+
```
|
package/es/View3d.js
CHANGED
|
@@ -826,16 +826,21 @@ export class View3d {
|
|
|
826
826
|
const prefetch = pane.addFolder({
|
|
827
827
|
title: "Prefetch"
|
|
828
828
|
});
|
|
829
|
+
// Not all `IVolumeLoader`s implement `updateFetchOptions`. This cast makes it sound to try to call it, but we
|
|
830
|
+
// still have to be careful to null-check it!
|
|
831
|
+
// TODO depending on how the relationship between loaders and images pans out, it's not impossible that the loader
|
|
832
|
+
// for an image will be changeable and this variable will capture a stale reference to old loaders. Careful!
|
|
833
|
+
const loader = this.image?.volume.loader;
|
|
829
834
|
// one number will be used for all axis directions
|
|
830
835
|
prefetch.addInput(allGlobalLoadingOptions, "numChunksToPrefetchAhead").on("change", event => {
|
|
831
|
-
|
|
836
|
+
loader?.updateFetchOptions?.({
|
|
832
837
|
maxPrefetchDistance: [event.value, event.value, event.value, event.value]
|
|
833
838
|
});
|
|
834
839
|
this.image?.volume.updateRequiredData({});
|
|
835
840
|
});
|
|
836
841
|
// should we try to prefetch along Z even if we are only playing along T?
|
|
837
842
|
prefetch.addInput(allGlobalLoadingOptions, "prefetchAlongNonPlayingAxis").on("change", event => {
|
|
838
|
-
|
|
843
|
+
loader?.updateFetchOptions?.({
|
|
839
844
|
onlyPriorityDirections: !event.value
|
|
840
845
|
});
|
|
841
846
|
});
|
|
@@ -3,14 +3,23 @@ import { Euler, Vector2, Vector3 } from "three";
|
|
|
3
3
|
* Marks groups of related settings that may have changed.
|
|
4
4
|
*/
|
|
5
5
|
export let SettingsFlags = /*#__PURE__*/function (SettingsFlags) {
|
|
6
|
+
/** parameters: translation, rotation, scale, flipAxes */
|
|
6
7
|
SettingsFlags[SettingsFlags["TRANSFORM"] = 1] = "TRANSFORM";
|
|
8
|
+
/** parameters: gammaMin, gammaLevel, gammaMax, brightness*/
|
|
7
9
|
SettingsFlags[SettingsFlags["CAMERA"] = 2] = "CAMERA";
|
|
10
|
+
/** parameters: showBoundingBox, boundingBoxColor */
|
|
8
11
|
SettingsFlags[SettingsFlags["BOUNDING_BOX"] = 4] = "BOUNDING_BOX";
|
|
12
|
+
/** parameters: bounds, zSlice */
|
|
9
13
|
SettingsFlags[SettingsFlags["ROI"] = 8] = "ROI";
|
|
14
|
+
/** parameters: maskAlpha */
|
|
10
15
|
SettingsFlags[SettingsFlags["MASK_ALPHA"] = 16] = "MASK_ALPHA";
|
|
16
|
+
/** parameters: density, diffuse, specular, emissive, glossiness */
|
|
11
17
|
SettingsFlags[SettingsFlags["MATERIAL"] = 32] = "MATERIAL";
|
|
18
|
+
/** parameters: resolution, useInterpolation, pixelSamplingRate, primaryRayStepSize, secondaryRayStepSize*/
|
|
12
19
|
SettingsFlags[SettingsFlags["SAMPLING"] = 64] = "SAMPLING";
|
|
20
|
+
/** parameters: isOrtho, orthoScale, viewAxis, visible, maxProjectMode */
|
|
13
21
|
SettingsFlags[SettingsFlags["VIEW"] = 128] = "VIEW";
|
|
22
|
+
/** parameters: maskChannelIndex */
|
|
14
23
|
SettingsFlags[SettingsFlags["MASK_DATA"] = 256] = "MASK_DATA";
|
|
15
24
|
SettingsFlags[SettingsFlags["ALL"] = 1023] = "ALL";
|
|
16
25
|
return SettingsFlags;
|
|
@@ -19,7 +28,9 @@ export let Axis = /*#__PURE__*/function (Axis) {
|
|
|
19
28
|
Axis["X"] = "x";
|
|
20
29
|
Axis["Y"] = "y";
|
|
21
30
|
Axis["Z"] = "z";
|
|
31
|
+
/** Alias for NONE, indicates 3D mode */
|
|
22
32
|
Axis["XYZ"] = "";
|
|
33
|
+
/** No current axis, indicates 3D mode */
|
|
23
34
|
Axis["NONE"] = "";
|
|
24
35
|
return Axis;
|
|
25
36
|
}({});
|
package/es/loaders/TiffLoader.js
CHANGED
|
@@ -191,7 +191,9 @@ class TiffLoader extends ThreadableVolumeLoader {
|
|
|
191
191
|
bytesPerSample: getBytesPerSample(dims.pixeltype),
|
|
192
192
|
url: this.url
|
|
193
193
|
};
|
|
194
|
-
const worker = new Worker(new URL("../workers/FetchTiffWorker", import.meta.url)
|
|
194
|
+
const worker = new Worker(new URL("../workers/FetchTiffWorker", import.meta.url), {
|
|
195
|
+
type: "module"
|
|
196
|
+
});
|
|
195
197
|
worker.onmessage = e => {
|
|
196
198
|
if (e.data.isError) {
|
|
197
199
|
reject(deserializeError(e.data.error));
|
|
@@ -7,5 +7,5 @@ declare function SurfaceNets(data: any, dims: any, isovalue: any): {
|
|
|
7
7
|
vertices: number[][];
|
|
8
8
|
faces: number[][];
|
|
9
9
|
};
|
|
10
|
-
declare function ConstructTHREEGeometry(surfaceNetResult: any): BufferGeometry[];
|
|
10
|
+
declare function ConstructTHREEGeometry(surfaceNetResult: any): BufferGeometry<import("three").NormalBufferAttributes>[];
|
|
11
11
|
import { BufferGeometry } from "three/src/core/BufferGeometry";
|
|
@@ -33,7 +33,7 @@ export default class RayMarchedAtlasVolume implements VolumeRenderImpl {
|
|
|
33
33
|
private createGeometry;
|
|
34
34
|
private createTickMarks;
|
|
35
35
|
cleanup(): void;
|
|
36
|
-
doRender(renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | Texture): void;
|
|
36
|
+
doRender(renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | Texture | null): void;
|
|
37
37
|
get3dObject(): Group;
|
|
38
38
|
private setUniform;
|
|
39
39
|
updateActiveChannels(channelcolors: FuseChannel[], channeldata: Channel[]): void;
|
|
@@ -18,7 +18,7 @@ export declare class ThreeJsPanel {
|
|
|
18
18
|
scene: Scene;
|
|
19
19
|
private meshRenderTarget;
|
|
20
20
|
private meshRenderToBuffer;
|
|
21
|
-
animateFuncs: ((renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture) => void)[];
|
|
21
|
+
animateFuncs: ((renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | null) => void)[];
|
|
22
22
|
private inRenderLoop;
|
|
23
23
|
private requestedRender;
|
|
24
24
|
hasWebGL2: boolean;
|
|
@@ -81,7 +81,7 @@ export declare class ThreeJsPanel {
|
|
|
81
81
|
replaceCamera(newCam: PerspectiveCamera | OrthographicCamera): void;
|
|
82
82
|
replaceControls(newControls: TrackballControls): void;
|
|
83
83
|
switchViewMode(mode: string): void;
|
|
84
|
-
getMeshDepthTexture(): DepthTexture;
|
|
84
|
+
getMeshDepthTexture(): DepthTexture | null;
|
|
85
85
|
resize(comp: HTMLElement | null, w?: number, h?: number, _ow?: number, _oh?: number, _eOpts?: unknown): void;
|
|
86
86
|
setClearColor(color: Color, alpha: number): void;
|
|
87
87
|
getWidth(): number;
|
|
@@ -56,7 +56,7 @@ export default class VolumeDrawable {
|
|
|
56
56
|
setGamma(gmin: number, glevel: number, gmax: number): void;
|
|
57
57
|
setFlipAxes(flipX: -1 | 1, flipY: -1 | 1, flipZ: -1 | 1): void;
|
|
58
58
|
setMaxProjectMode(isMaxProject: boolean): void;
|
|
59
|
-
onAnimate(renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | Texture): void;
|
|
59
|
+
onAnimate(renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | Texture | null): void;
|
|
60
60
|
getViewMode(): Axis;
|
|
61
61
|
getIsovalue(channel: number): number | undefined;
|
|
62
62
|
hasIsosurface(channel: number): boolean;
|
|
@@ -13,7 +13,7 @@ export interface VolumeRenderImpl {
|
|
|
13
13
|
*/
|
|
14
14
|
updateSettings: (settings: VolumeRenderSettings, dirtyFlags?: number | SettingsFlags) => void;
|
|
15
15
|
get3dObject: () => Object3D;
|
|
16
|
-
doRender: (renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | Texture) => void;
|
|
16
|
+
doRender: (renderer: WebGLRenderer, camera: PerspectiveCamera | OrthographicCamera, depthTexture?: DepthTexture | Texture | null) => void;
|
|
17
17
|
updateVolumeDimensions: () => void;
|
|
18
18
|
cleanup: () => void;
|
|
19
19
|
viewpointMoved: () => void;
|
package/es/types/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { Light, AREA_LIGHT, SKY_LIGHT } from "./Light.js";
|
|
|
22
22
|
export type { ImageInfo } from "./ImageInfo.js";
|
|
23
23
|
export type { ControlPoint } from "./Lut.js";
|
|
24
24
|
export type { CreateLoaderOptions } from "./loaders/index.js";
|
|
25
|
-
export type { IVolumeLoader, PerChannelCallback } from "./loaders/IVolumeLoader.js";
|
|
25
|
+
export type { IVolumeLoader, PerChannelCallback, ThreadableVolumeLoader } from "./loaders/IVolumeLoader.js";
|
|
26
26
|
export type { ZarrLoaderFetchOptions } from "./loaders/OmeZarrLoader.js";
|
|
27
27
|
export type { WorkerLoader } from "./workers/VolumeLoaderContext.js";
|
|
28
28
|
export { Histogram, Lut, remapControlPoints, View3d, Volume, VolumeDrawable, LoadSpec, VolumeMaker, VolumeCache, RequestQueue, SubscribableRequestQueue, PrefetchDirection, OMEZarrLoader, JsonImageInfoLoader, RawArrayLoader, type RawArrayData, type RawArrayInfo, type RawArrayLoaderOptions, TiffLoader, VolumeLoaderContext, VolumeLoadError, VolumeLoadErrorType, VolumeFileFormat, createVolumeLoader, Channel, Light, ViewportCorner, AREA_LIGHT, RENDERMODE_PATHTRACE, RENDERMODE_RAYMARCH, SKY_LIGHT, type CameraState, };
|
|
@@ -4,9 +4,8 @@ import { CreateLoaderOptions, PrefetchDirection } from "../loaders/index.js";
|
|
|
4
4
|
import { ThreadableVolumeLoader, LoadSpec, RawChannelDataCallback, LoadedVolumeInfo } from "../loaders/IVolumeLoader.js";
|
|
5
5
|
import { RawArrayLoader } from "../loaders/RawArrayLoader.js";
|
|
6
6
|
import { TiffLoader } from "../loaders/TiffLoader.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ChannelLoadEvent, MetadataUpdateEvent, WorkerMsgTypeGlobal, WorkerMsgTypeWithLoader, WorkerRequestPayload, WorkerResponsePayload } from "./types.js";
|
|
8
8
|
import type { ZarrLoaderFetchOptions } from "../loaders/OmeZarrLoader.js";
|
|
9
|
-
import { WorkerMsgType } from "./types.js";
|
|
10
9
|
/**
|
|
11
10
|
* A handle that holds the worker and manages requests and messages to/from it.
|
|
12
11
|
*
|
|
@@ -22,9 +21,7 @@ declare class SharedLoadWorkerHandle {
|
|
|
22
21
|
private worker;
|
|
23
22
|
private pendingRequests;
|
|
24
23
|
private workerOpen;
|
|
25
|
-
|
|
26
|
-
onChannelData: ((e: ChannelLoadEvent) => void) | undefined;
|
|
27
|
-
onUpdateMetadata: ((e: MetadataUpdateEvent) => void) | undefined;
|
|
24
|
+
onEvent: ((e: ChannelLoadEvent | MetadataUpdateEvent) => void) | undefined;
|
|
28
25
|
constructor();
|
|
29
26
|
/** Given a handle for settling a promise when a response is received from the worker, store it and return its ID */
|
|
30
27
|
private registerMessagePromise;
|
|
@@ -35,16 +32,16 @@ declare class SharedLoadWorkerHandle {
|
|
|
35
32
|
* Send a message of type `T` to the worker.
|
|
36
33
|
* Returns a `Promise` that resolves with the worker's response, or rejects with an error message.
|
|
37
34
|
*/
|
|
38
|
-
sendMessage<T extends
|
|
35
|
+
sendMessage<T extends WorkerMsgTypeGlobal>(type: T, payload: WorkerRequestPayload<T>): Promise<WorkerResponsePayload<T>>;
|
|
36
|
+
sendMessage<T extends WorkerMsgTypeWithLoader>(type: T, payload: WorkerRequestPayload<T>, loaderId: number): Promise<WorkerResponsePayload<T>>;
|
|
39
37
|
/** Receive a message from the worker. If it's an event, call a callback; otherwise, resolve/reject a promise. */
|
|
40
38
|
private receiveMessage;
|
|
41
|
-
setThrottleChannelData(throttle: boolean): void;
|
|
42
39
|
}
|
|
43
40
|
/**
|
|
44
41
|
* A context in which volume loaders can be run, which allows loading to run on a WebWorker (where it won't block
|
|
45
42
|
* rendering or UI updates) and loaders to share a single `VolumeCache` and `RequestQueue`.
|
|
46
43
|
*
|
|
47
|
-
*
|
|
44
|
+
* # To use:
|
|
48
45
|
* 1. Create a `VolumeLoaderContext` with the desired cache and queue configuration.
|
|
49
46
|
* 2. Before creating a loader, await `onOpen` to ensure the worker is ready.
|
|
50
47
|
* 3. Create a loader with `createLoader`. This accepts nearly the same arguments as `createVolumeLoader`, but without
|
|
@@ -56,14 +53,15 @@ declare class SharedLoadWorkerHandle {
|
|
|
56
53
|
*/
|
|
57
54
|
declare class VolumeLoaderContext {
|
|
58
55
|
private workerHandle;
|
|
56
|
+
private loaders;
|
|
59
57
|
private openPromise;
|
|
60
|
-
private
|
|
61
|
-
private activeLoaderId;
|
|
58
|
+
private throttleChannelData;
|
|
62
59
|
constructor(maxCacheSize?: number, maxActiveRequests?: number, maxLowPriorityRequests?: number);
|
|
63
60
|
/** Returns a `Promise` that resolves when the worker is ready. `await` it before trying to create a loader. */
|
|
64
61
|
onOpen(): Promise<void>;
|
|
65
62
|
/** Close this context, its worker, and any active loaders. */
|
|
66
63
|
close(): void;
|
|
64
|
+
private handleEvent;
|
|
67
65
|
/**
|
|
68
66
|
* Create a new loader within this context. This loader will share the context's `VolumeCache` and `RequestQueue`.
|
|
69
67
|
*
|
|
@@ -71,7 +69,6 @@ declare class VolumeLoaderContext {
|
|
|
71
69
|
*/
|
|
72
70
|
createLoader(path: string | string[], options?: Omit<CreateLoaderOptions, "cache" | "queue">): Promise<WorkerLoader | TiffLoader | RawArrayLoader>;
|
|
73
71
|
setThrottleChannelData(throttle: boolean): void;
|
|
74
|
-
getActiveLoader(): WorkerLoader | undefined;
|
|
75
72
|
}
|
|
76
73
|
/**
|
|
77
74
|
* A handle to an instance of `IVolumeLoader` (technically, a `ThreadableVolumeLoader`) running on a WebWorker.
|
|
@@ -81,12 +78,11 @@ declare class VolumeLoaderContext {
|
|
|
81
78
|
declare class WorkerLoader extends ThreadableVolumeLoader {
|
|
82
79
|
private loaderId;
|
|
83
80
|
private workerHandle;
|
|
84
|
-
private isOpen;
|
|
85
81
|
private currentLoadId;
|
|
86
82
|
private currentLoadCallback;
|
|
87
83
|
private currentMetadataUpdateCallback;
|
|
88
84
|
constructor(loaderId: number, workerHandle: SharedLoadWorkerHandle);
|
|
89
|
-
private
|
|
85
|
+
private getLoaderId;
|
|
90
86
|
/** Close and permanently invalidate this loader. */
|
|
91
87
|
close(): void;
|
|
92
88
|
/**
|
|
@@ -9,13 +9,18 @@ import type { ZarrLoaderFetchOptions } from "../loaders/OmeZarrLoader.js";
|
|
|
9
9
|
export declare const enum WorkerMsgType {
|
|
10
10
|
INIT = 0,
|
|
11
11
|
CREATE_LOADER = 1,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
CLOSE_LOADER = 2,
|
|
13
|
+
CREATE_VOLUME = 3,
|
|
14
|
+
LOAD_DIMS = 4,
|
|
15
|
+
LOAD_VOLUME_DATA = 5,
|
|
16
|
+
SET_PREFETCH_PRIORITY_DIRECTIONS = 6,
|
|
17
|
+
SYNCHRONIZE_MULTICHANNEL_LOADING = 7,
|
|
18
|
+
UPDATE_FETCH_OPTIONS = 8
|
|
18
19
|
}
|
|
20
|
+
/** The variants of `WorkerMessageType` which represent "global" actions that don't require a specific loader */
|
|
21
|
+
export type WorkerMsgTypeGlobal = WorkerMsgType.INIT | WorkerMsgType.CREATE_LOADER;
|
|
22
|
+
/** The variants of `WorkerMessageType` which represent actions on a specific loader */
|
|
23
|
+
export type WorkerMsgTypeWithLoader = Exclude<WorkerMsgType, WorkerMsgTypeGlobal>;
|
|
19
24
|
/** The kind of response a worker can return - `SUCCESS`, `ERROR`, or `EVENT`. */
|
|
20
25
|
export declare const enum WorkerResponseResult {
|
|
21
26
|
SUCCESS = 0,
|
|
@@ -29,9 +34,13 @@ export declare const enum WorkerEventType {
|
|
|
29
34
|
/** Fired when data for a channel (or batch of channels) is loaded */
|
|
30
35
|
CHANNEL_LOAD = 1
|
|
31
36
|
}
|
|
32
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* All messages to/from a worker carry a `msgId`, a `type`, and a `payload` (whose type is determined by `type`).
|
|
39
|
+
* Messages which operate on a specific loader also require a `loaderId`.
|
|
40
|
+
*/
|
|
33
41
|
type WorkerMsgBase<T extends WorkerMsgType, P> = {
|
|
34
42
|
msgId: number;
|
|
43
|
+
loaderId: T extends WorkerMsgTypeWithLoader ? number : undefined;
|
|
35
44
|
type: T;
|
|
36
45
|
payload: P;
|
|
37
46
|
};
|
|
@@ -46,12 +55,12 @@ export type WorkerRequestPayload<T extends WorkerMsgType> = {
|
|
|
46
55
|
path: string | string[];
|
|
47
56
|
options?: CreateLoaderOptions;
|
|
48
57
|
};
|
|
58
|
+
[WorkerMsgType.CLOSE_LOADER]: void;
|
|
49
59
|
[WorkerMsgType.CREATE_VOLUME]: LoadSpec;
|
|
50
60
|
[WorkerMsgType.LOAD_DIMS]: LoadSpec;
|
|
51
61
|
[WorkerMsgType.LOAD_VOLUME_DATA]: {
|
|
52
62
|
imageInfo: ImageInfo;
|
|
53
63
|
loadSpec: LoadSpec;
|
|
54
|
-
loaderId: number;
|
|
55
64
|
loadId: number;
|
|
56
65
|
};
|
|
57
66
|
[WorkerMsgType.SET_PREFETCH_PRIORITY_DIRECTIONS]: PrefetchDirection[];
|
|
@@ -61,7 +70,8 @@ export type WorkerRequestPayload<T extends WorkerMsgType> = {
|
|
|
61
70
|
/** Maps each `WorkerMsgType` to the type of the payload of responses of that type. */
|
|
62
71
|
export type WorkerResponsePayload<T extends WorkerMsgType> = {
|
|
63
72
|
[WorkerMsgType.INIT]: void;
|
|
64
|
-
[WorkerMsgType.CREATE_LOADER]:
|
|
73
|
+
[WorkerMsgType.CREATE_LOADER]: number | undefined;
|
|
74
|
+
[WorkerMsgType.CLOSE_LOADER]: void;
|
|
65
75
|
[WorkerMsgType.CREATE_VOLUME]: LoadedVolumeInfo;
|
|
66
76
|
[WorkerMsgType.LOAD_DIMS]: VolumeDims[];
|
|
67
77
|
[WorkerMsgType.LOAD_VOLUME_DATA]: void;
|
|
@@ -69,11 +79,13 @@ export type WorkerResponsePayload<T extends WorkerMsgType> = {
|
|
|
69
79
|
[WorkerMsgType.SYNCHRONIZE_MULTICHANNEL_LOADING]: void;
|
|
70
80
|
[WorkerMsgType.UPDATE_FETCH_OPTIONS]: void;
|
|
71
81
|
}[T];
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
eventType: WorkerEventType.CHANNEL_LOAD;
|
|
82
|
+
type WorkerEventBase<T extends WorkerEventType> = {
|
|
83
|
+
eventType: T;
|
|
75
84
|
loaderId: number;
|
|
76
85
|
loadId: number;
|
|
86
|
+
};
|
|
87
|
+
/** Event for when a batch of channel data loads. */
|
|
88
|
+
export type ChannelLoadEvent = WorkerEventBase<WorkerEventType.CHANNEL_LOAD> & {
|
|
77
89
|
channelIndex: number[];
|
|
78
90
|
dtype: NumberType[];
|
|
79
91
|
data: TypedArray<NumberType>[];
|
|
@@ -81,10 +93,7 @@ export type ChannelLoadEvent = {
|
|
|
81
93
|
atlasDims?: [number, number];
|
|
82
94
|
};
|
|
83
95
|
/** Event for when metadata updates. */
|
|
84
|
-
export type MetadataUpdateEvent = {
|
|
85
|
-
eventType: WorkerEventType.METADATA_UPDATE;
|
|
86
|
-
loaderId: number;
|
|
87
|
-
loadId: number;
|
|
96
|
+
export type MetadataUpdateEvent = WorkerEventBase<WorkerEventType.METADATA_UPDATE> & {
|
|
88
97
|
imageInfo?: ImageInfo;
|
|
89
98
|
loadSpec?: LoadSpec;
|
|
90
99
|
};
|
|
@@ -9,9 +9,16 @@ import { rebuildLoadSpec } from "./util.js";
|
|
|
9
9
|
let cache = undefined;
|
|
10
10
|
let queue = undefined;
|
|
11
11
|
let subscribableQueue = undefined;
|
|
12
|
-
let
|
|
12
|
+
let loaderCount = 0;
|
|
13
|
+
const loaders = new Map();
|
|
14
|
+
const getLoader = loaderId => {
|
|
15
|
+
const loader = loaders.get(loaderId);
|
|
16
|
+
if (loader === undefined) {
|
|
17
|
+
throw new VolumeLoadError(`Loader with ID ${loaderId} does not exist`);
|
|
18
|
+
}
|
|
19
|
+
return loader;
|
|
20
|
+
};
|
|
13
21
|
let initialized = false;
|
|
14
|
-
let copyOnLoad = false;
|
|
15
22
|
const messageHandlers = {
|
|
16
23
|
[WorkerMsgType.INIT]: ({
|
|
17
24
|
maxCacheSize,
|
|
@@ -30,37 +37,50 @@ const messageHandlers = {
|
|
|
30
37
|
path,
|
|
31
38
|
options
|
|
32
39
|
}) => {
|
|
33
|
-
const
|
|
34
|
-
const fileType = options?.fileType || pathToFileType(pathString);
|
|
35
|
-
copyOnLoad = fileType === VolumeFileFormat.JSON;
|
|
36
|
-
loader = await createVolumeLoader(path, {
|
|
40
|
+
const loader = await createVolumeLoader(path, {
|
|
37
41
|
...options,
|
|
38
42
|
cache,
|
|
39
43
|
queue: subscribableQueue
|
|
40
44
|
});
|
|
41
|
-
return loader !== undefined;
|
|
42
|
-
},
|
|
43
|
-
[WorkerMsgType.CREATE_VOLUME]: async loadSpec => {
|
|
44
45
|
if (loader === undefined) {
|
|
45
|
-
|
|
46
|
+
return undefined;
|
|
46
47
|
}
|
|
48
|
+
const pathString = Array.isArray(path) ? path[0] : path;
|
|
49
|
+
const fileType = options?.fileType || pathToFileType(pathString);
|
|
50
|
+
const copyOnLoad = fileType === VolumeFileFormat.JSON;
|
|
51
|
+
const loaderId = loaderCount;
|
|
52
|
+
loaderCount += 1;
|
|
53
|
+
loaders.set(loaderId, {
|
|
54
|
+
loader,
|
|
55
|
+
copyOnLoad
|
|
56
|
+
});
|
|
57
|
+
return loaderId;
|
|
58
|
+
},
|
|
59
|
+
[WorkerMsgType.CLOSE_LOADER]: (_, loaderId) => {
|
|
60
|
+
loaders.delete(loaderId);
|
|
61
|
+
return Promise.resolve();
|
|
62
|
+
},
|
|
63
|
+
[WorkerMsgType.CREATE_VOLUME]: async (loadSpec, loaderId) => {
|
|
64
|
+
const {
|
|
65
|
+
loader
|
|
66
|
+
} = getLoader(loaderId);
|
|
47
67
|
return await loader.createImageInfo(rebuildLoadSpec(loadSpec));
|
|
48
68
|
},
|
|
49
|
-
[WorkerMsgType.LOAD_DIMS]: async loadSpec => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
69
|
+
[WorkerMsgType.LOAD_DIMS]: async (loadSpec, loaderId) => {
|
|
70
|
+
const {
|
|
71
|
+
loader
|
|
72
|
+
} = getLoader(loaderId);
|
|
53
73
|
return await loader.loadDims(rebuildLoadSpec(loadSpec));
|
|
54
74
|
},
|
|
55
75
|
[WorkerMsgType.LOAD_VOLUME_DATA]: ({
|
|
56
76
|
imageInfo,
|
|
57
77
|
loadSpec,
|
|
58
|
-
loaderId,
|
|
59
78
|
loadId
|
|
60
|
-
}) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
}, loaderId) => {
|
|
80
|
+
const {
|
|
81
|
+
loader,
|
|
82
|
+
copyOnLoad
|
|
83
|
+
} = getLoader(loaderId);
|
|
64
84
|
return loader.loadRawChannelData(imageInfo, rebuildLoadSpec(loadSpec), (imageInfo, loadSpec) => {
|
|
65
85
|
const message = {
|
|
66
86
|
responseResult: WorkerResponseResult.EVENT,
|
|
@@ -86,16 +106,25 @@ const messageHandlers = {
|
|
|
86
106
|
self.postMessage(message, copyOnLoad ? [] : data.map(d => d.buffer));
|
|
87
107
|
});
|
|
88
108
|
},
|
|
89
|
-
[WorkerMsgType.SET_PREFETCH_PRIORITY_DIRECTIONS]: directions => {
|
|
109
|
+
[WorkerMsgType.SET_PREFETCH_PRIORITY_DIRECTIONS]: (directions, loaderId) => {
|
|
110
|
+
const {
|
|
111
|
+
loader
|
|
112
|
+
} = getLoader(loaderId);
|
|
90
113
|
// Silently does nothing if the loader isn't an `OMEZarrLoader`
|
|
91
114
|
loader?.setPrefetchPriority(directions);
|
|
92
115
|
return Promise.resolve();
|
|
93
116
|
},
|
|
94
|
-
[WorkerMsgType.SYNCHRONIZE_MULTICHANNEL_LOADING]: syncChannels => {
|
|
117
|
+
[WorkerMsgType.SYNCHRONIZE_MULTICHANNEL_LOADING]: (syncChannels, loaderId) => {
|
|
118
|
+
const {
|
|
119
|
+
loader
|
|
120
|
+
} = getLoader(loaderId);
|
|
95
121
|
loader?.syncMultichannelLoading(syncChannels);
|
|
96
122
|
return Promise.resolve();
|
|
97
123
|
},
|
|
98
|
-
[WorkerMsgType.UPDATE_FETCH_OPTIONS]: fetchOptions => {
|
|
124
|
+
[WorkerMsgType.UPDATE_FETCH_OPTIONS]: (fetchOptions, loaderId) => {
|
|
125
|
+
const {
|
|
126
|
+
loader
|
|
127
|
+
} = getLoader(loaderId);
|
|
99
128
|
loader?.updateFetchOptions(fetchOptions);
|
|
100
129
|
return Promise.resolve();
|
|
101
130
|
}
|
|
@@ -103,25 +132,18 @@ const messageHandlers = {
|
|
|
103
132
|
self.onmessage = async ({
|
|
104
133
|
data
|
|
105
134
|
}) => {
|
|
106
|
-
const {
|
|
107
|
-
msgId,
|
|
108
|
-
type,
|
|
109
|
-
payload
|
|
110
|
-
} = data;
|
|
111
135
|
let message;
|
|
112
136
|
try {
|
|
113
|
-
const response = await messageHandlers[type](payload);
|
|
137
|
+
const response = await messageHandlers[data.type](data.payload, data.loaderId);
|
|
114
138
|
message = {
|
|
139
|
+
...data,
|
|
115
140
|
responseResult: WorkerResponseResult.SUCCESS,
|
|
116
|
-
msgId,
|
|
117
|
-
type,
|
|
118
141
|
payload: response
|
|
119
142
|
};
|
|
120
143
|
} catch (e) {
|
|
121
144
|
message = {
|
|
145
|
+
...data,
|
|
122
146
|
responseResult: WorkerResponseResult.ERROR,
|
|
123
|
-
msgId,
|
|
124
|
-
type,
|
|
125
147
|
payload: serializeError(e)
|
|
126
148
|
};
|
|
127
149
|
}
|