Files
buzz-sheet/lib/image-export/export.worker.ts
T

72 lines
2.3 KiB
TypeScript

import { init, Renderer } from "takumi-js/wasm/no-init";
import type { WorkerRequest, WorkerResult } from "./types";
import { renderExport } from "./render";
let rendererPromise: Promise<Renderer> | undefined;
async function getRenderer(origin: string) {
rendererPromise ??= (async () => {
const response = await fetch(new URL("/takumi.wasm", origin), {
signal: AbortSignal.timeout(15000),
});
if (!response.ok) throw new Error("Unable to load image renderer");
await init({ module_or_path: await response.arrayBuffer() });
const renderer = new Renderer();
try {
const fonts = await Promise.all(
[
{ name: "Anuphan", path: "/Anuphan.ttf" },
{ name: "Genshin Overview", path: "/zh-cn.ttf" },
{
name: "Kanit Overview",
path: "/Kanit-SemiBold.ttf",
weight: 600,
style: "normal" as const,
},
{
name: "Kanit Poster",
path: "/Kanit-ExtraBoldItalic.ttf",
weight: 800,
style: "italic" as const,
},
].map(async ({ path, ...descriptor }) => {
const font = await fetch(new URL(path, origin), {
signal: AbortSignal.timeout(15000),
});
if (!font.ok) throw new Error("Unable to load export fonts");
return {
...descriptor,
data: new Uint8Array(await font.arrayBuffer()),
};
}),
);
for (const font of fonts) await renderer.registerFont(font);
return renderer;
} catch (error) {
renderer.free();
throw error;
}
})().catch((error) => {
rendererPromise = undefined;
throw error;
});
return rendererPromise;
}
let queue = Promise.resolve();
self.onmessage = ({ data }: MessageEvent<WorkerRequest>) => {
queue = queue.then(async () => {
try {
const renderer = await getRenderer(data.origin);
const image = await renderExport(renderer, data.request, data.origin);
const bytes = image.buffer as ArrayBuffer;
self.postMessage({ id: data.id, bytes } satisfies WorkerResult, {
transfer: [bytes],
});
} catch (error) {
self.postMessage({
id: data.id,
error: error instanceof Error ? error.message : "Image export failed",
} satisfies WorkerResult);
}
});
};