function renderTextAsync(textContent, options = {}) {
function workerCode() {
self.onmessage = function (e) {
const { textContent, options } = e.data;
const {
family = "Arial",
size = 10,
resolution = 2,
canvas = new OffscreenCanvas(0, 0)
} = options || {};
const ctx = canvas.getContext("2d");
const font = `${size * resolution}px ${family}`;
ctx.font = font;
const metrics = ctx.measureText(textContent);
const ascent = Math.round(metrics.actualBoundingBoxAscent);
const descent = Math.round(metrics.actualBoundingBoxDescent);
const left = Math.round(metrics.actualBoundingBoxLeft);
const right = Math.round(metrics.actualBoundingBoxRight);
const width = left + right;
const height = ascent + descent;
canvas.width = width;
canvas.height = height;
ctx.font = font;
ctx.fillStyle = "black";
ctx.fillText(textContent, left, ascent);
canvas.convertToBlob().then((blob) => {
const reader = new FileReader();
reader.onload = () => {
self.postMessage({
width,
height,
data: reader.result
});
};
reader.readAsDataURL(blob);
});
};
}
let src = workerCode.toString();
src = src.split(/\n/g).slice(1, -1).join("\n");
let blob = new Blob([src], { type: "text/javascript" });
let objectURL = URL.createObjectURL(blob);
return new Promise((resolve) => {
const worker = new Worker(objectURL, { type: "module" });
if (options.canvas) {
worker.postMessage({ textContent, options }, [options.canvas]);
} else {
worker.postMessage({ textContent, options });
}
worker.onmessage = (e) => {
const { width, height, data } = e.data;
worker.terminate();
resolve({ width, height, data });
};
});
}