import { readFileSync } from "node:fs";
import { join } from "node:path";
import type { OgRuntime } from "./render";
/** Bun counterpart of runtime.ts for tests and scripts/og-samples.tsx: the same precompiled modules, read from disk. */
export function loadRuntimeFromDisk(): OgRuntime {
const root = join(import.meta.dir, "../../..");
const bytes = (path: string) => {
const buffer = readFileSync(join(root, path));
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer;
};
return {
yoga: new WebAssembly.Module(bytes("node_modules/satori/yoga.wasm")),
resvg: new WebAssembly.Module(bytes("node_modules/@resvg/resvg-wasm/index_bg.wasm")),
fonts: {
regular: bytes("src/server/og/fonts/plex-sans-400.bin"),
semibold: bytes("src/server/og/fonts/plex-sans-600.bin"),
},
};
}
const IHDR_END = 24;
/** Width and height from a PNG's IHDR chunk, or null when the bytes are not a PNG. */
export function pngSize(png: Uint8Array): { width: number; height: number } | null {
const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
if (png.length < IHDR_END || signature.some((byte, index) => png[index] !== byte)) return null;
const view = new DataView(png.buffer, png.byteOffset, png.byteLength);
return { width: view.getUint32(16), height: view.getUint32(20) };
}