Skip to content

FontManager.resolve_font silently returns the default face for any .bdf #517

Description

@ChuckBuilds

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_sevenassets/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:

PluginSymptom
clock-simple5x7.bdf and 4x6.bdf rendered byte-identical to the default
countdownfive_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
newsboth .bdf faces fell back
tide-display4x6.bdf worked and 5x7.bdf did not, purely because the default font_size of 6 happened to match one of them
mqtt-notifications, youtube-statssame 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:
returnImageFont.truetype(path, size_px)
exceptOSError:
native=_bdf_pixel_size(path)
ifnativeisNoneornative==size_px:
raisereturnImageFont.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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions