tituli.fonts¶
Font discovery with no bundled fonts.
tituli never ships a typeface (licensing), so a typeface request — a family
name, weight and slant — is resolved against the fonts already installed on the
machine, and falls back to the scalable face Pillow embeds (Aileron). That fallback
is a real font, not a stub, so every render works out of the box on a bare CI
runner; it just looks better on a machine with Helvetica Neue.
Resolution order is a preference list: the first family found wins.
>>> face = resolve_face(["No Such Family", "DejaVu Sans"], size=48)
>>> face.size
48
>>> face.family in ("DejaVu Sans", "Aileron") or isinstance(face.family, str)
True
Module Attributes
A family request that means Pillow's embedded face, and never the system. |
Functions
|
The bytes of the font file behind |
|
|
|
Sorted family names installed on this machine. |
|
First installed family in the preference list, at the closest style. |
Platform font directories that exist on this machine. |
|
Installed faces grouped by family name. |
|
|
Resolve a typeface request to a sized |
Classes
|
A resolved, sized font ready to measure and draw with Pillow. |
|
One face inside a font file (a |
- tituli.fonts.EMBEDDED = 'tituli:embedded'¶
A family request that means Pillow’s embedded face, and never the system. In a preference list it is a stop: the names before it are looked up as usual, and if none is installed the embedded face is used without scanning further. Alone (or first) it never scans the system at all, so the result is the same bytes on every machine with the same Pillow — the deterministic choice for a caller whose output must not depend on the installed fonts. (Asking for
"Aileron"by name is not the same thing: a machine that has Aileron installed would resolve to that file.)
- class tituli.fonts.Face(family, style, size, path, index=0, features=())[source]¶
Bases:
objectA resolved, sized font ready to measure and draw with Pillow.
- property applied_features: tuple[str, ...]¶
The requested
featuresthis font has, so the ones measured and outlined with; a requested tag missing here was not applied.>>> resolve_face(EMBEDDED, size=12).applied_features ()
- features: tuple[str, ...] = ()¶
OpenType feature tags the style asked for (tituli#4); which of them the font has is
applied_features.
- length(text)[source]¶
Advance width of
textin pixels.With
applied_features, the advances of the substituted glyphs (tituli.features.featured_length()): the font’s design advances, without hinting or kerning, which is what tabular figures are for.- Return type:
- property pil: FreeTypeFont¶
The Pillow font object (cached per
(path, index, size)).
- class tituli.fonts.FontFile(path, index, family, style)[source]¶
Bases:
objectOne face inside a font file (a
.ttcholds several).
- tituli.fonts.face_bytes(face)[source]¶
The bytes of the font file behind
face— the embedded face’s too.Pillow keeps the embedded face’s bytes on the font object it builds (
font_bytes), so the fallback has an identity like any file does.- Return type:
>>> face_bytes(resolve_face(EMBEDDED, size=12))[:4] in (b"\x00\x01\x00\x00", b"true", b"OTTO") True
- tituli.fonts.face_digest(face)[source]¶
sha256offace_bytes()— what makes two faces the same face.A family name is not an identity (two machines can install different files under one name, and the embedded face can change with Pillow); the bytes are.
- Return type:
- tituli.fonts.find_font(family, *, weight=400, italic=False, condensed=False)[source]¶
First installed family in the preference list, at the closest style.
familymay be one name or a preference list. A path to a font file is accepted too, and wins outright.>>> find_font("definitely-not-installed-xyz") is None True
- tituli.fonts.font_dirs()[source]¶
Platform font directories that exist on this machine.
Extra directories can be prepended with
TITULI_FONT_DIRS(os.pathsepseparated), which is also how a project supplies its own licensed fonts.
- tituli.fonts.font_index()[source]¶
Installed faces grouped by family name. Scanned once per process.
>>> idx = font_index() >>> all(isinstance(k, str) for k in idx) True
- tituli.fonts.resolve_face(family=('Helvetica Neue', 'Inter', 'Helvetica', 'Avenir Next', 'Roboto', 'Univers', 'Liberation Sans', 'DejaVu Sans', 'Arial'), *, size, weight=400, italic=False, condensed=False, features=())[source]¶
Resolve a typeface request to a sized
Face; never fails.featuresare OpenType feature tags to apply (("tnum",)), carried by the face; seeFace.applied_featuresfor which the font has.Falls back to Pillow’s embedded Aileron when nothing in the list is installed, so a render on a fontless CI box still produces a real (if plainer) result.
EMBEDDEDin the list stops the search there (see its comment):- Return type:
>>> resolve_face(EMBEDDED, size=20).path is None True >>> resolve_face(["definitely-not-installed-xyz", EMBEDDED], size=20).family 'Aileron'