import { decode, encode } from 'blurhash'; type Req = | { id: number; type: 'blurhashToBase64Image'; payload: { blurhash: string; width: number; height: number } } | { id: number; type: 'base64ImageToBlurhash'; payload: { base64Image: string } }; type Res = | { id: number; ok: true; data: string } | { id: number; ok: false; error: string }; const toBase64 = async (blurhash: string, width: number, height: number): Promise => { const pixels = decode(blurhash, width, height); const canvas = new OffscreenCanvas(width, height); const ctx = canvas.getContext('2d'); if (!ctx) throw new Error('No 2d context'); const imageData = ctx.createImageData(width, height); imageData.data.set(pixels); ctx.putImageData(imageData, 0, 0); const blob = await canvas.convertToBlob({ type: 'image/png' }); const buf = new Uint8Array(await blob.arrayBuffer()); let bin = ''; for (let i = 0; i < buf.length; i++) bin += String.fromCharCode(buf[i]); return `data:image/png;base64,${btoa(bin)}`; }; const toBlurhash = async (base64Image: string): Promise => { const src = base64Image?.trim(); if (!src) throw new Error('Empty image data'); const resp = await fetch(src); const blob = await resp.blob(); if (!blob.size) throw new Error('Image fetch returned empty blob'); const bitmap = await createImageBitmap(blob); const { width, height } = bitmap; if (!width || !height) { bitmap.close(); throw new Error(`Image has invalid size ${width}x${height}`); } const canvas = new OffscreenCanvas(width, height); const ctx = canvas.getContext('2d'); if (!ctx) { bitmap.close(); throw new Error('No 2d context'); } ctx.drawImage(bitmap, 0, 0, width, height); bitmap.close(); const imageData = ctx.getImageData(0, 0, width, height); return encode(imageData.data, imageData.width, imageData.height, 4, 4); }; self.onmessage = async (e: MessageEvent) => { const { id, type, payload } = e.data; const reply = (res: Res) => (self as unknown as Worker).postMessage(res); try { if (type === 'blurhashToBase64Image') { const data = await toBase64(payload.blurhash, payload.width, payload.height); reply({ id, ok: true, data }); } else if (type === 'base64ImageToBlurhash') { const data = await toBlurhash(payload.base64Image); reply({ id, ok: true, data }); } else { throw new Error(`Unknown type ${type}`); } } catch (err: any) { reply({ id, ok: false, error: String(err?.message ?? err) }); } };