UNPKG

@cf-wasm/og

Version:

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

203 lines (202 loc) 7.09 kB
const require_maps = require("./maps.cjs"); const require_cache = require("./cache.cjs"); const require_errors = require("./errors.cjs"); //#region src/core/font.ts /** Default user agent for loading css */ const GOOGLE_FONT_CSS_DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"; /** Google fonts utils */ var GoogleFontsUtils = class { constructor() { this._defaultCssLoader = async (cssUrl, userAgent) => { return (await require_cache.cache.serve(cssUrl, () => fetch(cssUrl, { headers: { "User-Agent": userAgent } }).then((res) => { if (!res.ok) throw new require_errors.FetchError(`Response was not successful (status: \`${res.status}\`, statusText: \`${res.statusText}\`)`, { response: res }); return res; }).catch((e) => { throw new require_errors.FetchError(`An error ocurred while fetching \`${cssUrl}\``, { cause: e, response: e instanceof require_errors.FetchError ? e.response : void 0 }); }))).text(); }; this._cssLoader = this._defaultCssLoader; } /** * Loads Google font css * * @param cssUrl The Google font css url * @param userAgent The user agent header to be used * * @returns On success, the css as string */ async loadCss(cssUrl, userAgent = GOOGLE_FONT_CSS_DEFAULT_USER_AGENT) { let css = await this._cssLoader(cssUrl, userAgent); if (typeof css === "undefined") css = await this._defaultCssLoader(cssUrl, userAgent); else if (typeof css !== "string") throw new Error("Google font css loader return value must resolve to string"); return css; } /** * Sets Google font css loader * * @param loader The {@link GoogleFontCssLoader} */ setCssLoader(loader) { if (typeof loader !== "function") throw new TypeError("Argument 1 must be a function."); this._cssLoader = loader; } }; const googleFonts = new GoogleFontsUtils(); /** Constructs Google font css url */ function constructGoogleFontCssUrl(family, { style = "normal", weight = 400, subset = "latin", display, text } = {}) { if (typeof family !== "string" || family.trim().length === 0) throw new Error("Not a valid font family name was provided"); const params = { family: `${family.replaceAll(" ", "+")}:${style === "italic" ? "ital," : ""}wght@${style === "italic" ? "1," : ""}${weight}` }; if (text) params.text = encodeURIComponent(text); else params.subset = subset; if (typeof display === "string") params.display = display; return `https://fonts.googleapis.com/css2?${Object.keys(params).map((key) => `${key}=${params[key]}`).join("&")}`; } /** * A helper function for loading google fonts as {@link ArrayBuffer} * * @param family The name of the font family * @param param1 Options * * @returns A promise which resolved to {@link ArrayBuffer} */ async function loadGoogleFont(family, options = {}) { const cssUrl = constructGoogleFontCssUrl(family, options); const fromMap = require_maps.FONT_CACHE_MAP.get(cssUrl); if (fromMap) return fromMap; const fontUrl = (await googleFonts.loadCss(cssUrl)).match(/src: url\((.+)\) format\('(opentype|truetype)'\)/)?.[1]; if (!fontUrl) throw new Error("The css does not content source for truetype font."); const buffer = await (await require_cache.cache.serve(fontUrl, () => fetch(fontUrl).then((res) => { if (!res.ok) throw new require_errors.FetchError(`Response was not successful (status: ${res.status}, statusText: ${res.statusText})`, { response: res }); return res; }).catch((e) => { throw new require_errors.FetchError(`An error ocurred while fetching ${fontUrl}`, { cause: e, response: e instanceof require_errors.FetchError ? e.response : void 0 }); }))).arrayBuffer(); require_maps.FONT_CACHE_MAP.set(cssUrl, buffer); return buffer; } /** A helper class to load Custom font */ var CustomFont = class { /** * Creates an instance of {@link CustomFont} * * @param name The name of the font (can be used for font-family css property) * @param input Font data as `ArrayBuffer` or a promise which resolves to `ArrayBuffer` * @param options */ constructor(name, input, { style = "normal", weight = 400, lang } = {}) { this.type = "custom"; this.name = name; this.style = style; this.weight = weight; this.input = input; this.lang = lang; } /** * A promise which resolves to font data as `ArrayBuffer` */ get data() { const fallback = async () => typeof this.input === "function" ? this.input() : this.input; this.promise = this.promise?.then(null, fallback) ?? fallback(); return this.promise; } }; /** A helper class to load Google font */ var GoogleFont = class { /** * Creates an instance of {@link GoogleFont} * * @param family The name of font family to load * @param options The {@link GoogleFontOptions} */ constructor(family, { name, style = "normal", weight = 400, subset = "latin", text } = {}) { this.type = "google"; this.name = name || family; this.style = style; this.weight = weight; this.subset = subset; this.family = family; this.text = text; } /** A promise which resolves to font data as `ArrayBuffer` */ get data() { const fallback = async () => loadGoogleFont(this.family, { style: this.style, weight: this.weight, subset: this.subset, text: this.text }); this.promise = this.promise?.then(null, fallback) ?? fallback(); return this.promise; } /** * Checks whether font can load buffer * * @returns On success, true otherwise the error object thrown */ async canLoad() { try { await this.data; } catch (e) { return e; } return true; } }; /** Default font utils */ var DefaultFont = class { constructor() { this._shouldResolve = true; } /** * Sets default font for image rendering * * @param input {@link FontInput} */ set(input) { if (!input) throw new TypeError("Argument 1 type is not acceptable"); this._shouldResolve = true; this._input = input; } /** * Gets default font buffer for image rendering if it is set * * @returns A Promise which resolves to ArrayBuffer if default font is set, * otherwise undefined */ async get() { let buffer; if (this._shouldResolve && this._input) { const input = typeof this._input === "function" ? await this._input() : await this._input; if (input instanceof Response) buffer = await input.arrayBuffer(); else if ("data" in input) buffer = await input.data; else buffer = input; } else if (this._data) buffer = this._data; this._data = buffer; this._shouldResolve = false; return buffer; } /** * Check whether default font is set or not * * @returns true if default font is set, otherwise false */ has() { return Boolean(this._input); } }; const defaultFont = new DefaultFont(); //#endregion exports.CustomFont = CustomFont; exports.GOOGLE_FONT_CSS_DEFAULT_USER_AGENT = GOOGLE_FONT_CSS_DEFAULT_USER_AGENT; exports.GoogleFont = GoogleFont; exports.constructGoogleFontCssUrl = constructGoogleFontCssUrl; exports.defaultFont = defaultFont; exports.googleFonts = googleFonts; exports.loadGoogleFont = loadGoogleFont; //# sourceMappingURL=font.cjs.map