Skip to content

Instantly share code, notes, and snippets.

@jmaicaaan
Created August 29, 2024 02:32
Show Gist options
  • Save jmaicaaan/af590dc40c66f49cf6dd151c55d81feb to your computer and use it in GitHub Desktop.
Save jmaicaaan/af590dc40c66f49cf6dd151c55d81feb to your computer and use it in GitHub Desktop.
import {
Resvg
} from '@resvg/resvg-js';
import {
NextResponse
} from 'next/server';
import satori, {
SatoriOptions
} from 'satori';
import {
Ticket
} from './Ticket';
export async function GET() {
const fonts = await Promise.all([getFont({
font: 'Inter'
})]).then(
(fonts) => fonts.flat(),
);
const svg = await satori((
<Ticket />
), {
fonts,
width: 800,
height: 300,
});
const resvg = new Resvg(svg);
const pngData = resvg.render();
const img = pngData.asPng();
return new NextResponse(img, {
status: 200,
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'private, max-age=30, stale-while-revalidate=30',
},
});
};
/**
* Grabbed from https://github.com/kentcdodds/epic-camp-tickets/blob/main/app/img.server.ts
*/
async function getFont({
font,
weights = [400, 500, 600, 700],
}: {
font: string
weights?: Array<number>
}) {
const weightsString = weights.join(';');
const fetchUrl = `https://fonts.googleapis.com/css2?family=${font}:wght@${weightsString}`;
const css = await fetch(fetchUrl).then((response) => response.text());
const resource = css.matchAll(
/src: url\((.+)\) format\('(opentype|truetype)'\)/g,
);
return Promise.all(
[...resource as any]
.map((match) => match[1])
.map((url) => fetch(url).then((response) => response.arrayBuffer()))
.map(async (buffer, i) => ({
name: font,
style: 'normal',
weight: weights[i],
data: await buffer,
})),
) as Promise<SatoriOptions['fonts']>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment