Fonts¶
Font loading and text measurement live in the novasvg.fonts submodule. It is
backed by the same font stack that paints text and <foreignObject> content, so a
measurement can never disagree with what is rendered.
import novasvg.fonts as fonts
fonts.add_font_face_from_file("DejaVu Sans", False, False, "DejaVuSans.ttf")
face = fonts.get_font_face("DejaVu Sans", bold=False, italic=False)
font = fonts.Font(face, size=16.0)
font.measure_text("Hello, world!") # width in pixels
Reference¶
- class FontFace(*args, **kwargs)¶
- advance_width_units(self, codepoint: int) float¶
Advance width of a single Unicode codepoint, in raw font design units (unscaled).
- codepoints(self) list[int]¶
Every Unicode codepoint this face’s cmap maps to a glyph (see FontFace::codepoints() in font.h for exactly which cmap formats are covered – virtually every real-world font).
- is_null(self) bool¶
Check if the font face is null/invalid.
- kern_advance_units(self, first: int, second: int) float¶
Kerning adjustment between two consecutive codepoints, in raw font design units (unscaled) – see FontFace::kernAdvanceUnits() in font.h for why this is a per-pair query rather than a bulk table like codepoints().
- property ascent_units¶
Ascent in raw font design units (unscaled).
- property descent_units¶
Descent in raw font design units (unscaled).
- property notdef_advance_width_units¶
The advance width used for any codepoint outside this font’s cmap (glyph id 0, the “.notdef” glyph) – what advance_width_units() itself already falls back to for such a codepoint.
- property units_per_em¶
Raw font design-unit space this face’s own tables are defined in (e.g. head.unitsPerEm). Pair with advance_width_units()/ascent_units()/descent_units() to build a complete, size-independent advance table – e.g. to hand text-measurement data to a JS engine that can’t call back into Python per string (mermaidx’s v8_engine does exactly this).
- class Font(*args, **kwargs)¶
- glyph_boxes()¶
(self, text: str) -> list
Per-glyph (pen_x, ink_left, ink_right, ink_top, ink_bottom) in pixels (top/bottom relative to the baseline, y down) for every glyph that has an outline (spaces are skipped), using the same ligature + kerning walk as measure_text().
- is_null(self) bool¶
Check if the font is null/invalid.
- measure_text(self, text: str) float¶
Measure the advance width of a UTF-8 string, in pixels, at this font’s size.
- property ascent¶
Ascent in pixels, at this font’s size.
- property descent¶
Descent in pixels (typically negative), at this font’s size.
- property face¶
The underlying FontFace.
- property height¶
ascent - descent.
- property line_gap¶
Recommended extra spacing between lines, in pixels.
- property size¶
The pixel size this font was constructed with.
- property x_height¶
Height of a lowercase ‘x’ glyph, in pixels.
- add_font_face_from_file(family: str, bold: bool, italic: bool, filename: str) bool¶
Add a font face from a file to the cache.
- add_font_face_from_data(family: str, bold: bool, italic: bool, data: bytes) bool¶
Add a font face from a memory buffer (bytes) to the cache.
- get_font_face(family: str, bold: bool = False, italic: bool = False) novasvg.FontFace¶
Look up a font face previously registered via add_font_face_from_file/_data (falling back to novasvg’s built-in generic-family table, e.g. “sans-serif”).
- get_font_face_for_family_stack(family_stack: str, bold: bool = False, italic: bool = False) novasvg.FontFace¶
Resolve a CSS-style comma-separated font-family stack (e.g. ‘“trebuchet ms”, verdana, arial, sans-serif’) name by name: a face registered or installed under that exact name, then a metric-compatible substitute from novasvg’s built-in table (case-insensitive, e.g. ‘arial’ -> Liberation Sans), then generic keywords. Names nothing matches are skipped; returns a null face if none resolve.
- measure_foreign_object(html: str, font: novasvg.Font, max_width: float | None = None, family: str | None = None, bold: bool = False, italic: bool = False) dict¶
Height/width (and line count/line-height) novasvg will use when painting <foreignObject> content, computed WITHOUT rendering – the exact same logic ForeignObjectSimple::render() itself uses (see measureForeignObjectContent() in svgelement.h), so a caller building the SVG’s own layout (e.g. mermaidx’s headless JS DOM shim sizing a node box for an HTML label) can ask novasvg what size it will need instead of guessing separately. Text soft-wraps only if the HTML’s own CSS white-space allows it (not nowrap/pre), at max_width (px) if given, else at the px width/max-width the HTML itself declares – the same rule render() applies at the foreignObject’s own width, so layout and paint agree. Bold and italic runs (<b>, <strong>, <i>, <em>, inline font-weight / font-style) are measured with the faces they are painted with when family is given: font is then the face of the base style (bold / italic say which it is) and the other variants are looked up in family exactly as SVG <text> looks them up. Without family every run is measured with font alone, as if it had no bold or italic in it. Returns {‘height’: float, ‘width’: float, ‘line_count’: int, ‘line_height’: float}; ‘width’ is the widest resulting line.