Initial commit
This commit is contained in:
90
pages/api/thumbnail.js
Normal file
90
pages/api/thumbnail.js
Normal file
@ -0,0 +1,90 @@
|
||||
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"`,
|
||||
},
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user