Native PDF generation for Elixir.
Builds a styled element tree, lays it out with Taffy (flexbox), and renders it to PDF via krilla — all in a Rust NIF.
Summary
Functions
Computes layout without rendering, returning the box tree.
Paginates a node tree without rendering, returning one box tree per page.
Renders a node tree (or a rendered ~PDF template) to a PDF binary.
Functions
@spec layout( Mead.Node.t() | Phoenix.LiveView.Rendered.t(), keyword() ) :: map()
Computes layout without rendering, returning the box tree.
Each box is a map with absolute :x/:y (page coordinates, top-left
origin), :width, :height, :children, and — for text nodes — the
wrapped :lines. Mirrors the geometry render/2 draws from; intended
for tests and debugging.
@spec paginate( Mead.Node.t() | Phoenix.LiveView.Rendered.t(), keyword() ) :: [map()]
Paginates a node tree without rendering, returning one box tree per page.
Boxes are in page coordinates (the page margin and any header height
are included in positions). Takes the same options as render/2, plus:
:chrome- when true, each page is returned as%{content: box, header: box | nil, footer: box | nil}instead of the bare content box.
@spec render( Mead.Node.t() | Phoenix.LiveView.Rendered.t(), keyword() ) :: binary()
Renders a node tree (or a rendered ~PDF template) to a PDF binary.
Options
:page_size-{width, height}in points, defaults to A4 portrait.:margin- uniform page margin in points applied on every page (the content box is inset by it), defaults to 0.:session- aMead.Sessionto render through (reuses parsed fonts and warm shaping state across renders; the recommended way to render repeatedly). SeeMead.Session.new/1.:font_set- a prebuiltMead.FontSet; a fresh session is created for the call. Prefer:sessionfor repeated renders.:fonts-%{family => [variant]}map to build an ephemeral font set, seeMead.FontSet.new/2.:font_fallback- fallback chain for the ephemeral:fontsset (Mead.FontSet.new/2's:fallbackoption).:font_pool- lazy fallback pool paths for the ephemeral:fontsset (Mead.FontSet.new/2's:pooloption; the pool is rescanned per call — prefer a persistent:sessionfor pooled rendering).:font- path to a single TTF/OTF used as the entire default family.
With none of the font options, rendering goes through the global
default session (Mead.Session.default/0): fonts from the :mead_pdf, :fonts application env, parsed once per VM.
:title/:author/:language- document metadata (PDF Info dictionary + XMP).:header/:footer- running page chrome: a node tree (or~PDFtemplate) laid out against the content width, painted at the top / bottom of every page's content box; the flow content shrinks by its height. Counter spans (Mead.Node.page_number/1,page_count/1; markup<page_number/>,<page_count/>) are substituted after pagination — chrome containing them is re-laid out per page, inside its reserved height.:max_pages- pagination safety cap (also honored bypaginate/2). Raises with a clear error instead of paginating further; a runaway document (e.g. content that can never fit a page) then fails fast rather than looping. Defaults to the:mead_pdf, :max_pagesapplication env, or 5000; pass:infinityto disable.
Content taller than one page's content box flows onto additional pages;
see Mead.Node for the pagination props (break_before, wrap,
repeat).