@fideus-labs/ngff-zarr 0.8.0 → 0.9.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/esm/browser-mod.d.ts +2 -2
- package/esm/browser-mod.d.ts.map +1 -1
- package/esm/browser-mod.js +2 -2
- package/esm/browser-mod.js.map +1 -1
- package/esm/mod.d.ts +1 -1
- package/esm/mod.d.ts.map +1 -1
- package/esm/mod.js +1 -1
- package/esm/mod.js.map +1 -1
- package/esm/utils/compute_omero-shared.d.ts +12 -0
- package/esm/utils/compute_omero-shared.d.ts.map +1 -1
- package/esm/utils/compute_omero-shared.js +28 -0
- package/esm/utils/compute_omero-shared.js.map +1 -1
- package/esm/utils/compute_omero.d.ts +10 -38
- package/esm/utils/compute_omero.d.ts.map +1 -1
- package/esm/utils/compute_omero.js +332 -79
- package/esm/utils/compute_omero.js.map +1 -1
- package/esm/utils/omero_worker_rpc.d.ts +37 -0
- package/esm/utils/omero_worker_rpc.d.ts.map +1 -0
- package/esm/utils/omero_worker_rpc.js +156 -0
- package/esm/utils/omero_worker_rpc.js.map +1 -0
- package/esm/workers/omero_codec_worker.d.ts +2 -0
- package/esm/workers/omero_codec_worker.d.ts.map +1 -0
- package/esm/workers/omero_codec_worker.js +215 -0
- package/esm/workers/omero_codec_worker.js.map +1 -0
- package/package.json +2 -3
- package/esm/utils/compute_omero-browser.d.ts +0 -45
- package/esm/utils/compute_omero-browser.d.ts.map +0 -1
- package/esm/utils/compute_omero-browser.js +0 -250
- package/esm/utils/compute_omero-browser.js.map +0 -1
- package/esm/workers/compute_omero_worker.d.ts +0 -47
- package/esm/workers/compute_omero_worker.d.ts.map +0 -1
- package/esm/workers/compute_omero_worker.js +0 -113
- package/esm/workers/compute_omero_worker.js.map +0 -1
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
/**
|
|
4
|
-
* Browser-specific OMERO metadata computation using WebWorker.
|
|
5
|
-
* This module offloads CPU-intensive statistics computation to a WebWorker
|
|
6
|
-
* to prevent blocking the main thread.
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - WebWorker-based computation via Comlink
|
|
10
|
-
* - Chunked streaming for memory efficiency with large images
|
|
11
|
-
* - Automatic fallback to main thread if WebWorker unavailable
|
|
12
|
-
* - Inline worker code (bundled as Blob URL)
|
|
13
|
-
*/
|
|
14
|
-
import * as Comlink from "comlink";
|
|
15
|
-
import { buildOmeroFromAccumulators, createAccumulator, extractChannel, updateAccumulator, validateQuantiles, } from "./compute_omero-shared.js";
|
|
16
|
-
import { zarrGet } from "./worker_pool.js";
|
|
17
|
-
// Re-export shared utilities for convenience
|
|
18
|
-
export { getDefaultColors, GLASBEY_COLORS, } from "./compute_omero-shared.js";
|
|
19
|
-
// Worker state
|
|
20
|
-
let worker = null;
|
|
21
|
-
let workerProxy = null;
|
|
22
|
-
let workerSupported = null;
|
|
23
|
-
let workerBlobUrl = null;
|
|
24
|
-
// Chunk size for streaming (256K elements = ~1MB for float32)
|
|
25
|
-
const CHUNK_SIZE = 256 * 1024;
|
|
26
|
-
/**
|
|
27
|
-
* Check if WebWorkers are supported in this environment.
|
|
28
|
-
*/
|
|
29
|
-
function isWorkerSupported() {
|
|
30
|
-
if (workerSupported === null) {
|
|
31
|
-
try {
|
|
32
|
-
workerSupported = typeof Worker !== "undefined" &&
|
|
33
|
-
typeof Blob !== "undefined" &&
|
|
34
|
-
typeof URL !== "undefined" &&
|
|
35
|
-
typeof URL.createObjectURL === "function";
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
workerSupported = false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return workerSupported;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Get or create the worker proxy.
|
|
45
|
-
* Returns null if workers are not supported.
|
|
46
|
-
*/
|
|
47
|
-
function getWorkerProxy() {
|
|
48
|
-
if (!isWorkerSupported()) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
if (!workerProxy) {
|
|
52
|
-
try {
|
|
53
|
-
// In bundled builds, the Worker constructor line below is replaced with
|
|
54
|
-
// inline Blob URL code that assigns workerBlobUrl. In non-bundled mode,
|
|
55
|
-
// we use a module URL and there's no Blob URL to clean up.
|
|
56
|
-
workerBlobUrl = null; // Will be overwritten in bundled mode
|
|
57
|
-
worker = (() => {
|
|
58
|
-
const workerCode = `var L=Symbol("Comlink.proxy"),q=Symbol("Comlink.endpoint"),v=Symbol("Comlink.releaseProxy"),y=Symbol("Comlink.finalizer"),B=Symbol("Comlink.thrown"),P=t=>typeof t=="object"&&t!==null||typeof t=="function",H={canHandle:t=>P(t)&&t[L],serialize(t){let{port1:e,port2:n}=new MessageChannel;return w(t,e),[n,[n]]},deserialize(t){return t.start(),j(t)}},\$={canHandle:t=>P(t)&&B in t,serialize({value:t}){let e;return t instanceof Error?e={isError:!0,value:{message:t.message,name:t.name,stack:t.stack}}:e={isError:!1,value:t},[e,[]]},deserialize(t){throw t.isError?Object.assign(new Error(t.value.message),t.value):t.value}},I=new Map([["proxy",H],["throw",\$]]);function U(t,e){for(let n of t)if(e===n||n==="*"||n instanceof RegExp&&n.test(e))return!0;return!1}function w(t,e=globalThis,n=["*"]){e.addEventListener("message",function o(r){if(!r||!r.data)return;if(!U(n,r.origin)){console.warn(\`Invalid origin '\${r.origin}' for comlink proxy\`);return}let{id:a,type:c,path:u}=Object.assign({path:[]},r.data),l=(r.data.argumentList||[]).map(E),i;try{let s=u.slice(0,-1).reduce((f,A)=>f[A],t),F=u.reduce((f,A)=>f[A],t);switch(c){case"GET":i=F;break;case"SET":s[u.slice(-1)[0]]=E(r.data.value),i=!0;break;case"APPLY":i=F.apply(s,l);break;case"CONSTRUCT":{let f=new F(...l);i=Z(f)}break;case"ENDPOINT":{let{port1:f,port2:A}=new MessageChannel;w(t,A),i=V(f,[f])}break;case"RELEASE":i=void 0;break;default:return}}catch(s){i={value:s,[B]:0}}Promise.resolve(i).catch(s=>({value:s,[B]:0})).then(s=>{let[F,f]=p(s);e.postMessage(Object.assign(Object.assign({},F),{id:a}),f),c==="RELEASE"&&(e.removeEventListener("message",o),T(e),y in t&&typeof t[y]=="function"&&t[y]())}).catch(s=>{let[F,f]=p({value:new TypeError("Unserializable return value"),[B]:0});e.postMessage(Object.assign(Object.assign({},F),{id:a}),f)})}),e.start&&e.start()}function G(t){return t.constructor.name==="MessagePort"}function T(t){G(t)&&t.close()}function j(t,e){let n=new Map;return t.addEventListener("message",function(r){let{data:a}=r;if(!a||!a.id)return;let c=n.get(a.id);if(c)try{c(a)}finally{n.delete(a.id)}}),x(t,n,[],e)}function h(t){if(t)throw new Error("Proxy has been released and is not useable")}function k(t){return m(t,new Map,{type:"RELEASE"}).then(()=>{T(t)})}var g=new WeakMap,d="FinalizationRegistry"in globalThis&&new FinalizationRegistry(t=>{let e=(g.get(t)||0)-1;g.set(t,e),e===0&&k(t)});function Q(t,e){let n=(g.get(e)||0)+1;g.set(e,n),d&&d.register(t,e,t)}function W(t){d&&d.unregister(t)}function x(t,e,n=[],o=function(){}){let r=!1,a=new Proxy(o,{get(c,u){if(h(r),u===v)return()=>{W(a),k(t),e.clear(),r=!0};if(u==="then"){if(n.length===0)return{then:()=>a};let l=m(t,e,{type:"GET",path:n.map(i=>i.toString())}).then(E);return l.then.bind(l)}return x(t,e,[...n,u])},set(c,u,l){h(r);let[i,s]=p(l);return m(t,e,{type:"SET",path:[...n,u].map(F=>F.toString()),value:i},s).then(E)},apply(c,u,l){h(r);let i=n[n.length-1];if(i===q)return m(t,e,{type:"ENDPOINT"}).then(E);if(i==="bind")return x(t,e,n.slice(0,-1));let[s,F]=O(l);return m(t,e,{type:"APPLY",path:n.map(f=>f.toString()),argumentList:s},F).then(E)},construct(c,u){h(r);let[l,i]=O(u);return m(t,e,{type:"CONSTRUCT",path:n.map(s=>s.toString()),argumentList:l},i).then(E)}});return Q(a,t),a}function Y(t){return Array.prototype.concat.apply([],t)}function O(t){let e=t.map(p);return[e.map(n=>n[0]),Y(e.map(n=>n[1]))]}var z=new WeakMap;function V(t,e){return z.set(t,e),t}function Z(t){return Object.assign(t,{[L]:!0})}function p(t){for(let[e,n]of I)if(n.canHandle(t)){let[o,r]=n.serialize(t);return[{type:"HANDLER",name:e,value:o},r]}return[{type:"RAW",value:t},z.get(t)||[]]}function E(t){switch(t.type){case"HANDLER":return I.get(t.name).deserialize(t.value);case"RAW":return t.value}}function m(t,e,n,o){return new Promise(r=>{let a=X();e.set(a,r),t.start&&t.start(),t.postMessage(Object.assign({id:a},n),o)})}function X(){return new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")}var _=["30A2DA","FC4F30","E5AE38","6D904F","8B8B8B","17BECF","9467BD","D62728","1F77B4","E377C2","8C564B","BCBD22","3A0183","004300","0FFFA9","5E0040","C6BDFF","425052","B80080","FFB7B3","7D0200","6126FF","FFFF9A","AEC9AB","00867C","553A00","94FCFF","00BF00","7D00A0","AB7200","91FF00","01BE8A","00457B","C8826F","FF1F83","DD00FF","057400","644461","888FFF","FFB6F4","536237","CE85FF","686A84","BEB4BE","A56089","95D3FF","0100F8","FF8002","8B2945","ADA06D","53458B","C8FFD9","AA4600","FF798F","83D371","909EBF","9400F5","EBD09B","AD8BB1","00634A","FFDC00","887751","7EABA3","000097","F500C6","653329","006678","04E3C8","A737AE","C5DBE1","4D6EFF","9B9301","CD586B","EFDEFE","795A00","5F889A","B4FF92","5E726B","520066","058751","84206F","3C9605","657300","F1A06C","5F5045","BD004A","D06827","D796AB","895DFF","826C76","2B55B9","6E7CBB","E7D5D3","5D0018","7C3B01","80B17D","C8D97D","00E83B","7CB2FF","FF55FF","A42721","1DE4FF","7DAF3B","7B4B91","E0FF48","6B00C4","CDA897","BE63C4","89CDCE","4603C8","5E9279","414A01","05A79D","CF8C37","FFF8D0","435471","B544FF","CF4993","CFA4DF","94D400","A794DA","2DA558","8DE3B6","A4A99D","6C5CB7","FF7E5E","A7838A","AFBED8","2AC4FF","A6683D","F691FE","874B64","FF0C4B","215E23","4292FF","87839D","672D45","B14F41","004E53","5F1B00","AD4167","503267","D6FFFD","7FB5D1","A9B969","FF96CB","C87495","365039","FFD063","5E5862","879476","A978FF","03C863","E7BED4","D4E3D0","876790","897C27","CDDCFF","AA676B","323474","FF5EA9","009BB0","71FFDD","785C38","50659B","CC00B3","577B55","516E7B","015F92","AABDBE","017F99","04DD97","873A2C","F0968E","75C6AA","70695D","CCDC09","AF8557","D80075","9D3F81","D94500","DD6754","5FFF79","D5B173","62265E","BAA23D","D9F2B3","57028F","A19BAA","4D4A27","A4A9FF","ACE8DB","995901","AC00E2","47822F","CBC3AD","00C5B6","615378","336D68","A59280","8499A2","FD5764","7096D2","728D07","7F004C","1530A0","D1C1E2","C985D0","6C454B","7F0024","00A279","B2A9CF","F90000","B0E9FF","939E50","727A82","D92E55","476101","0059FF","7740B5","ACE460","674525","525D51","957368","A9E49A","A30058","D962F6","8E7DCF","FFBD93","A30092","9AFFB9","A7C2FF","F46200","E5F0FF","B89CA4","609694","FF9F35","8C2900","726B32","DF824E","AF7BD5","BC2D00","7B6FA3","484362","C7A3FF","004D28","C4C68E","E048D7","E7E965","E5C10B","00F4F1","9F5BA2","4C41B7","65338E","767E6C","A98A36"];function K(t){return t===1?["FFFFFF"]:Array.from({length:t},(e,n)=>_[n%_.length])}function b(t){let[e,n]=t;if(!(e>=0&&e<=1))throw new Error(\`Low quantile must be between 0 and 1, got \${e}\`);if(!(n>=0&&n<=1))throw new Error(\`High quantile must be between 0 and 1, got \${n}\`);if(e>=n)throw new Error(\`Low quantile must be less than high quantile, got (\${e}, \${n})\`)}function tt(t){if(!/^[0-9A-Fa-f]{6}\$/.test(t))throw new Error(\`Color must be a 6-digit hexadecimal string without # prefix, got '\${t}'\`)}function R(t,e){if(t.length===0)return NaN;if(t.length===1)return t[0];let n=e*(t.length-1),o=Math.floor(n),r=Math.ceil(n),a=n-o;return o===r?t[o]:t[o]*(1-a)+t[r]*a}function N(){return{min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY,sample:[],count:0}}function D(t,e){for(let n=0;n<e.length;n++){let o=e[n];if(!Number.isNaN(o)){if(o<t.min&&(t.min=o),o>t.max&&(t.max=o),t.sample.length<1e4)t.sample.push(o);else{let r=Math.floor(Math.random()*(t.count+1));r<1e4&&(t.sample[r]=o)}t.count++}}}function et(t,e){if(t.count===0)return{min:NaN,max:NaN,qLow:NaN,qHigh:NaN};t.sample.sort((r,a)=>r-a);let n=R(t.sample,e[0]),o=R(t.sample,e[1]);return{min:t.min,max:t.max,qLow:n,qHigh:o}}function S(t,e,n,o){let r=e[o],a=1;for(let s=o+1;s<e.length;s++)a*=e[s];let c=1;for(let s=0;s<o;s++)c*=e[s];let u=c*a,l=new Array(u),i=0;for(let s=0;s<c;s++){let f=s*r*a+n*a;for(let A=0;A<a;A++)l[i++]=t[f+A]}return l}function M(t,e,n,o){let r=t.length,a;if(n!==void 0){if(n.length<r)throw new Error(\`Not enough colors provided. Got \${n.length}, need \${r}.\`);for(let l of n.slice(0,r))tt(l);a=n.slice(0,r)}else a=K(r);let c;if(o!==void 0){if(o.length<r)throw new Error(\`Not enough labels provided. Got \${o.length}, need \${r}.\`);c=o.slice(0,r)}else c=Array(r).fill("");return{channels:t.map((l,i)=>{let s=et(l,e),F={min:s.min,max:s.max,start:s.qLow,end:s.qHigh};return{color:a[i],window:F,label:c[i]}})}}var C=null,nt={initializeComputation(t){b(t.quantiles);let e=t.dims.indexOf("c"),n=e!==-1?t.shape[e]:1;C={accumulators:Array.from({length:n},()=>N()),input:t}},processChunk(t){if(!C)throw new Error("Computation not initialized. Call initializeComputation first.");let{accumulators:e,input:n}=C,{shape:o,dims:r}=n,{chunkData:a}=t,c=r.indexOf("c");if(c!==-1)for(let l=0;l<e.length;l++){let i=S(a,o,l,c);D(e[l],i)}else D(e[0],a)},finalizeComputation(){if(!C)throw new Error("Computation not initialized. Call initializeComputation first.");let{accumulators:t,input:e}=C,n=M(t,e.quantiles,e.colors,e.labels);return C=null,n},computeOmero(t,e){b(e.quantiles);let{shape:n,dims:o,quantiles:r,colors:a,labels:c}=e,u=o.indexOf("c"),l=u!==-1,i=l?n[u]:1,s=Array.from({length:i},()=>N());if(l)for(let F=0;F<i;F++){let f=S(t,n,F,u);D(s[F],f)}else D(s[0],t);return M(s,r,a,c)},ping(){return"pong"}};w(nt);
|
|
59
|
-
/*! Bundled license information:
|
|
60
|
-
|
|
61
|
-
comlink/dist/esm/comlink.mjs:
|
|
62
|
-
(**
|
|
63
|
-
* @license
|
|
64
|
-
* Copyright 2019 Google LLC
|
|
65
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
66
|
-
*)
|
|
67
|
-
*/
|
|
68
|
-
`;
|
|
69
|
-
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
70
|
-
const url = URL.createObjectURL(blob);
|
|
71
|
-
workerBlobUrl = url;
|
|
72
|
-
return new Worker(url, { type: "module" });
|
|
73
|
-
})();
|
|
74
|
-
workerProxy = Comlink.wrap(worker);
|
|
75
|
-
}
|
|
76
|
-
catch (e) {
|
|
77
|
-
// Worker creation failed, fall back to main thread
|
|
78
|
-
console.warn("Failed to create OMERO computation worker:", e);
|
|
79
|
-
workerSupported = false;
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return workerProxy;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Compute OMERO metadata on the main thread (fallback implementation).
|
|
87
|
-
* Used when WebWorker is not available.
|
|
88
|
-
*/
|
|
89
|
-
async function computeOmeroMainThread(image, options = {}) {
|
|
90
|
-
const quantiles = options.quantiles ?? [0.02, 0.98];
|
|
91
|
-
validateQuantiles(quantiles);
|
|
92
|
-
const dims = image.dims;
|
|
93
|
-
const shape = image.data.shape;
|
|
94
|
-
// Check if there's a channel dimension
|
|
95
|
-
const cIndex = dims.indexOf("c");
|
|
96
|
-
const hasChannelDim = cIndex !== -1;
|
|
97
|
-
const nChannels = hasChannelDim ? shape[cIndex] : 1;
|
|
98
|
-
// Read all data from the zarr array
|
|
99
|
-
const result = await zarrGet(image.data);
|
|
100
|
-
const fullData = result.data;
|
|
101
|
-
// Create accumulators for each channel
|
|
102
|
-
const accumulators = Array.from({ length: nChannels }, () => createAccumulator());
|
|
103
|
-
if (hasChannelDim) {
|
|
104
|
-
// Multi-channel: extract each channel and compute statistics
|
|
105
|
-
for (let chIdx = 0; chIdx < nChannels; chIdx++) {
|
|
106
|
-
const channelData = extractChannel(fullData, shape, chIdx, cIndex);
|
|
107
|
-
updateAccumulator(accumulators[chIdx], channelData);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
// Single channel: compute directly
|
|
112
|
-
updateAccumulator(accumulators[0], fullData);
|
|
113
|
-
}
|
|
114
|
-
return buildOmeroFromAccumulators(accumulators, quantiles, options.colors, options.labels);
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Compute OMERO metadata from an NgffImage using WebWorker.
|
|
118
|
-
*
|
|
119
|
-
* This function computes visualization parameters (OMERO metadata) from image data:
|
|
120
|
-
* - min/max: The actual data range
|
|
121
|
-
* - start/end: Display window based on quantiles (default 2% and 98%)
|
|
122
|
-
*
|
|
123
|
-
* For multi-channel images (with 'c' dimension), statistics are computed
|
|
124
|
-
* separately for each channel, resulting in per-channel OMERO windows.
|
|
125
|
-
*
|
|
126
|
-
* The computation is performed in a WebWorker to avoid blocking the main thread.
|
|
127
|
-
* If WebWorkers are not available, falls back to main thread computation.
|
|
128
|
-
*
|
|
129
|
-
* @param image - The NgffImage to compute metadata for
|
|
130
|
-
* @param options - Optional configuration for quantiles, colors, and labels
|
|
131
|
-
* @returns Promise resolving to Omero metadata with computed window parameters
|
|
132
|
-
*/
|
|
133
|
-
export async function computeOmeroFromNgffImage(image, options = {}) {
|
|
134
|
-
const api = getWorkerProxy();
|
|
135
|
-
// Fallback to main thread if worker unavailable
|
|
136
|
-
if (!api) {
|
|
137
|
-
return computeOmeroMainThread(image, options);
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
const quantiles = options.quantiles ?? [0.02, 0.98];
|
|
141
|
-
const shape = image.data.shape;
|
|
142
|
-
const dims = image.dims;
|
|
143
|
-
// Read data from zarr array
|
|
144
|
-
const result = await zarrGet(image.data);
|
|
145
|
-
const fullData = result.data;
|
|
146
|
-
const totalSize = fullData.length;
|
|
147
|
-
// For small datasets, use single-call API
|
|
148
|
-
if (totalSize <= CHUNK_SIZE * 2) {
|
|
149
|
-
// Transfer the data buffer to the worker
|
|
150
|
-
const typedArray = fullData;
|
|
151
|
-
// Create a copy of the buffer that we can transfer
|
|
152
|
-
const buffer = new ArrayBuffer(typedArray.byteLength);
|
|
153
|
-
const view = new Uint8Array(buffer);
|
|
154
|
-
view.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength));
|
|
155
|
-
const TypedArrayConstructor = typedArray.constructor;
|
|
156
|
-
return await api.computeOmero(Comlink.transfer(new TypedArrayConstructor(buffer), [buffer]), {
|
|
157
|
-
shape,
|
|
158
|
-
dims,
|
|
159
|
-
quantiles: quantiles,
|
|
160
|
-
colors: options.colors,
|
|
161
|
-
labels: options.labels,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
// For large datasets, use streaming API
|
|
165
|
-
await api.initializeComputation({
|
|
166
|
-
shape,
|
|
167
|
-
dims,
|
|
168
|
-
quantiles: quantiles,
|
|
169
|
-
colors: options.colors,
|
|
170
|
-
labels: options.labels,
|
|
171
|
-
});
|
|
172
|
-
// Stream data in chunks
|
|
173
|
-
const typedArray = fullData;
|
|
174
|
-
for (let offset = 0; offset < totalSize; offset += CHUNK_SIZE) {
|
|
175
|
-
const end = Math.min(offset + CHUNK_SIZE, totalSize);
|
|
176
|
-
const chunk = typedArray.slice(offset, end);
|
|
177
|
-
// Create a copy of the chunk buffer that we can transfer
|
|
178
|
-
const chunkBuffer = new ArrayBuffer(chunk.byteLength);
|
|
179
|
-
const chunkView = new Uint8Array(chunkBuffer);
|
|
180
|
-
chunkView.set(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
181
|
-
const ChunkConstructor = chunk.constructor;
|
|
182
|
-
await api.processChunk({
|
|
183
|
-
chunkData: Comlink.transfer(new ChunkConstructor(chunkBuffer), [
|
|
184
|
-
chunkBuffer,
|
|
185
|
-
]),
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
// Finalize and return result
|
|
189
|
-
return await api.finalizeComputation();
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
// Fallback to main thread on any error
|
|
193
|
-
console.warn("WebWorker OMERO computation failed, falling back to main thread:", error);
|
|
194
|
-
return computeOmeroMainThread(image, options);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Compute OMERO metadata from a Multiscales object using WebWorker.
|
|
199
|
-
*
|
|
200
|
-
* This is a convenience function that computes OMERO metadata from the
|
|
201
|
-
* highest resolution image in a multiscales pyramid for accurate statistics.
|
|
202
|
-
*
|
|
203
|
-
* @param multiscales - The Multiscales object to compute metadata for
|
|
204
|
-
* @param options - Optional configuration for quantiles, colors, and labels
|
|
205
|
-
* @returns Promise resolving to Omero metadata with computed window parameters
|
|
206
|
-
*/
|
|
207
|
-
export async function computeOmeroFromMultiscales(multiscales, options = {}) {
|
|
208
|
-
if (!multiscales.images || multiscales.images.length === 0) {
|
|
209
|
-
throw new Error("Multiscales has no images");
|
|
210
|
-
}
|
|
211
|
-
// Always use the highest resolution (first) image for accurate statistics
|
|
212
|
-
const image = multiscales.images[0];
|
|
213
|
-
const computeOptions = {};
|
|
214
|
-
if (options.quantiles !== undefined) {
|
|
215
|
-
computeOptions.quantiles = options.quantiles;
|
|
216
|
-
}
|
|
217
|
-
if (options.colors !== undefined) {
|
|
218
|
-
computeOptions.colors = options.colors;
|
|
219
|
-
}
|
|
220
|
-
if (options.labels !== undefined) {
|
|
221
|
-
computeOptions.labels = options.labels;
|
|
222
|
-
}
|
|
223
|
-
return await computeOmeroFromNgffImage(image, computeOptions);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Terminate the OMERO computation worker and release resources.
|
|
227
|
-
* Call this when you're done with OMERO computations to free memory.
|
|
228
|
-
*/
|
|
229
|
-
export function terminateOmeroWorker() {
|
|
230
|
-
if (workerProxy) {
|
|
231
|
-
workerProxy[Comlink.releaseProxy]();
|
|
232
|
-
workerProxy = null;
|
|
233
|
-
}
|
|
234
|
-
if (worker) {
|
|
235
|
-
worker.terminate();
|
|
236
|
-
worker = null;
|
|
237
|
-
}
|
|
238
|
-
if (workerBlobUrl) {
|
|
239
|
-
URL.revokeObjectURL(workerBlobUrl);
|
|
240
|
-
workerBlobUrl = null;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Check if the OMERO computation will use a WebWorker.
|
|
245
|
-
* Useful for testing or conditional logic.
|
|
246
|
-
*/
|
|
247
|
-
export function isUsingWorker() {
|
|
248
|
-
return isWorkerSupported() && getWorkerProxy() !== null;
|
|
249
|
-
}
|
|
250
|
-
//# sourceMappingURL=compute_omero-browser.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compute_omero-browser.js","sourceRoot":"","sources":["../../src/utils/compute_omero-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { type ComputeOmeroChunkInput, type ComputeOmeroWorkerInput } from "../utils/compute_omero-shared.js";
|
|
2
|
-
import type { Omero } from "../types/zarr_metadata.js";
|
|
3
|
-
/**
|
|
4
|
-
* Worker API exposed via Comlink.
|
|
5
|
-
*
|
|
6
|
-
* IMPORTANT: This worker maintains global state and does not support
|
|
7
|
-
* concurrent computations. Only one computation can be active at a time.
|
|
8
|
-
* If initializeComputation is called while another computation is in
|
|
9
|
-
* progress, the previous computation state will be lost.
|
|
10
|
-
*
|
|
11
|
-
* The typical workflow is:
|
|
12
|
-
* 1. initializeComputation() - Start a new computation
|
|
13
|
-
* 2. processChunk() - Call multiple times to stream data
|
|
14
|
-
* 3. finalizeComputation() - Get results and reset state
|
|
15
|
-
*/
|
|
16
|
-
declare const workerApi: {
|
|
17
|
-
/**
|
|
18
|
-
* Initialize a new OMERO computation.
|
|
19
|
-
* Must be called before processChunk.
|
|
20
|
-
*
|
|
21
|
-
* WARNING: This will overwrite any existing computation state.
|
|
22
|
-
* Do not call this if another computation is in progress.
|
|
23
|
-
*/
|
|
24
|
-
initializeComputation(input: ComputeOmeroWorkerInput): void;
|
|
25
|
-
/**
|
|
26
|
-
* Process a chunk of data.
|
|
27
|
-
* Call this multiple times for streaming large datasets.
|
|
28
|
-
*/
|
|
29
|
-
processChunk(chunkInput: ComputeOmeroChunkInput): void;
|
|
30
|
-
/**
|
|
31
|
-
* Finalize computation and return OMERO metadata.
|
|
32
|
-
* Resets state after returning.
|
|
33
|
-
*/
|
|
34
|
-
finalizeComputation(): Omero;
|
|
35
|
-
/**
|
|
36
|
-
* Compute OMERO metadata in a single call (non-streaming).
|
|
37
|
-
* Useful for smaller datasets where streaming overhead isn't needed.
|
|
38
|
-
*/
|
|
39
|
-
computeOmero(data: ArrayLike<number>, input: ComputeOmeroWorkerInput): Omero;
|
|
40
|
-
/**
|
|
41
|
-
* Check if worker is ready.
|
|
42
|
-
*/
|
|
43
|
-
ping(): string;
|
|
44
|
-
};
|
|
45
|
-
export type ComputeOmeroWorkerApi = typeof workerApi;
|
|
46
|
-
export {};
|
|
47
|
-
//# sourceMappingURL=compute_omero_worker.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compute_omero_worker.d.ts","sourceRoot":"","sources":["../../src/workers/compute_omero_worker.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAK7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAYvD;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,SAAS;IACb;;;;;;OAMG;iCAC0B,uBAAuB,GAAG,IAAI;IAe3D;;;OAGG;6BACsB,sBAAsB,GAAG,IAAI;IA0BtD;;;OAGG;2BACoB,KAAK;IAqB5B;;;OAGG;uBAEK,SAAS,CAAC,MAAM,CAAC,SAChB,uBAAuB,GAC7B,KAAK;IA4BR;;OAEG;YACK,MAAM;CAGf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,SAAS,CAAC"}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
/**
|
|
4
|
-
* WebWorker for computing OMERO metadata.
|
|
5
|
-
* This worker performs CPU-intensive statistics computation off the main thread.
|
|
6
|
-
*/
|
|
7
|
-
import * as Comlink from "comlink";
|
|
8
|
-
import { buildOmeroFromAccumulators, createAccumulator, extractChannel, updateAccumulator, validateQuantiles, } from "../utils/compute_omero-shared.js";
|
|
9
|
-
let currentState = null;
|
|
10
|
-
/**
|
|
11
|
-
* Worker API exposed via Comlink.
|
|
12
|
-
*
|
|
13
|
-
* IMPORTANT: This worker maintains global state and does not support
|
|
14
|
-
* concurrent computations. Only one computation can be active at a time.
|
|
15
|
-
* If initializeComputation is called while another computation is in
|
|
16
|
-
* progress, the previous computation state will be lost.
|
|
17
|
-
*
|
|
18
|
-
* The typical workflow is:
|
|
19
|
-
* 1. initializeComputation() - Start a new computation
|
|
20
|
-
* 2. processChunk() - Call multiple times to stream data
|
|
21
|
-
* 3. finalizeComputation() - Get results and reset state
|
|
22
|
-
*/
|
|
23
|
-
const workerApi = {
|
|
24
|
-
/**
|
|
25
|
-
* Initialize a new OMERO computation.
|
|
26
|
-
* Must be called before processChunk.
|
|
27
|
-
*
|
|
28
|
-
* WARNING: This will overwrite any existing computation state.
|
|
29
|
-
* Do not call this if another computation is in progress.
|
|
30
|
-
*/
|
|
31
|
-
initializeComputation(input) {
|
|
32
|
-
validateQuantiles(input.quantiles);
|
|
33
|
-
const cIndex = input.dims.indexOf("c");
|
|
34
|
-
const nChannels = cIndex !== -1 ? input.shape[cIndex] : 1;
|
|
35
|
-
currentState = {
|
|
36
|
-
accumulators: Array.from({ length: nChannels }, () => createAccumulator()),
|
|
37
|
-
input,
|
|
38
|
-
};
|
|
39
|
-
},
|
|
40
|
-
/**
|
|
41
|
-
* Process a chunk of data.
|
|
42
|
-
* Call this multiple times for streaming large datasets.
|
|
43
|
-
*/
|
|
44
|
-
processChunk(chunkInput) {
|
|
45
|
-
if (!currentState) {
|
|
46
|
-
throw new Error("Computation not initialized. Call initializeComputation first.");
|
|
47
|
-
}
|
|
48
|
-
const { accumulators, input } = currentState;
|
|
49
|
-
const { shape, dims } = input;
|
|
50
|
-
const { chunkData } = chunkInput;
|
|
51
|
-
const cIndex = dims.indexOf("c");
|
|
52
|
-
const hasChannelDim = cIndex !== -1;
|
|
53
|
-
if (hasChannelDim) {
|
|
54
|
-
// Multi-channel: extract each channel and update its accumulator
|
|
55
|
-
for (let chIdx = 0; chIdx < accumulators.length; chIdx++) {
|
|
56
|
-
const channelData = extractChannel(chunkData, shape, chIdx, cIndex);
|
|
57
|
-
updateAccumulator(accumulators[chIdx], channelData);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
// Single channel: update directly
|
|
62
|
-
updateAccumulator(accumulators[0], chunkData);
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
/**
|
|
66
|
-
* Finalize computation and return OMERO metadata.
|
|
67
|
-
* Resets state after returning.
|
|
68
|
-
*/
|
|
69
|
-
finalizeComputation() {
|
|
70
|
-
if (!currentState) {
|
|
71
|
-
throw new Error("Computation not initialized. Call initializeComputation first.");
|
|
72
|
-
}
|
|
73
|
-
const { accumulators, input } = currentState;
|
|
74
|
-
const result = buildOmeroFromAccumulators(accumulators, input.quantiles, input.colors, input.labels);
|
|
75
|
-
// Reset state
|
|
76
|
-
currentState = null;
|
|
77
|
-
return result;
|
|
78
|
-
},
|
|
79
|
-
/**
|
|
80
|
-
* Compute OMERO metadata in a single call (non-streaming).
|
|
81
|
-
* Useful for smaller datasets where streaming overhead isn't needed.
|
|
82
|
-
*/
|
|
83
|
-
computeOmero(data, input) {
|
|
84
|
-
validateQuantiles(input.quantiles);
|
|
85
|
-
const { shape, dims, quantiles, colors, labels } = input;
|
|
86
|
-
const cIndex = dims.indexOf("c");
|
|
87
|
-
const hasChannelDim = cIndex !== -1;
|
|
88
|
-
const nChannels = hasChannelDim ? shape[cIndex] : 1;
|
|
89
|
-
// Create accumulators for each channel
|
|
90
|
-
const accumulators = Array.from({ length: nChannels }, () => createAccumulator());
|
|
91
|
-
if (hasChannelDim) {
|
|
92
|
-
// Multi-channel: extract each channel and compute statistics
|
|
93
|
-
for (let chIdx = 0; chIdx < nChannels; chIdx++) {
|
|
94
|
-
const channelData = extractChannel(data, shape, chIdx, cIndex);
|
|
95
|
-
updateAccumulator(accumulators[chIdx], channelData);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
// Single channel: compute directly
|
|
100
|
-
updateAccumulator(accumulators[0], data);
|
|
101
|
-
}
|
|
102
|
-
return buildOmeroFromAccumulators(accumulators, quantiles, colors, labels);
|
|
103
|
-
},
|
|
104
|
-
/**
|
|
105
|
-
* Check if worker is ready.
|
|
106
|
-
*/
|
|
107
|
-
ping() {
|
|
108
|
-
return "pong";
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
// Expose the API via Comlink
|
|
112
|
-
Comlink.expose(workerApi);
|
|
113
|
-
//# sourceMappingURL=compute_omero_worker.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compute_omero_worker.js","sourceRoot":"","sources":["../../src/workers/compute_omero_worker.ts"],"names":[],"mappings":"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"}
|