Skip to content

Instantly share code, notes, and snippets.

@romanlv
Created December 19, 2022 17:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romanlv/4f3c78b661bd530779d488189461032a to your computer and use it in GitHub Desktop.
Save romanlv/4f3c78b661bd530779d488189461032a to your computer and use it in GitHub Desktop.
OG Image Generation without next.js and edge runtime
import satori from "satori";
import type { SatoriOptions } from "satori";
import { Resvg } from "@resvg/resvg-js";
import fs from "fs";
import { join } from "path";
import { ReactElement } from "react";
const fallbackFont = fs.readFileSync(
join(
// fileURLToPath(import.meta.url),
".",
"assets/fonts/noto-sans-v27-latin-regular.ttf"
)
);
type Options = {
width: number;
height: number;
debug: boolean;
fonts?: SatoriOptions["fonts"];
};
// reversed engineered version of @vercel/og
// https://vercel.com/docs/concepts/functions/edge-functions/og-image-api
// that does not depend on wasm modules
// so works in pure node env
export async function renderToImage(
node: ReactElement,
options: Options = {
width: 1200,
height: 630,
debug: !1,
}
) {
const svg = await satori(node, {
width: options.width,
height: options.height,
debug: options.debug,
fonts: options.fonts || [
{
name: "sans serif",
data: fallbackFont,
weight: 700,
style: "normal",
},
],
// loadAdditionalAsset: F({
// emoji: options.emoji,
// }),
});
const w = new Resvg(svg, {
fitTo: {
mode: "width",
value: options.width,
},
});
return {
image: w.render().asPng(),
contentType: "image/png",
};
}
{
"dependencies": {
"@resvg/resvg-js": "^2.2.0",
"react": "^18.2.0",
"satori": "^0.0.44"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment