Open Graph image
Create social media images locally in your browser. Share the link. Nothing is
uploaded.
Inter Display
DejaVu Sans Mono
Download #
JavaScript #
This ES module uses static WebAssembly instance imports and includes SVG, PNG,
and WebP output. Remove imports and output calls that your application does not use.
import * as ogImageRenderer from "./text-to-og-image-svg-inter.wasm";
import * as svgRasterizer from "./svg-rasterize-to-bmp-b8g8r8a8-srgb.wasm";
import * as pngEncoder from "./bmp-to-png.wasm";
import * as webpEncoder from "./bmp-b8g8r8a8-srgb-to-webp-lossless.wasm";
const encoder = new TextEncoder();
const decoder = new TextDecoder("utf-8", { fatal: true });
function renderOutput(exports, inputSize) {
const result = BigInt.asUintN(64, exports.render(inputSize));
if ((result >> 63n) !== 0n) throw new Error("rejected input");
return {
size: Number(result & 0xffff_ffffn),
ptr: Number((result >> 32n) & 0x7fff_ffffn),
};
}
export function renderOGImageToSVG({
title = "",
subtitle = "",
textColor = 0xffffffff,
backgroundColor = 0x4b2e83ff,
fontMaxSize = 112,
fontWeight = 700,
} = {}) {
const form = new URLSearchParams({ title, subtitle }).toString();
const input = new Uint8Array(
ogImageRenderer.memory.buffer,
ogImageRenderer.input_ptr(),
ogImageRenderer.input_utf8_cap(),
);
const { read, written } = encoder.encodeInto(form, input);
if (read !== form.length) {
throw new RangeError("Open Graph image input is too large");
}
ogImageRenderer.uniform_set_text_color_rgba(textColor);
ogImageRenderer.uniform_set_background_color_rgba(backgroundColor);
ogImageRenderer.uniform_set_font_max_size(fontMaxSize);
ogImageRenderer.uniform_set_font_weight(fontWeight);
const output = renderOutput(ogImageRenderer, written);
if (output.size > ogImageRenderer.output_utf8_cap()) {
throw new RangeError("Open Graph image output is too large");
}
return decoder.decode(new Uint8Array(
ogImageRenderer.memory.buffer,
output.ptr,
output.size,
));
}
export function renderOGImageToPNG(options) {
const svg = renderOGImageToSVG(options);
const input = new Uint8Array(
svgRasterizer.memory.buffer,
svgRasterizer.input_ptr(),
svgRasterizer.input_utf8_cap(),
);
const { read, written } = encoder.encodeInto(svg, input);
if (read !== svg.length) {
throw new RangeError("Open Graph SVG is too large to rasterize");
}
const bmpOutput = renderOutput(svgRasterizer, written);
if (bmpOutput.size > svgRasterizer.output_bytes_cap()) {
throw new RangeError("Open Graph BMP output is too large");
}
const bmp = new Uint8Array(
svgRasterizer.memory.buffer,
bmpOutput.ptr,
bmpOutput.size,
);
if (bmp.length > pngEncoder.input_bytes_cap()) {
throw new RangeError("Open Graph BMP input is too large");
}
new Uint8Array(
pngEncoder.memory.buffer,
pngEncoder.input_ptr(),
bmp.length,
).set(bmp);
const pngOutput = renderOutput(pngEncoder, bmp.length);
if (pngOutput.size > pngEncoder.output_bytes_cap()) {
throw new RangeError("Open Graph PNG output is too large");
}
return new Uint8Array(
pngEncoder.memory.buffer,
pngOutput.ptr,
pngOutput.size,
).slice();
}
export function renderOGImageToWebp(options) {
const svg = renderOGImageToSVG(options);
const input = new Uint8Array(
svgRasterizer.memory.buffer,
svgRasterizer.input_ptr(),
svgRasterizer.input_utf8_cap(),
);
const { read, written } = encoder.encodeInto(svg, input);
if (read !== svg.length) {
throw new RangeError("Open Graph SVG is too large to rasterize");
}
const bmpOutput = renderOutput(svgRasterizer, written);
if (bmpOutput.size > svgRasterizer.output_bytes_cap()) {
throw new RangeError("Open Graph BMP output is too large");
}
const bmp = new Uint8Array(
svgRasterizer.memory.buffer,
bmpOutput.ptr,
bmpOutput.size,
);
if (bmp.length > webpEncoder.input_bytes_cap()) {
throw new RangeError("Open Graph BMP input is too large");
}
new Uint8Array(
webpEncoder.memory.buffer,
webpEncoder.input_ptr(),
bmp.length,
).set(bmp);
const webpOutput = renderOutput(webpEncoder, bmp.length);
if (webpOutput.size > webpEncoder.output_bytes_cap()) {
throw new RangeError("Open Graph WebP output is too large");
}
return new Uint8Array(
webpEncoder.memory.buffer,
webpOutput.ptr,
webpOutput.size,
).slice();
}
const options = {
title: "Reusable components",
subtitle: "Rendered locally with embedded Inter paths",
textColor: 0xffffffff,
backgroundColor: 0x4b2e83ff,
fontMaxSize: 112,
fontWeight: 700,
};
const svg = renderOGImageToSVG(options);
const png = renderOGImageToPNG(options);
const webp = renderOGImageToWebp(options);
console.log({ svg, png, webp });