Quick Start =========== Installation ------------ Install ManimPango from PyPI:: pip install manimpango The Windows and macOS wheels bundle their native dependencies, so installing them from PyPI does not require Pango or Cairo to be installed separately. Linux has no binary wheels at present, so installation there builds from source and requires a C compiler, ``pkg-config``, and the Pango development headers. To build from source on macOS, install Pango and Cairo first, for example with `Homebrew `_:: brew install pango cairo Source builds on Windows need Pango 1.56 or newer to register private font files at runtime. Rendering Plain Text -------------------- Use :func:`~manimpango.render` for plain text. It returns a :class:`~manimpango.RenderedText` object containing SVG and layout metadata. .. code-block:: python import manimpango result = manimpango.render("Hello, world!", size=24.0) svg = result.svg result.save("hello.svg") ``save()`` writes to an existing parent directory; it does not create missing directories. Understanding ``RenderedText`` ------------------------------ Both rendering functions return a :class:`~manimpango.RenderedText` object rather than writing a temporary file. It keeps the SVG document and the layout result together, so callers can choose whether to keep the SVG in memory, save it, or inspect its geometry. The basic result contract is executable and independent of the host's font metrics: .. doctest:: >>> import manimpango >>> result = manimpango.render("Hello, world!", size=24.0) >>> isinstance(result, manimpango.RenderedText) True >>> result.line_count 1 >>> isinstance(result.svg, str) and result.width > 0 and result.height > 0 True For example, one macOS/Pango installation produces the following selected values. The exact numbers vary with the selected font and native backend; the relationships and SVG user-space units do not. .. code-block:: pycon >>> result RenderedText(width=130.0, height=24.0, baseline=18.0, line_count=1) >>> round(result.width, 1), round(result.height, 1), round(result.baseline, 1) (130.0, 24.0, 18.0) >>> result.ink_bounds Bounds(x=0.38671875, y=1.546875, width=127.33203125, height=19.875) >>> result.logical_bounds Bounds(x=0.0, y=0.0, width=130.0, height=24.0) ``width`` and ``height`` are the rendered SVG viewport dimensions, and ``baseline`` is the first line's baseline position. ``ink_bounds`` is tight to glyph drawing, so it excludes the side bearings and whitespace visible in ``logical_bounds``. All of these values, as well as font ``size`` and an optional layout ``width``, are ``float`` values in SVG user-space units—not raw Pango units or device pixels. An SVG consumer may subsequently scale the document. The complete SVG is available without another render operation, and may be written only when a file is needed: .. code-block:: python svg = result.svg result.save("hello.svg") ``RenderedText`` is immutable and ``result.lines`` is a tuple. Its ``lines`` describe the parsed text, code-point ranges, bounds, and baselines for individual lines. The following section shows how to inspect them. Rendering Markup ---------------- Pango markup has its own entry point. Do not pass markup to ``render()``. .. code-block:: python result = manimpango.render_markup( "Important", font="Helvetica", size=24.0, ) Styling Plain Text with Spans ----------------------------- Use :class:`~manimpango.TextSpan` for styled ranges in plain text. Span offsets are Python code-point offsets and are half-open, just like string slices. Spans and markup are deliberately separate APIs. .. code-block:: python text = "Hello, world!" result = manimpango.render( text, spans=( manimpango.TextSpan(0, 5, weight=manimpango.Weight.BOLD), manimpango.TextSpan(7, 12, foreground="#3366cc"), ), ) Inspecting Layout Metadata -------------------------- All geometry exposed by ManimPango is a ``float`` in SVG user-space units. ``Bounds`` records an ``x``, ``y``, ``width``, and ``height`` in that same coordinate system. ``LineInfo`` contains the rendered line text, its half-open code-point range, bounds, and baseline. .. code-block:: python result = manimpango.render("Line 1\nLine 2", width=200.0) print(result.width, result.height, result.baseline) print(result.ink_bounds, result.logical_bounds) for line in result.lines: print(line.text, line.start, line.end, line.bounds, line.baseline) Variable Fonts -------------- ``weight`` accepts a :class:`~manimpango.Weight` member or an integer from 1 through 1000. Use ``variations`` for OpenType axes; axis tags contain exactly four ASCII characters. ManimPango forwards these settings to Pango, but a visible effect depends on the selected font, axis, and renderer backend. For example, the bundled test font's ``wght`` axis changes output on the current Linux, macOS, and Windows test backends, while its ``CNTR`` axis does not change output through the current macOS Pango/CoreText/Cairo stack. This is a fixture-and-renderer compatibility observation, not a general CoreText limitation. Test variation-dependent output on every platform you support. .. code-block:: python result = manimpango.render( "Smooth weight", font="Inter", weight=450, variations={"wght": 650, "wdth": 90}, ) Custom Fonts ------------ :func:`~manimpango.register_font` returns a :class:`~manimpango.FontRegistration` handle. Use it as a context manager so the registration closes predictably. Multiple handles for a path are reference-safe; closing one does not release the font while another remains open. .. code-block:: python with manimpango.register_font("path/to/MyFont.ttf") as registration: assert not registration.closed result = manimpango.render("Custom font", font="My Font") assert registration.closed