Skip to main content

A simple mathematical LaTeX renderer for Python. Output as PNG (Pillow) or SVG (vector text with New Computer Modern).

Super- and subscript

Installation

pip install fondi

Requires Python 3.8+, Pillow, and NumPy.

Quick start

import fondi

mt = fondi.MathText(r"\frac{1}{2}", fontSize=50, color=(255, 255, 255, 255))

mt.to_pil().save("formula.png")   # raster
mt.save_svg("formula.svg")        # small SVG + external fonts (default)

MathText arguments

Argument Type Description
text str Fondi math string (LaTeX-like, not full LaTeX).
fontSize int Nominal size in pixels (same scale as the PNG renderer).
color (R, G, B, A) Each channel 0–255.

Output methods

Method Returns Use for
to_pil() PIL.Image Matplotlib, GUIs, notebooks, textures.
to_svg(...) str SVG XML; you control where files are written.
save_svg(path, ...) Path Write SVG to disk; optional font copy.
scene() Scene Inspect layout primitives (advanced).
image PIL.Image Same as to_pil() (backward compatible).

SVG export and fonts

Text in SVG uses New CM10 (NewCM10-Regular.otf / NewCM10-Italic.otf from the package). Integrals and braces are still embedded PNGs inside the SVG (v1).

You choose how those OTF files are shipped:

Mode SVG size Font files Best for
Embedded Large (~1 MB+) Inside the SVG Single file, email, simple hosting
External + copy Small (few KB) Copied next to the SVG First export in a project
External, no copy Small You provide them Many SVGs sharing one fonts/ folder

1. Embedded fonts (self-contained)

Every to_svg() call includes both full OTF files as base64 in <defs>. No separate font files; viewers need nothing installed.

svg = mt.to_svg()                                    # default
svg = mt.to_svg(embed_fonts=True)

with open("formula.svg", "w") as f:
    f.write(svg)

mt.save_svg("formula.svg", embed_fonts=True)

2. External fonts (small SVG)

The SVG references OTF files by URL, e.g. fonts/NewCM10-Regular.otf. You must keep those paths valid relative to where the SVG is opened (browser, Inkscape, etc.).

to_svg() — string only

svg = mt.to_svg(embed_fonts=False, font_url_prefix="fonts/")
# Writes no font files. You place the OTFs yourself.
Parameter Default Meaning
embed_fonts True False → external @font-face URLs.
font_url_prefix "" Directory prefix in the URL, e.g. "fonts/" or "" if OTFs sit beside the SVG.

Copy fonts once from the package:

from fondi.backends import copy_font_files

copy_font_files("shared/fonts/")
# Creates shared/fonts/NewCM10-Regular.otf and NewCM10-Italic.otf

Then export many formulas pointing at the same folder:

for name, tex in formulas.items():
    m = fondi.MathText(tex, 24, (0, 0, 0, 255))
    with open(f"out/{name}.svg", "w") as f:
        f.write(m.to_svg(embed_fonts=False, font_url_prefix="../shared/fonts/"))

save_svg() — write file (+ optional font copy)

mt.save_svg("out/formula.svg")

Defaults: embed_fonts=False, font_subdir="fonts", copy_fonts=True.

Parameter Default Meaning
embed_fonts False True → one large self-contained SVG.
font_subdir "fonts" Subfolder under the SVG’s parent for OTF files and URL prefix ("fonts/"). Use None for OTFs in the same directory as the SVG.
copy_fonts True Copy bundled OTFs into font_subdir. False → only write the SVG (fonts must already exist there).

Copy fonts once per output tree:

mt.save_svg("out/formula.svg", embed_fonts=False, font_subdir="fonts")
out/
  formula.svg
  fonts/
    NewCM10-Regular.otf
    NewCM10-Italic.otf

SVG only (fonts already present):

from fondi.backends import copy_font_files

copy_font_files("out/fonts/")   # once

for i, tex in enumerate(items):
    fondi.MathText(tex, 20, (0, 0, 0, 255)).save_svg(
        f"out/label_{i}.svg",
        embed_fonts=False,
        font_subdir="fonts",
        copy_fonts=False,
    )

OTFs beside the SVG (no subfolder):

mt.save_svg("out/formula.svg", embed_fonts=False, font_subdir=None)
# Expects out/NewCM10-Regular.otf next to out/formula.svg
# URLs in SVG: NewCM10-Regular.otf (no prefix)

Choosing a mode (cheat sheet)

# One file, simplest sharing
mt.save_svg("x.svg", embed_fonts=True)

# Project with assets/fonts/ reused everywhere
copy_font_files("assets/fonts/")
mt.save_svg("plots/a.svg", embed_fonts=False, font_subdir="fonts", copy_fonts=False)
# Ensure font_subdir resolves from plots/a.svg → often use font_url_prefix like "../assets/fonts/"
# via to_svg(), or place fonts relative to each SVG accordingly

For nested paths, prefer to_svg(embed_fonts=False, font_url_prefix="...") with a prefix that matches your real directory layout.

Low-level API

from fondi.backends import render_svg, save_svg_bundle, copy_font_files

scene = mt.scene()
svg = render_svg(scene, embed_fonts=False, font_url_prefix="fonts/")
save_svg_bundle(scene, "out.svg", embed_fonts=False, font_subdir="fonts", copy_fonts=False)

PNG export

Raster output bakes the font into pixels. No font files are needed at view time.

img = mt.to_pil()
img.save("formula.png")
mt.image.save("formula.png")   # equivalent

Architecture

Layouts position math and emit a backend-neutral scene graph (TextRun, Line, RasterSymbol, …). Renderers turn the same scene into PNG or SVG — new macros are implemented once.

Layer Role
layout/*, plain/plain.py Geometry + scene primitives only
metrics.py Font measurement (single source)
scene.py Data types
backends/pillow.py, backends/svg.py PNG / SVG output

Adding a macro (write once)

  1. Add FooLayout(Layout) under src/fondi/layout/.
  2. Register MACROS["\\foo"] = FooLayout.
  3. Position children with boundingBox, setCenter, etc.
  4. Implement collect_scene(offset) returning TextRun, Line, RasterSymbol, … — no Pillow or SVG code in the layout.
  5. Run tests/test.py (PNG) and tests/test_svg.py (SVG smoke).

Features

  • Parentheses
  • Subscript / superscript
  • Delimiters ((), [], cases {) as vector paths; integrals still PNG (v1)
  • Fractions
  • Cases
  • Greek letters
  • Square root
  • Integrals

Tests

cd tests && python test.py      # regenerate PNG golden images
cd tests && python test_svg.py  # SVG smoke (embedded + external fonts)

Metadata

Release files for fondi 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fondi 0.2.2
File Size Uploaded Provenance
fondi-0.2.2.tar.gz 10.5 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fondi 0.2.2
File Interpreter ABI Platform
fondi-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 21.1 MB

Release files / fondi-0.2.2.tar.gz

Download URL fondi-0.2.2.tar.gz
Size 10.5 MB
Tags Source
SHA-256 checksum
How to use checksums
71e50fd0eb968ac9f393693c43cd62f60356bcd47255e1b2b7200197160a7763
BLAKE2b-256 checksum
How to use checksums
bfcf7cbb129004dda49f641085c4beed71fa52366274d9a8b305c1a6998ed537
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / fondi-0.2.2-py3-none-any.whl

Download URL fondi-0.2.2-py3-none-any.whl
Size 10.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
3623d007ced80eac2f33462afcd6ba6c4f115d5efe61c56836682c7f257783c5
BLAKE2b-256 checksum
How to use checksums
1106dd66eb3d1684b11ca45a0f17fde69855e697f3fd3e9925c9591193eecd79
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Security for fondi 0.2.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page