UNPKG

@cf-wasm/og

Version:

Generate Open Graph Images dynamically from HTML/CSS without a browser.

139 lines (138 loc) 4.06 kB
const require_maps = require("./maps.cjs"); const require_font = require("./font.cjs"); const require_asset = require("./asset.cjs"); const require_resvg = require("./resvg.cjs"); const require_satori = require("./satori.cjs"); //#region src/core/render.ts /** Default render options */ const RENDER_DEFAULT_OPTIONS = { width: 1200, height: 630, debug: false, fonts: [] }; /** * Renders {@link ReactNode} to image * * @param element The {@link ReactNode} * @param options The {@link RenderOptions} * * @returns An object containing methods for rendering the input element to image */ function render(element, options = {}) { const promises = {}; const renderOptions = { ...RENDER_DEFAULT_OPTIONS, ...options }; const loadAdditionalAsset = async (languageCode, segment) => { const next = () => require_asset.loadDynamicAsset(languageCode, segment, renderOptions?.emoji); let result; if (options.loadAdditionalAsset) result = await options.loadAdditionalAsset(languageCode, segment, next); result ??= await next(); if (Array.isArray(result)) return await Promise.all(result.map(async (asset) => ({ ...asset, data: await asset.data }))); return result; }; const getFonts = async () => { const fallback = async () => { const defaultFonts = []; const fallbackFont = await (renderOptions.defaultFont?.data ?? require_font.defaultFont.get()); if (fallbackFont) defaultFonts.push(new require_font.CustomFont("sans serif", fallbackFont, { weight: 400, style: "normal" })); else { console.warn("(@cf-wasm/og) [ WARN ] No default font specified. Using 'Noto Sans' from Google Fonts as the fallback."); defaultFonts.push(new require_font.GoogleFont("Noto Sans", { name: "sans serif", weight: 400, style: "normal" })); } return Promise.all([...defaultFonts, ...renderOptions.fonts].map(async (font) => ({ ...font, data: await font.data }))).then((fonts) => fonts.map((font) => { const key = JSON.stringify([ font.name, font.style || "", font.weight || "", font.lang || "", font.data.byteLength ]); const fromMap = require_maps.SATORI_FONT_CACHE_MAP.get(key); if (fromMap) return fromMap; require_maps.SATORI_FONT_CACHE_MAP.set(key, font); return font; })); }; promises.fonts = promises.fonts?.then(null, fallback) ?? fallback(); return promises.fonts; }; /** * Method to render the element as svg image * * @returns A promise which resolves to rendered svg image as {@link SvgResult} */ const asSvg = async () => { const fallback = async () => { const satoriFonts = await getFonts(); const satoriOptions = { ...renderOptions.satoriOptions, width: renderOptions.width, height: renderOptions.height, debug: renderOptions.debug, fonts: satoriFonts, loadAdditionalAsset }; return { image: await require_satori.satori(element, satoriOptions), height: satoriOptions.height, width: satoriOptions.width, type: "image/svg+xml" }; }; promises.svg = promises.svg?.then(null, fallback) ?? fallback(); return promises.svg; }; /** * Method to render the element as png image * * @returns A promise which resolves to rendered png image as {@link PngResult} */ const asPng = async () => { const fallback = async () => { const resvg = await require_resvg.createResvg((await asSvg()).image, { ...renderOptions.resvgOptions, fitTo: { mode: "width", value: renderOptions.width } }); const renderedImage = resvg.render(); const result = { pixels: renderedImage.pixels, image: renderedImage.asPng(), width: renderedImage.width, height: renderedImage.height, type: "image/png" }; renderedImage.free(); resvg.free(); return result; }; promises.png = promises.png?.then(null, fallback) ?? fallback(); return promises.png; }; return { asSvg, asPng }; } //#endregion exports.RENDER_DEFAULT_OPTIONS = RENDER_DEFAULT_OPTIONS; exports.render = render; //# sourceMappingURL=render.cjs.map