Summary
FontManager.resolve_font() cannot load a bitmap (.bdf) font at anything other than its own pixel size, and when it fails it returns the default face without signalling it. Callers cannot tell a successful load from a silent fallback, so a plugin offering a .bdf in its font picker appears to ignore the setting.
Why it is invisible
A .bdf exists at exactly one pixel size. FreeType raises OSError: invalid pixel size for any other, so ImageFont.truetype(path, size) fails whenever the requested size differs from the file's PIXEL_SIZE. resolve_font then falls back — and in current Pillow the default face is itself a FreeTypeFont, so the returned type gives no hint that anything went wrong.
common_fonts carries five_by_seven → assets/fonts/5x7.bdf, which is native 7px. Any caller asking for it at the usual 8 gets the default face back and no error.
Impact seen in plugins
This has now surfaced in five plugins in ledmatrix-plugins, each with its own copy of the loader:
| Plugin |
Symptom |
| clock-simple |
5x7.bdf and 4x6.bdf rendered byte-identical to the default |
| countdown |
five_by_seven fell back even though the plugin had its own working loader — the catalog has the family, so the plugin trusted the core's answer |
| news |
both .bdf faces fell back |
| tide-display |
4x6.bdf worked and 5x7.bdf did not, purely because the default font_size of 6 happened to match one of them |
| mqtt-notifications, youtube-stats |
same loader, same behaviour |
The countdown case is the one that argues for fixing it here: the plugin only consulted its own loader when the catalog missed a family, so a family the core claims-and-then-degrades is worse than one it does not know about.
Suggested fix
In the loader, on OSError, read PIXEL_SIZE from the .bdf header and retry at that size before giving up:
try:
return ImageFont.truetype(path, size_px)
except OSError:
native = _bdf_pixel_size(path)
if native is None or native == size_px:
raise
return ImageFont.truetype(path, native)
That is the fix applied per-plugin in ChuckBuilds/ledmatrix-plugins#362, #369 and #370; doing it in FontManager would let those copies drop it.
Failing that, having resolve_font signal the fallback — a return value, or a warning naming the family — would at least make it diagnosable rather than looking like a plugin bug.
Environment
Pillow 11.3.0. The .bdf size constraint is a FreeType property rather than a Pillow-version one, so I would expect this to reproduce broadly, but I have only verified it here.
Summary
FontManager.resolve_font()cannot load a bitmap (.bdf) font at anything other than its own pixel size, and when it fails it returns the default face without signalling it. Callers cannot tell a successful load from a silent fallback, so a plugin offering a.bdfin its font picker appears to ignore the setting.Why it is invisible
A
.bdfexists at exactly one pixel size. FreeType raisesOSError: invalid pixel sizefor any other, soImageFont.truetype(path, size)fails whenever the requested size differs from the file'sPIXEL_SIZE.resolve_fontthen falls back — and in current Pillow the default face is itself aFreeTypeFont, so the returned type gives no hint that anything went wrong.common_fontscarriesfive_by_seven→assets/fonts/5x7.bdf, which is native 7px. Any caller asking for it at the usual 8 gets the default face back and no error.Impact seen in plugins
This has now surfaced in five plugins in
ledmatrix-plugins, each with its own copy of the loader:5x7.bdfand4x6.bdfrendered byte-identical to the defaultfive_by_sevenfell back even though the plugin had its own working loader — the catalog has the family, so the plugin trusted the core's answer.bdffaces fell back4x6.bdfworked and5x7.bdfdid not, purely because the defaultfont_sizeof 6 happened to match one of themThe countdown case is the one that argues for fixing it here: the plugin only consulted its own loader when the catalog missed a family, so a family the core claims-and-then-degrades is worse than one it does not know about.
Suggested fix
In the loader, on
OSError, readPIXEL_SIZEfrom the.bdfheader and retry at that size before giving up:That is the fix applied per-plugin in ChuckBuilds/ledmatrix-plugins#362, #369 and #370; doing it in
FontManagerwould let those copies drop it.Failing that, having
resolve_fontsignal the fallback — a return value, or a warning naming the family — would at least make it diagnosable rather than looking like a plugin bug.Environment
Pillow 11.3.0. The
.bdfsize constraint is a FreeType property rather than a Pillow-version one, so I would expect this to reproduce broadly, but I have only verified it here.