This repository has been archived by the owner on Jul 21, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
128 lines (103 loc) · 3.62 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const { parse } = require('url');
const fetch = require('node-fetch');
const { createCanvas, loadImage, registerFont } = require('canvas');
/* Load Archivo font */
registerFont(__dirname + '/fonts/archivo_bold.ttf', {
family: 'Archivo',
weight: 'bold'
});
/* Dimensions */
const WIDTH = 1400;
const HEIGHT = 800;
/* Styles */
const color = '#ffffff';
const backgroundColor = '#000000';
const logoPromise = loadImage(__dirname + '/images/import.png');
const arrowPromise = loadImage(__dirname + '/images/arrow.png');
async function fetchImage(url) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`${url} failed ${res.status}`);
}
const image = await loadImage(await res.buffer());
return image;
}
module.exports = async (req, res) => {
let repo, org;
const { pathname } = parse(req.url, true);
const parts = pathname.substring(1).split('/');
switch (parts.length) {
case 1:
repo = decodeURIComponent(parts[0] || 'import');
break;
case 2:
org = decodeURIComponent(parts[0]);
repo = decodeURIComponent(parts[1]);
break;
}
const ops = [ logoPromise ];
if (org) {
const avatarUrl = `https://github.com/${org}.png`;
ops.push(fetchImage(avatarUrl), arrowPromise);
}
const [ logo, avatar, arrow ] = await Promise.all(ops);
const canvas = createCanvas(WIDTH, HEIGHT);
const ctx = canvas.getContext('2d');
ctx.patternQuality = 'best';
// Measure title dimensions
ctx.font = 'bold 4.4em Archivo';
const text = ctx.measureText(repo);
const textWidth = text.width;
const textHeight = text.actualBoundingBoxAscent + text.actualBoundingBoxDescent;
const logoWidth = logo.width * 0.465;
const logoHeight = logo.height * 0.465;
const avatarWidth = logoHeight;
const avatarHeight = logoHeight;
const padding = 40;
const boundingBoxWidth = textWidth + logoWidth + padding;
//const boundingBoxHeight = Math.max(textHeight, logoHeight, avatarHeight);
const boundingBoxHeight = Math.max(textHeight, logoHeight);
const boundingBoxX = (WIDTH / 2) - (boundingBoxWidth / 2);
const boundingBoxY = (HEIGHT / 2) - (boundingBoxHeight / 2);
// Draw background
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, WIDTH, HEIGHT);
// Draw bounding box (debug)
//ctx.fillStyle = 'red';
//ctx.fillRect(boundingBoxX, boundingBoxY, boundingBoxWidth, boundingBoxHeight);
ctx.fillStyle = 'blue';
//ctx.fillRect(WIDTH / 2, 0, 1, HEIGHT);
//ctx.fillRect(0, HEIGHT / 2, WIDTH, 1);
let logoX = boundingBoxX;
let logoY = boundingBoxY;
let titleX = boundingBoxX + logoWidth + padding;
let titleY = (HEIGHT / 2);
let textBaseline = 'middle';
if (avatar) {
// Draw avatar
let avatarX = (WIDTH / 2) + (padding * 2);
let avatarY = (HEIGHT / 2) - avatarHeight - padding;
ctx.drawImage(avatar, avatarX, avatarY, avatarWidth, avatarHeight);
// Draw arrow
let arrowWidth = arrow.width * 0.5;
let arrowHeight = arrow.height * 0.5;
let arrowX = (WIDTH / 2) - (arrowWidth / 2);
let arrowY = (HEIGHT / 2) - (arrowHeight / 2) - (avatarHeight / 2) - padding;
ctx.drawImage(arrow, arrowX, arrowY, arrowWidth, arrowHeight);
// Adjust title
textBaseline = 'top';
titleX = (WIDTH / 2) - (textWidth / 2);
titleY += padding;
// Adjust logo
logoX = (WIDTH / 2) - logoWidth - (padding * 2);
logoY = (HEIGHT / 2) - logoHeight - padding;
}
// Draw logo
ctx.drawImage(logo, logoX, logoY, logoWidth, logoHeight);
// Draw title
ctx.textBaseline = textBaseline;
ctx.fillStyle = color;
ctx.fillText(repo, titleX, titleY);
res.setHeader('Content-Type', 'image/png');
canvas.createPNGStream().pipe(res);
};