-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathog-images.config.js
139 lines (118 loc) Β· 5.1 KB
/
og-images.config.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
129
130
131
132
133
134
135
136
137
138
139
import fsPromises from 'node:fs/promises'
import fs from 'node:fs'
import { Buffer } from 'node:buffer'
import { html, styled } from 'og-images-generator'
/**
* Get the TTF font for the specified family and axes values. Adapted from [this GitHub issue comment](https://github.com/vercel/satori/issues/162#issuecomment-2058182646).
*
* NOTE: satori, the library which generates the image, doesn't support variable fonts, so we do some shenanigans to get Google Fonts to serve a non-variable font and then use that.
* @param {string} family The font family
* @param {string[]} axes The axes of the font
* @param {number[]} value The values of the axes
* @returns {Promise<ArrayBuffer>} The TTF font
* @example
* const ttfFont = await getTtfFont('Roboto', ['wght'], [700]);
*/
async function getTtfFont(family, axes, value) {
const familyParam = `${axes.join(',')}@${value.join(',')}`
// Get css style sheet with user agent Mozilla/5.0 Firefox/1.0 to ensure non-variable TTF is returned
const cssRes = await fetch(`https://fonts.googleapis.com/css2?family=${family}:${familyParam}&display=swap`, {
headers: {
'User-Agent': 'Mozilla/5.0 Firefox/1.0',
},
})
const css = await cssRes.text()
const ttfUrl = css.match(/url\(([^)]+)\)/)?.[1]
return await fetch(ttfUrl).then(res => res.arrayBuffer())
}
const UNBOUNDED_TTF_DIR = 'node_modules/.astro'
const UNBOUNDED_TTF = `${UNBOUNDED_TTF_DIR}/unbounded.ttf`
let fontBuffer
try {
fontBuffer = await fsPromises.readFile(UNBOUNDED_TTF)
}
catch (e) {
console.error('Failed to read Unbounded font from file, fetching from Google Fonts')
const arrayBuffer = await getTtfFont('Unbounded', ['wght'], [900])
fontBuffer = Buffer.from(arrayBuffer)
await fsPromises.mkdir(UNBOUNDED_TTF_DIR, { recursive: true })
await fsPromises.writeFile(UNBOUNDED_TTF, fontBuffer)
}
/** @type {import('og-images-generator').RenderOptions} */
export const renderOptions = {
satori: {
fonts: [{ name: 'Unbounded Variable', data: fontBuffer, weight: 900 }],
width: 2048,
height: 1170,
},
resvg: {
loadSystemFonts: false
}
}
const styles = {
container: styled.div`
height: 100%;
width: 100%;
display: flex;
filter: contrast(1.7) saturate(0);
`,
wrap: styled.div`
position: absolute;
top: 0;
background: rgba(191, 30, 46, 0.75);
left: 0;
padding: 97px 170px 97px 170px;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
font-size: 120px;
font-family: 'Unbounded Variable', sans-serif;
`,
title: styled.div`
height: 100%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
`
}
/*
* @param {string} imagePath
* @returns {string}
*/
function getImageDataURLFromAstroPublicDir(imagePath) {
return `https://cometrobotics.org/${imagePath}`
// TODO: figure out why this causes image generation to hang. satori docs indicate that it should be possible to use data URIs in this way, and I've tested that the generated data URIs are valid and render an image as expected.
// update: did some more testing, looks like its not even an issue with satori, something between the generated html string and whatever intermediate processing og image gen library does to it is causing satori-html to hang when converting the html to a VNode tree for satori. specifically, it uses ultrahtml to parse? the html, and that is hanging... so we aren't even getting to the point of generating the image...
// might just leave this like this for now. its not the end of the world that we have to fetch these images from the live site. its definitely slower than reading images locally, but since we just take the hit once at build time its not a big deal and i have more important things to do lol
const fileExt = imagePath.split('.').pop()
console.log({fileExt})
const file = fs.readFileSync(`./public/${imagePath}`)
const base64 = Buffer.from(file).toString('base64')
return `data:image/${fileExt};base64,${base64}`
}
/** @type {import('og-images-generator').Template} */
function template({ page }) {
let title = page.meta.tags['og:title'] ?? ''
if (['Home', 'Comet Robotics', 'Comet Robotics at UT Dallas'].includes(title)) {
title = ''
}
const wordmarkStyles = title ? styled.div`width: 445px;` : styled.div`width: 1250px;`
return html` <!-- -->
<div style=${styles.container}>
<img src="https://github.com/Comet-Robotics/cometrobotics.org/raw/c16375ca9033971919e0d6f36727377d1fdc1cc4/public/DSC02011.jpg" style="width: 100%; height: 100%; object-fit: cover;"/>
</div>
<div style=${styles.wrap}>
<img style=${wordmarkStyles} src="https://github.com/Comet-Robotics/cometrobotics.org/raw/c16375ca9033971919e0d6f36727377d1fdc1cc4/public/wordmark.png"/>
${title ? html`<div style=${styles.title}>${title.trim()}</div>` : ''}
</div>
`
};
// <img style=${wordmarkStyles} src="${getImageDataURLFromAstroPublicDir('wordmark.png')}"/>
// <img src="${getImageDataURLFromAstroPublicDir('DSC02011.jpg')}" style="width: 100%; height: 100%; object-fit: cover;"/>
export { template }