Skip to content

Commit 2f82feb

Browse files
fix: resolve non-latin char issue in generated OG images (#318)
Changes made - update font source with Google font - add error handling in font fetching logic - update docs in dynamic-og-images blog post --------- Co-authored-by: satnaing <[email protected]>
1 parent 0440d2a commit 2f82feb

File tree

6 files changed

+140
-52
lines changed

6 files changed

+140
-52
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/content/blog/dynamic-og-images.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,48 @@ Dynamic OG images will be generated at build time for blog posts that
4141
Dynamic OG image of AstroPaper includes _the blog post title_, _author name_ and _site title_. Author name and site title will be retrieved via `SITE.author` and `SITE.title` of **"src/config.ts"** file. The title is generated from the blog post frontmatter `title`.
4242
![Example Dynamic OG Image link](https://user-images.githubusercontent.com/53733092/209704501-e9c2236a-3f4d-4c67-bab3-025aebd63382.png)
4343

44+
### Issue Non-Latin Characters
45+
46+
Titles with non-latin characters won't display properly out of the box. To resolve this, we have to replace `fontsConfig` inside `loadGoogleFont.ts` with your preferred font.
47+
48+
```ts
49+
// file: loadGoogleFont.ts
50+
51+
async function loadGoogleFonts(
52+
text: string
53+
): Promise<
54+
Array<{ name: string; data: ArrayBuffer; weight: number; style: string }>
55+
> {
56+
const fontsConfig = [
57+
{
58+
name: "Noto Sans JP",
59+
font: "Noto+Sans+JP",
60+
weight: 400,
61+
style: "normal",
62+
},
63+
{
64+
name: "Noto Sans JP",
65+
font: "Noto+Sans+JP:wght@700",
66+
weight: 700,
67+
style: "normal",
68+
},
69+
{ name: "Noto Sans", font: "Noto+Sans", weight: 400, style: "normal" },
70+
{
71+
name: "Noto Sans",
72+
font: "Noto+Sans:wght@700",
73+
weight: 700,
74+
style: "normal",
75+
},
76+
];
77+
// other codes
78+
}
79+
```
80+
81+
> Check out [this PR](https://github.com/satnaing/astro-paper/pull/318) for more info.
82+
4483
## Limitations
4584

4685
At the time of writing this, [Satori](https://github.com/vercel/satori) is fairly new and has not reached major release yet. So, there are still some limitations to this dynamic OG image feature.
4786

48-
- If you have Blog posts with non-English titles, you have to set `embedFonts` option to `false` (file: `src/utils/generateOgImage.tsx`). Even after this, the OG image might not be displayed very well.
4987
- Besides, RTL languages are not supported yet.
5088
- [Using emoji](https://github.com/vercel/satori#emojis) in the title might be a little bit tricky.

src/utils/generateOgImages.tsx

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,20 @@
1-
import satori, { type SatoriOptions } from "satori";
21
import { Resvg } from "@resvg/resvg-js";
32
import { type CollectionEntry } from "astro:content";
43
import postOgImage from "./og-templates/post";
54
import siteOgImage from "./og-templates/site";
65

7-
const fetchFonts = async () => {
8-
// Regular Font
9-
const fontFileRegular = await fetch(
10-
"https://www.1001fonts.com/download/font/ibm-plex-mono.regular.ttf"
11-
);
12-
const fontRegular: ArrayBuffer = await fontFileRegular.arrayBuffer();
13-
14-
// Bold Font
15-
const fontFileBold = await fetch(
16-
"https://www.1001fonts.com/download/font/ibm-plex-mono.bold.ttf"
17-
);
18-
const fontBold: ArrayBuffer = await fontFileBold.arrayBuffer();
19-
20-
return { fontRegular, fontBold };
21-
};
22-
23-
const { fontRegular, fontBold } = await fetchFonts();
24-
25-
const options: SatoriOptions = {
26-
width: 1200,
27-
height: 630,
28-
embedFont: true,
29-
fonts: [
30-
{
31-
name: "IBM Plex Mono",
32-
data: fontRegular,
33-
weight: 400,
34-
style: "normal",
35-
},
36-
{
37-
name: "IBM Plex Mono",
38-
data: fontBold,
39-
weight: 600,
40-
style: "normal",
41-
},
42-
],
43-
};
44-
456
function svgBufferToPngBuffer(svg: string) {
467
const resvg = new Resvg(svg);
478
const pngData = resvg.render();
489
return pngData.asPng();
4910
}
5011

5112
export async function generateOgImageForPost(post: CollectionEntry<"blog">) {
52-
const svg = await satori(postOgImage(post), options);
13+
const svg = await postOgImage(post);
5314
return svgBufferToPngBuffer(svg);
5415
}
5516

5617
export async function generateOgImageForSite() {
57-
const svg = await satori(siteOgImage(), options);
18+
const svg = await siteOgImage();
5819
return svgBufferToPngBuffer(svg);
5920
}

src/utils/loadGoogleFont.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { FontStyle, FontWeight } from "satori";
2+
3+
export type FontOptions = {
4+
name: string;
5+
data: ArrayBuffer;
6+
weight: FontWeight | undefined;
7+
style: FontStyle | undefined;
8+
};
9+
10+
async function loadGoogleFont(
11+
font: string,
12+
text: string
13+
): Promise<ArrayBuffer> {
14+
const API = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`;
15+
16+
const css = await (
17+
await fetch(API, {
18+
headers: {
19+
"User-Agent":
20+
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1",
21+
},
22+
})
23+
).text();
24+
25+
const resource = css.match(
26+
/src: url\((.+)\) format\('(opentype|truetype)'\)/
27+
);
28+
29+
if (!resource) throw new Error("Failed to download dynamic font");
30+
31+
const res = await fetch(resource[1]);
32+
33+
if (!res.ok) {
34+
throw new Error("Failed to download dynamic font. Status: " + res.status);
35+
}
36+
37+
const fonts: ArrayBuffer = await res.arrayBuffer();
38+
return fonts;
39+
}
40+
41+
async function loadGoogleFonts(
42+
text: string
43+
): Promise<
44+
Array<{ name: string; data: ArrayBuffer; weight: number; style: string }>
45+
> {
46+
const fontsConfig = [
47+
{
48+
name: "IBM Plex Mono",
49+
font: "IBM+Plex+Mono",
50+
weight: 400,
51+
style: "normal",
52+
},
53+
{
54+
name: "IBM Plex Mono",
55+
font: "IBM+Plex+Mono:wght@700",
56+
weight: 700,
57+
style: "bold",
58+
},
59+
];
60+
61+
const fonts = await Promise.all(
62+
fontsConfig.map(async ({ name, font, weight, style }) => {
63+
const data = await loadGoogleFont(font, text);
64+
return { name, data, weight, style };
65+
})
66+
);
67+
68+
return fonts;
69+
}
70+
71+
export default loadGoogleFonts;

src/utils/og-templates/post.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { SITE } from "@config";
1+
import satori from "satori";
22
import type { CollectionEntry } from "astro:content";
3+
import { SITE } from "@config";
4+
import loadGoogleFonts, { type FontOptions } from "../loadGoogleFont";
35

4-
export default (post: CollectionEntry<"blog">) => {
5-
return (
6+
export default async (post: CollectionEntry<"blog">) => {
7+
return satori(
68
<div
79
style={{
810
background: "#fefbfb",
@@ -91,6 +93,14 @@ export default (post: CollectionEntry<"blog">) => {
9193
</div>
9294
</div>
9395
</div>
94-
</div>
96+
</div>,
97+
{
98+
width: 1200,
99+
height: 630,
100+
embedFont: true,
101+
fonts: (await loadGoogleFonts(
102+
post.data.title + post.data.author + SITE.title + "by"
103+
)) as FontOptions[],
104+
}
95105
);
96106
};

src/utils/og-templates/site.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import satori from "satori";
12
import { SITE } from "@config";
3+
import loadGoogleFonts, { type FontOptions } from "../loadGoogleFont";
24

3-
export default () => {
4-
return (
5+
export default async () => {
6+
return satori(
57
<div
68
style={{
79
background: "#fefbfb",
@@ -82,6 +84,12 @@ export default () => {
8284
</div>
8385
</div>
8486
</div>
85-
</div>
87+
</div>,
88+
{
89+
width: 1200,
90+
height: 630,
91+
embedFont: true,
92+
fonts: (await loadGoogleFonts(SITE.title + SITE.desc)) as FontOptions[],
93+
}
8694
);
8795
};

0 commit comments

Comments
 (0)