Je voulais générer une image en utilisant vercel/satori sur le navigateur.
Si vous auto-hébergez les fichiers de polices, vous pouvez utiliser satori sans aucun problème, mais si possible, vous ne souhaitez pas vous auto-héberger (cela sera gênant si le nombre de polices prises en charge augmente).
J’ai essayé de télécharger un fichier de police via Google Font et de voir s’il pouvait être utilisé avec satori, mais en conclusion, cela a échoué.
Conclusion
Ceci peut être réalisé si satori prend en charge woff2, mais cela ne peut pas être réalisé avec uniquement le frontal (côté client), qui ne le prend pas actuellement en charge.
Ceci peut être réalisé s’il existe un côté serveur.
Exigences
- Pas de côté serveur
- Il est supposé que l’utilisateur sélectionne le nom et le style de la police qu’il souhaite utiliser dans [Google Fonts] (https://fonts.google.com/) et les saisit dans le champ de saisie.
Flux de traitement supposé
- L’utilisateur saisit le nom et le style de la police
- Obtenez du CSS à partir de l’API Google Fonts
- Extraire l’URL du fichier de police à partir de CSS
- Téléchargez le fichier de police
- Génération d’images avec satori
Récupération CSS
Google Font modifie le format du fichier de police qu’il renvoie en fonction de l’agent utilisateur. J’ai donc essayé de résoudre ce problème en réécrivant l’en-tête User-Agent.
Cependant, si vous y réfléchissez bien, puisqu’il s’agit d’un en-tête interdit, il ne peut pas être écrasé et le plan est bloqué ici.
export const USER_AGENTS_BY_FONT_TYPE = { // IE11 as woff woff: "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", // Googlebot as truetype ttf: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",};
export type FontType = keyof typeof USER_AGENTS_BY_FONT_TYPE;
export async function fetchGoogleFontCSS( url: string, fontType: FontType = "ttf") { const response = await fetch(url, { headers: { "User-Agent": USER_AGENTS_BY_FONT_TYPE[fontType], }, });
if (!response.ok) { throw new Error( `Failed to load font: ${response.status} ${response.statusText}` ); }
return response.text();}L’agent utilisateur ne peut pas être écrasé avec fetch car il s’agit d’un [en-tête interdit] (https://developer.mozilla.org/ja/docs/Glossary/Forbidden_header_name).
Extraire les données du CSS
Si vous pouvez obtenir CSS, l’implémentation est la suivante.
const subsetRegex = /\/\* (.+?) \*\//;const fontFileRegex = /src: url\((.+?)\)/;
type ExtractResult = { subsets: Record<string, string>; hasItems: boolean;};
const extract = (regex: RegExp, line: string) => regex.exec(line)?.[1];
export function extractFontFromCSS(css: string): ExtractResult { const subsets: Record<string, string> = {};
let currentSubset = ""; for (const line of css.split("\n")) { const subset = extract(subsetRegex, line); if (subset) { currentSubset = subset; continue; }
const url = extract(fontFileRegex, line); if (url && !subsets[currentSubset]) { subsets[currentSubset] = url; } }
return { subsets, hasItems: Object.keys(subsets).length > 0, };}A la fin
J’ai donc fini par conclure que j’avais besoin d’un côté serveur ou d’un proxy.
En raison des restrictions du navigateur (en-têtes interdits, livraison de woff2 uniquement), nous avons renoncé à l’implémenter uniquement côté client.
Documents de référence
- Charger dynamiquement les polices Google avec JavaScript
- next.js/packages/font/src/google chez Canary · vercel/next.js
résumé
J’ai essayé d’obtenir woff/ttf depuis Google Fonts dans le navigateur, mais cela a échoué en raison des restrictions de l’agent utilisateur et de l’incompatibilité de satori avec woff2.
Il faut passer par le côté serveur ou proxy. Gardez une trace de ce que vous avez appris de vos échecs.
hsb.horse