Skip to content

Commit 77bfad7

Browse files
authored
Merge pull request #978 from wwWallet/fix/metadata-image-font-environment-missing
fix: create font environment to use in metadata image and use Inter SemiBold
2 parents 66d188d + ab41e8b commit 77bfad7

File tree

4 files changed

+70
-11
lines changed

4 files changed

+70
-11
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM node:22-bullseye-slim AS builder-base
22

3-
RUN apt-get update -y && apt-get install -y git && rm -rf /var/lib/apt/lists/*
3+
RUN apt-get update -y && apt-get install -y git fontconfig && rm -rf /var/lib/apt/lists/*
44

55
WORKDIR /home/node/app
66

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"depcheck": "^1.4.7",
7171
"eslint": "^8.56.0",
7272
"eslint-config-react-app": "^7.0.1",
73+
"fonteditor-core": "^2.6.3",
7374
"jsdom": "^26.0.0",
7475
"sharp": "^0.34.5",
7576
"vite": "^6.1.0",

vite-plugins/metadata-image.ts

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,64 @@
11
import path from "node:path";
2+
import { fileURLToPath } from "node:url";
3+
import { mkdir, readFile, writeFile } from "node:fs/promises";
24
import { Plugin } from "vite";
35
import sharp from "sharp";
46
import convert, { RGB } from "color-convert"
7+
import { createFont, woff2 } from "fonteditor-core";
58
import { findBrandingFile, findLogoFile } from "./brandingManifest";
69
import { getThemeFile } from "./theme";
710

811
type Env = Record<string, string|null|undefined>;
912

13+
const fontsConfTemplate = `<?xml version="1.0"?>
14+
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
15+
<fontconfig>
16+
<dir prefix="relative">./</dir>
17+
<config></config>
18+
</fontconfig>
19+
`;
20+
21+
/**
22+
* Sets up a self-contained font environment:
23+
* 1. Converts a WOFF2 font to TTF for Node rendering.
24+
* 2. Writes the font and a minimal Fontconfig XML to a project directory.
25+
* 3. Sets FONTCONFIG_PATH so rendering libraries can find the font.
26+
*
27+
* The reason for converting from WOFF2 to TTF is so we can keep using the
28+
* `@fontsource/inter` package and not need to bundle font files.
29+
*/
30+
async function setupFontsEnvironment(baseDir: string) {
31+
const fontsConfDir = path.resolve(baseDir, "fonts");
32+
const inputFontFiles = [
33+
import.meta.resolve("@fontsource/inter/files/inter-latin-600-normal.woff2"),
34+
];
35+
36+
await woff2.init();
37+
await mkdir(fontsConfDir, { recursive: true });
38+
39+
for (const input of inputFontFiles) {
40+
const inputBuffer = await readFile(fileURLToPath(input));
41+
42+
const font = createFont(inputBuffer, {
43+
type: "woff2",
44+
hinting: true,
45+
kerning: true,
46+
});
47+
48+
const outputBuffer = font.write({
49+
type: "ttf",
50+
hinting: true,
51+
kerning: true,
52+
});
53+
54+
await writeFile(path.join(fontsConfDir, path.basename(input)), outputBuffer as Buffer);
55+
}
56+
57+
await writeFile(path.join(fontsConfDir, "fonts.conf"), fontsConfTemplate),
58+
59+
process.env.FONTCONFIG_PATH = fontsConfDir;
60+
}
61+
1062
function splitTitle(title: string, maxLength: number): string[] {
1163
const lines: string[] = [];
1264
let remainingTitle = title;
@@ -69,20 +121,11 @@ type ImageTemplateProps = {
69121
text: string;
70122
}
71123
}
72-
73124
const imageTemplate = ({ title, logoB64, colors }: ImageTemplateProps) => `
74125
<svg width="1200" height="628" viewBox="0 0 1200 628" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
75-
<style>
76-
.header {
77-
dominant-baseline: hanging;
78-
}
79-
.footer {
80-
dominant-baseline: alphabetic;
81-
}
82-
</style>
83126
<rect x="0" y="0" width="1200" height="628" fill="${colors.background}" />
84127
${logoTemplate(logoB64, 250)}
85-
<g fill="${colors.text}" font-family="Arial" font-weight="bold">
128+
<g fill="${colors.text}" font-family="Inter SemiBold">
86129
${titleTemplate(title)}
87130
</g>
88131
</svg>
@@ -202,6 +245,9 @@ export function MetadataImagePlugin(env: Env): Plugin {
202245
return {
203246
name: "metadata-image-plugin",
204247

248+
async configResolved(config) {
249+
await setupFontsEnvironment(config.cacheDir);
250+
},
205251
async configureServer(server) {
206252
let image = await generateMetadataImage(env);
207253

yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2787,6 +2787,11 @@
27872787
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.13.tgz#87b309a6379c22b926e696893237826f64339b6f"
27882788
integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==
27892789

2790+
"@xmldom/xmldom@^0.8.3":
2791+
version "0.8.11"
2792+
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608"
2793+
integrity sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==
2794+
27902795
"@zxing/text-encoding@0.9.0":
27912796
version "0.9.0"
27922797
resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
@@ -4367,6 +4372,13 @@ follow-redirects@^1.15.6:
43674372
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
43684373
integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
43694374

4375+
fonteditor-core@^2.6.3:
4376+
version "2.6.3"
4377+
resolved "https://registry.yarnpkg.com/fonteditor-core/-/fonteditor-core-2.6.3.tgz#0a1c5abcc75a6de8348f67b9cb886a88adde18ca"
4378+
integrity sha512-YUryIKjkenjZ41E7JvM3V+02Ak4mTHDDTwBWgs9KBzypzHqLZHuua1UDRevZNTKawmnq1dbBAa70Jddl2+F4FQ==
4379+
dependencies:
4380+
"@xmldom/xmldom" "^0.8.3"
4381+
43704382
for-each@^0.3.3:
43714383
version "0.3.5"
43724384
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47"

0 commit comments

Comments
 (0)