NativeElixirPdfUtilities.HtmlToPdf.Font (native_elixir_pdf_utilities v1.0.0)

View Source

Font loading, fallback resolution, text measurement, and PDF text encoding.

The renderer loads explicitly configured fonts, discovers installed fonts on demand, and keeps the bundled DejaVu Sans faces as the final fallback.

Summary

Types

A document-scoped mapping from Unicode code points to PDF CIDs and font glyphs.

Functions

Encodes original text for an embedded Type0 font content stream. Applies the encoding's available ligatures unless letter spacing is nonzero.

Returns configured and bundled fallback faces in family declaration order, ordering each family's faces by the closest weight and style.

Loads explicit TTF font options into a registry.

Builds a document-scoped CID encoding for text shown with an embedded font. Entries may be strings or {text, letter_spacing} pairs for spaced glyph runs.

Returns the PDF resource key for a selected font face.

Resolves a CSS font-family value or fallback list to a supported font face.

Shapes common Latin ligatures when the font provides them and letter spacing is zero.

Returns whether a font face can safely encode every codepoint in text.

Measures glyph advances in PDF points for the selected font and size. Nonzero letter spacing disables optional ligatures; callers add spacing separately.

Builds CID-to-Unicode mappings for all text shown with an embedded font.

Types

built_in_font()

@type built_in_font() :: %{type: :built_in, family: String.t(), pdf_name: String.t()}

embedded_font()

@type embedded_font() :: %{
  type: :embedded,
  family: String.t(),
  weight: number(),
  style: font_style(),
  id: String.t(),
  pdf_name: String.t(),
  data: binary(),
  units_per_em: pos_integer(),
  widths: [non_neg_integer()],
  default_width: non_neg_integer(),
  cmap: %{optional(non_neg_integer()) => non_neg_integer()},
  kerning: %{optional({non_neg_integer(), non_neg_integer()}) => integer()},
  ascent: integer(),
  descent: integer(),
  line_gap: integer(),
  bbox: {integer(), integer(), integer(), integer()},
  embedding_flags: non_neg_integer(),
  variable_font?: boolean(),
  source: :configured | :bundled | :system
}

font_face()

@type font_face() :: built_in_font() | embedded_font()

font_style()

@type font_style() :: :normal | :italic

pdf_encoding()

@type pdf_encoding() :: %{
  codepoint_to_cid: %{optional(non_neg_integer()) => pos_integer()},
  cid_to_gid: %{optional(pos_integer()) => non_neg_integer()},
  cid_to_unicode: %{optional(pos_integer()) => non_neg_integer()}
}

A document-scoped mapping from Unicode code points to PDF CIDs and font glyphs.

registry()

@type registry() :: %{
  embedded: [embedded_font()],
  fallback: [embedded_font()],
  system_font_discovery: boolean()
}

Functions

encode_embedded_text(text, encoding_or_font, letter_spacing \\ 0)

@spec encode_embedded_text(String.t(), pdf_encoding() | embedded_font(), number()) ::
  String.t()

Encodes original text for an embedded Type0 font content stream. Applies the encoding's available ligatures unless letter spacing is nonzero.

fallback_faces(registry, weight, style)

@spec fallback_faces(registry(), number(), font_style()) :: [embedded_font()]

Returns configured and bundled fallback faces in family declaration order, ordering each family's faces by the closest weight and style.

load_registry(opts)

@spec load_registry(keyword()) ::
  {:ok, registry()}
  | :error
  | {:error, {:invalid_document | :resource_limit_exceeded, map()}}

Loads explicit TTF font options into a registry.

Accepted font entries are maps, keyword lists, or {family, path} tuples. Map and keyword entries must include :family and one or more :path or :data candidates; :weight and :style are optional.

pdf_encoding(texts, font)

@spec pdf_encoding([String.t() | {String.t(), number()}], embedded_font()) ::
  pdf_encoding()

Builds a document-scoped CID encoding for text shown with an embedded font. Entries may be strings or {text, letter_spacing} pairs for spaced glyph runs.

pdf_name(font)

@spec pdf_name(font_face()) :: String.t()

Returns the PDF resource key for a selected font face.

resolve(family_value, weight, style, registry)

@spec resolve(String.t() | [String.t()], number(), font_style(), registry()) ::
  {:ok, [String.t()], font_face()}
  | :error
  | {:error, {:resource_limit_exceeded, map()}}

Resolves a CSS font-family value or fallback list to a supported font face.

shape_ligatures(text, font, letter_spacing \\ 0)

@spec shape_ligatures(String.t(), map(), number()) :: String.t()

Shapes common Latin ligatures when the font provides them and letter spacing is zero.

supports_text?(font, text)

@spec supports_text?(font_face(), String.t()) :: boolean()

Returns whether a font face can safely encode every codepoint in text.

Built-in PDF fonts are limited to printable ASCII. Embedded fonts are checked against their Unicode character map.

text_width(text, font, font_size, letter_spacing \\ 0)

@spec text_width(String.t(), map(), number(), number()) :: number()

Measures glyph advances in PDF points for the selected font and size. Nonzero letter spacing disables optional ligatures; callers add spacing separately.

unicode_mappings(texts, font)

@spec unicode_mappings([String.t()], embedded_font()) :: %{
  optional(non_neg_integer()) => non_neg_integer()
}

Builds CID-to-Unicode mappings for all text shown with an embedded font.