latex-rust 1.0.1

Pure-Rust LaTeX math renderer. Parse to AST, TeX-faithful layout in zenith-float, emit SVG, PNG, or egui shapes. No JavaScript, no webview, no runtime.
Documentation

LaTeX-Rust

License: MIT License: Apache-2.0

Repository: https://github.com/jscarr64/LaTeX-Rust

Pure Rust LaTeX math renderer. No JavaScript. No webview. No runtime dependencies.

It parses LaTeX math into a typed AST, lays the AST out with a TeX-faithful box model whose dimensions are zenith-float Dim values (no hardware f32/f64 in the layout path), and renders to SVG, PNG (features = ["png"]), or egui shapes (features = ["egui"]).

Features

  • Parses LaTeX math to a typed AST
  • TeX-faithful layout engine (Appendix G exact)
  • SVG output — self-contained, scalable, no font embedding required
  • PNG output (features = ["png"]) via tiny-skia
  • egui integration (features = ["egui"]) for native desktop apps
  • Full symbol coverage — Greek, AMS, arrows, operators, font styles
  • Complete accent and decoration support
  • Multiline environments — align, gather, multline, cases, array
  • Color support — named, RGB, HTML, CMYK, gray, \definecolor
  • 100% pure Rust — no C, no Python, no shell, no subprocesses
  • MIT OR Apache-2.0
src/parser/     LaTeX → AST
src/layout/     AST → box model
src/font/       STIX Two Math metrics / TrueType loader
src/render/svg  box model → SVG
src/render/png  box model → PNG (`tiny-skia`, feature `png`)
src/render/egui box model → egui Shapes (feature `egui`)
golds/          gold tests (repository only)
benches/        parse / layout / render timings

This crate does not typeset documents. Text-mode LaTeX, TikZ, chemistry, and PDF are out of scope and return Err — never a fake render.

Quick start

[dependencies]
latex-rust = "1.0"

Until the crate is on crates.io:

[dependencies]
latex-rust = { git = "https://github.com/jscarr64/LaTeX-Rust" }
use latex_rust::{parse, layout, latex_to_svg, MathFont, MathStyle, SvgOptions};

let ast = parse(r"\frac{1}{2}").expect("parse");
let font = MathFont::stix_two_math().expect("STIX Two Math");
let boxed = layout(&ast, &font, MathStyle::Text).expect("layout");
assert!(!boxed.width.is_zero());

let svg = latex_to_svg(r"\frac{1}{2}", &font, &SvgOptions::new()).expect("svg");
assert!(svg.contains("<svg"));

Layout math uses the published zenith-float 1.0 crate (ExactNum software floats). This crate depends on zenith-float only — not on its inner kernel package.

MSRV is 1.76 (matches optional egui 0.28).

Usage

SVG

use latex_rust::{latex_to_svg, MathFont, SvgOptions};

let font = MathFont::stix_two_math().unwrap();
let svg = latex_to_svg(r"e^{i\pi}+1=0", &font, &SvgOptions::new()).unwrap();

PNG

Enable with features = ["png"]. tiny-skia rasterizes the same MathBox tree as the SVG backend. SIMD is selected at runtime:

  • On x86_64 with AVX2 — tiny-skia runs at peak performance automatically
  • On Apple Silicon — tiny-skia uses the ARM NEON path, also fast
  • No user configuration needed
  • No compile flags required
  • Works correctly on every supported architecture

Without the feature, latex_to_png / render_png return Err(Unsupported).

# #[cfg(feature = "png")]
# {
use latex_rust::{latex_to_png, MathFont, PngOptions};

let font = MathFont::stix_two_math().unwrap();
let png = latex_to_png(r"\frac{1}{2}", &font, &PngOptions::new()).unwrap();
assert!(png.starts_with(b"\x89PNG"));
# }

egui

Enable with features = ["egui"]. Glyphs become egui::Mesh; rules and color boxes become Shape::Rect. No SVG intermediate. Callers should keep the returned Vec<Shape> if the same expression is painted every frame (cache hit).

# #[cfg(feature = "egui")]
# {
use latex_rust::{latex_to_shapes, EguiOptions, MathFont};

let font = MathFont::stix_two_math().unwrap();
let (shapes, rect) =
    latex_to_shapes(r"x^2", &font, &EguiOptions::new(), egui::Pos2::ZERO, 1.0).unwrap();
assert!(!shapes.is_empty());
let _ = rect;
# }

Supported LaTeX

Math mode only. Command and environment coverage is the capability inventory in documents/latex-rust-build-sheet.md and the catalog data/symbols.tsv. Look up a command with latex_rust::lookup. Missing glyphs and unknown commands are Err.

Color: named_color / parse_color_spec. Channel values use Dim. spot and unknown names return Err. SVG, PNG, and egui all take Color::to_rgba8().

Performance

Times below are median-of-batch averages from cargo bench --features png,egui on this machine (release, zenith-float Dim layout). Re-run the bench on your hardware; the targets are the build-sheet gates.

Operation Target Measured
Parse \frac{1}{2} < 50µs 1.8µs
Parse full display equation < 200µs 3.3µs
Layout \frac{1}{2} < 100µs 13µs
Layout full display equation < 500µs 47µs
SVG \frac{1}{2} < 500µs 232µs
SVG full display equation < 1ms 951µs
PNG 144 DPI < 5ms 142µs
PNG 300 DPI < 15ms 350µs
egui inline (cache miss) < 2ms 216µs
egui inline (cache hit) < 0.1ms 29µs

KaTeX cold start in a browser is typically 200–400ms (JS parse + layout + font). This crate’s first MathFont::stix_two_math() plus an SVG of a short expression is on the order of the layout+SVG rows above after the face is loaded (embedded STIX Two Math, no network). There is no JS runtime to warm up.

Fonts

The crate embeds STIX Two Math 2.13 (SIL OFL 1.1) and loads metrics through ttf-parser using integer font units converted to Dim. Glyph outlines become SVG <path> elements (and PNG/egui meshes when those features are on).

License

MIT OR Apache-2.0. STIX Two Math remains under the SIL Open Font License 1.1. See NOTICE.