/ concept-collection / numbl-image-filter
Sign in
concept-collection / numbl-image-filter
numbl-image-filter / src / filter.worker.ts
70 lines · 2.0 KBCodeBlameHistory
c2ebacaInitial commit: numbl image filter web appJeremy Magland 1/// <reference lib="webworker" />
2/**
3 * Runs a numbl filter script off the main thread so full-resolution images
4 * with per-pixel scripts don't freeze the page.
5 *
6 * Contract: the script defines a function (default name `filterImage`) that
7 * takes the image array `img` (H x W x 3 doubles, 0-255) and returns a new
8 * image array. If the script has no function header it is run as-is with
9 * `img` predefined and `out` read back.
10 */
11import { executeCode, RTV } from "numbl";
12import type { RuntimeValue } from "numbl";
13import {
14 rgbaToTensorData,
15 tensorToRaw,
16 extractFunctionName,
17} from "./imageConvert.ts";
18import type { FilterRequest, FilterResponse } from "./filterTypes.ts";
20self.onmessage = (e: MessageEvent<FilterRequest>) => {
21 const { id, script, width, height, rgba } = e.data;
22 const logs: string[] = [];
23 try {
24 const { data, shape } = rgbaToTensorData(rgba, width, height);
25 const img = RTV.tensor(data, shape);
27 const fnName = extractFunctionName(script);
28 const source = fnName ? `out = ${fnName}(img);` : script;
29 const workspaceFiles = fnName
30 ? [{ name: `${fnName}.m`, source: script }]
31 : [];
33 const t0 = performance.now();
34 const result = executeCode(
35 source,
36 {
37 initialVariableValues: { img },
38 optimization: "1", // JS-JIT; browser-safe
39 displayResults: false,
40 onOutput: (text: string) => logs.push(text),
41 },
42 workspaceFiles,
43 "main.m"
44 );
45 const elapsedMs = performance.now() - t0;
47 const out: RuntimeValue | undefined =
48 result.variableValues.out ?? result.returnValue;
49 const image = tensorToRaw(out);
51 const response: FilterResponse = {
52 id,
53 ok: true,
54 width: image.width,
55 height: image.height,
56 rgba: image.rgba,
57 logs,
58 elapsedMs,
59 };
60 self.postMessage(response, [image.rgba.buffer]);
61 } catch (err) {
62 const response: FilterResponse = {
63 id,
64 ok: false,
65 error: err instanceof Error ? err.message : String(err),
66 logs,
67 };
68 self.postMessage(response);
69 }
70};
moveopenescclose