OpenFresco.Measure (open_fresco v0.1.0)

Copy Markdown View Source

Text measurement — the primitive that turns estimate-based layout into measurement-accurate layout (the checklist's "same wrap points, same measured sizes" gate).

When the :resvg dependency is available, widths come from resvg's own layout engine via query_all — the same engine that paints the final PNG, so wrap points match the render exactly. Without resvg (SVG-only hosts), it falls back to a character-count estimate (~0.55em), matching phoenix_kit_og's heuristic.

Measurement writes a probe SVG to a tempfile and calls the NIF, so it is used by the layout pass (OpenFresco.Layout) rather than the hot render path directly. Batch related strings into one widths/2 call.

Summary

Functions

Whether resvg-backed measurement is available (else estimate).

Measure a single string's width.

Measure a batch of text specs. Returns %{id => width_px}. Uses resvg when available (one NIF call for the whole batch); estimates otherwise or on any error. Empty strings measure 0.

Types

spec()

@type spec() :: %{
  id: String.t(),
  text: String.t(),
  size: number(),
  font: String.t(),
  weight: number()
}

Functions

available?()

@spec available?() :: boolean()

Whether resvg-backed measurement is available (else estimate).

text_width(text, font_spec, opts \\ [])

@spec text_width(
  String.t(),
  %{size: number(), font: String.t(), weight: number()},
  keyword()
) ::
  float()

Measure a single string's width.

widths(specs, opts \\ [])

@spec widths(
  [spec()],
  keyword()
) :: %{required(String.t()) => float()}

Measure a batch of text specs. Returns %{id => width_px}. Uses resvg when available (one NIF call for the whole batch); estimates otherwise or on any error. Empty strings measure 0.