/** * WASM Worker Bridge — runs OpenCV operations in a Web Worker. * * The worker loads opencv.js (~10MB) in its own thread. * Main thread stays responsive during WASM compilation. * * Lazy-creates the worker on first call. Sends ImageData + * params, gets back results via transferable buffers. */ import type { EdgeDetectionParams, EdgeDetectionResult, EdgeDetectionDebugResult } from './edges' import type { SegmentationParams, SegmentationDebugResult } from './segmentation' let worker: Worker | null = null let messageId = 0 const pending = new Map void; reject: (e: Error) => void }>() let initPromise: Promise | null = null let ready = false let failed = false function getWorker(): Worker { if (!worker) { worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' }) worker.onmessage = (event) => { const { id, type, error: errMsg, ...data } = event.data const handler = pending.get(id) if (!handler) return pending.delete(id) if (type === 'error') { handler.reject(new Error(errMsg ?? 'Worker error')) } else { handler.resolve(data) } } worker.onerror = (event) => { // Reject all pending for (const [, handler] of pending) { handler.reject(new Error(event.message ?? 'Worker crashed')) } pending.clear() } } return worker } function postMessage(type: string, imageData: ImageData, params: Record): Promise { return new Promise((resolve, reject) => { const id = ++messageId pending.set(id, { resolve, reject }) getWorker().postMessage({ id, type, imageData, params }, [imageData.data.buffer]) }) } /** Initialize the worker + load WASM. Returns true if ready. */ export async function initWasm(): Promise { if (ready) return true if (failed) return false if (initPromise) return initPromise initPromise = (async () => { try { // Send a ping — the worker will load opencv.js on first message const result = await postMessage('ping', new ImageData(1, 1), {}) ready = true return true } catch { failed = true return false } })() return initPromise } export function isWasmReady(): boolean { return ready } export function isWasmFailed(): boolean { return failed } // --- Edge detection --- export async function detectEdgesWasm( imageData: ImageData, params: Partial, ): Promise { const data = await postMessage('detect_edges', imageData, params as Record) return { regions: data.regions } } export async function detectEdgesWasmDebug( imageData: ImageData, params: Partial, ): Promise { const data = await postMessage('detect_edges_debug', imageData, params as Record) return { regions: data.regions, edgeImageData: data.edgeImageData, linesImageData: data.linesImageData, horizontalCount: data.horizontalCount, pairCount: data.pairCount, } } // --- Segmentation --- export async function segmentFieldWasmDebug( imageData: ImageData, params: Partial, ): Promise { const data = await postMessage('segment_field_debug', imageData, params as Record) return { boundary: data.boundary, coverage: data.coverage, maskImageData: data.maskImageData, overlayImageData: data.overlayImageData, } }