Boxes where the letters should be
This blog pre-renders an OG image as a PNG for every post. An SVG template gets the title, category label, and description, and resvg rasterizes it. On the Korean images, the title, label, and description all came out as empty boxes (tofu). Not a few characters. All of the Korean text.
The cause was simple. resvg had no fonts loaded, and the SVG asked for Inter and Arial. Neither font has Hangul glyphs. The renderer couldn't find a shape for those characters, so it drew a box instead.
There was no error. The PNG files were generated and the build went through. A file existing on disk said nothing about whether there was readable text inside it.
Can you point to the exact line in your image generation code that says which font file draws the text?
Why it stayed quiet
An SVG font-family is a request, not a guarantee. If the renderer doesn't have a font with that name, it looks for another one, and if nothing it has covers the glyph, it draws a box. None of this counts as a failure. The output is a valid PNG with a normal size and format. The breakage only shows up when a person looks at it.
What would you do? Turn on system fonts and be done, or commit the font files to the repo?
The fix: commit the fonts and load them by hand
- Bundled Noto Sans KR (400 and 700) and JetBrains Mono Bold under assets/fonts.
- Loaded those files into resvg explicitly and set loadSystemFonts to false. The reason is reproducibility: if you lean on system fonts, the output can change depending on which machine runs the build.
- Regenerated all 90 OG PNGs.
This has a cost. Each Noto Sans KR file is about 2.4 MB, so the two weights add up to about 4.9 MB, and JetBrains Mono adds about 270 KB. All of that now lives in the repo.
After the regeneration, every image changed at the byte level, including the English ones. The English home image, for example, went from 49,571 bytes to 44,174. Changing how fonts are loaded means every image gets redrawn, whatever language it's in.
Self-check
- Does your server-side image renderer (resvg, a headless browser, anything else) name its font files in code, or does it rely on the font-family names in the SVG?
- Does the font you load have glyphs for every script you actually render, including Hangul, Japanese, and symbols?
- Have you opened even one generated image for a non-English page and looked at it yourself?
The honest part
This commit fixed the fonts. It didn't add a check to stop this from happening again, and there are no tests in the changed files. The record doesn't say how long the boxed images were public, or whether link previews shared in that window are still sitting in some platform's cache, so I don't know either of those things. And since system fonts are now off, a title with a character that none of the three bundled fonts covers would produce the same symptom again. I haven't checked whether that has happened yet.