Files
thumbnail-api/pages/api/thumbnail.js
2025-05-22 22:21:48 -07:00

91 lines
2.2 KiB
JavaScript

import { ImageResponse } from "@vercel/og";
export const config = {
runtime: "edge",
};
/**
* Generates a dynamic WebP image with text using a custom font.
* @param {Request} req
* @returns {Promise<Response>}
*/
export default async function handler(req) {
const { searchParams } = new URL(req.url, "http://localhost");
const text = searchParams.get("text")?.trim() || "Demo";
const fontUrl = "https://lib.satki.net/fonts/Inter-Bold.ttf";
let fontData;
try {
const fontResponse = await fetch(fontUrl);
if (!fontResponse.ok) throw new Error(`Font fetch failed: ${fontResponse.status}`);
fontData = await fontResponse.arrayBuffer();
} catch (error) {
return new Response(
JSON.stringify({ error: "Failed to fetch font", message: error.message }),
{ status: 500, headers: { "Content-Type": "application/json" } }
);
}
const width = 2048;
const height = 1170;
const containerStyle = {
height: `${height}px`,
width: `${width}px`,
display: "flex",
textAlign: "center",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
flexWrap: "nowrap",
backgroundColor: "black",
backgroundImage: [
"radial-gradient(circle at 25px 25px, #676767 2%, transparent 0%)",
"radial-gradient(circle at 75px 75px, #676767 2%, transparent 0%)",
].join(", "),
backgroundSize: "100px 100px",
};
const textStyle = {
display: "flex",
fontSize: "95px",
fontStyle: "normal",
color: "white",
lineHeight: 1.8,
whiteSpace: "pre-wrap",
};
const image = new ImageResponse(
(
<div style={containerStyle}>
<div style={textStyle}>
<b>{text}</b>
</div>
</div>
),
{
width,
height,
fonts: [
{
name: "Inter",
data: fontData,
style: "normal",
weight: 700,
},
],
// Force output to WebP
contentType: "image/webp",
quality: 80, // <- not officially documented, but works with newer versions
}
);
return new Response(image.body, {
headers: {
"Content-Type": "image/webp",
"Content-Disposition": `inline; filename="${encodeURIComponent(text)}.webp"`,
},
});
}