Skip to content

Commit 8ad24e5

Browse files
committed
port old tile endpoint
1 parent 367c74c commit 8ad24e5

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

api/tile.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { createCanvas, GlobalFonts, loadImage } from '@napi-rs/canvas';
2+
3+
// TODO: maybe rewrite in rust?
4+
5+
/** @type {import("@vercel/node").VercelApiHandler} */
6+
export default async function handler(request, response) {
7+
if (!request.url) return response.status(400);
8+
9+
const url = new URL(request.url, `http://${request.headers.host}`);
10+
const { searchParams } = url;
11+
const hasContent = searchParams.has('content');
12+
const content = hasContent ? searchParams.get('content') : '';
13+
14+
GlobalFonts.registerFromPath('./assets/NotoColorEmoji-Regular.ttf', 'NotoColorEmoji');
15+
GlobalFonts.registerFromPath('./assets/PTSerif-Italic.ttf', 'pt');
16+
17+
const fontSize = 72;
18+
const lineHeight = fontSize + 6;
19+
20+
const imageSize = 800;
21+
const maxWidth = 540;
22+
23+
const words = content.split(' ');
24+
25+
// create canvas same width and height as image
26+
const canvas = createCanvas(imageSize, imageSize);
27+
const ctx = canvas.getContext('2d');
28+
29+
const tile = await loadImage('./assets/tile.jpg');
30+
ctx.drawImage(tile, 0, 0, imageSize, imageSize);
31+
32+
ctx.font = `400 ${fontSize}px pt, NotoColorEmoji`;
33+
ctx.textAlign = 'center';
34+
ctx.fillStyle = '#0f1b65';
35+
36+
// check line amount
37+
let line = '';
38+
/** @type {string[]} */
39+
const lines = [];
40+
41+
for (const word of words) {
42+
const testLine = `${line} ${word}`;
43+
const testWidth = ctx.measureText(testLine).width;
44+
45+
if (testWidth > maxWidth) {
46+
// go to next line
47+
lines.push(line.trim());
48+
line = word;
49+
continue;
50+
}
51+
52+
line = testLine;
53+
}
54+
55+
lines.push(line);
56+
57+
// fill tile with text
58+
let startX = 0;
59+
let startY = imageSize / 2 - ((lines.length - 1) * lineHeight) / 2 + 24;
60+
61+
for (const line of lines) {
62+
startX = imageSize / 2;
63+
ctx.fillText(line, startX, startY);
64+
startY += lineHeight;
65+
}
66+
67+
response.status(200).setHeader('Content-Type', 'image/png').send(canvas.toBuffer('image/png'));
68+
}

assets/NotoColorEmoji-Regular.ttf

22.6 MB
Binary file not shown.

assets/PTSerif-Italic.ttf

227 KB
Binary file not shown.

assets/tile.jpg

123 KB
Loading

0 commit comments

Comments
 (0)