Tincture.Font.TTF (Tincture v0.1.0)

Copy Markdown View Source

Reads the metrics and metadata a PDF needs out of a font file.

parse_basic_tables/1 takes the bytes of a TrueType or OpenType font and returns everything the rest of the library needs to lay text out and embed the font: units per em, glyph count, advance widths, the bounding box, style flags, the character map, kerning pairs and ligatures.

This module is a coordinator. It reads the sfnt table directory and hands each table to the module that understands that format:

Font files are untrusted input. Every parser returns :error rather than raising, and a table that is present but malformed fails the parse instead of producing wrong metrics.

Summary

Types

basic_metrics()

@type basic_metrics() :: %{
  units_per_em: pos_integer(),
  num_glyphs: pos_integer(),
  number_of_h_metrics: pos_integer(),
  advance_widths: [non_neg_integer()],
  max_advance_width: non_neg_integer(),
  cmap_by_code: %{optional(non_neg_integer()) => non_neg_integer()},
  cmap_var_selectors: [non_neg_integer()],
  cmap_non_default_uvs: %{
    optional({non_neg_integer(), non_neg_integer()}) => non_neg_integer()
  },
  gsub_scripts: [String.t()],
  gsub_features: [String.t()],
  gsub_ligatures: %{optional(String.t()) => String.t()},
  gsub_ligatures_all: %{optional(String.t()) => String.t()},
  gsub_substitutions_all: %{optional(String.t()) => String.t()},
  gpos_scripts: [String.t()],
  gpos_features: [String.t()],
  gpos_pair_kerns: %{
    optional({non_neg_integer(), non_neg_integer()}) => integer()
  },
  gpos_guardrail_skips: non_neg_integer(),
  italic: boolean(),
  bold: boolean(),
  italic_angle: float(),
  fixed_pitch: boolean(),
  head_bbox: {integer(), integer(), integer(), integer()} | nil,
  hhea_ascender: integer(),
  hhea_descender: integer(),
  hhea_line_gap: integer(),
  hhea_advance_width_max: non_neg_integer(),
  typo_ascender: integer() | nil,
  typo_descender: integer() | nil,
  typo_line_gap: integer() | nil,
  os2_avg_char_width: integer() | nil,
  x_height: integer() | nil,
  cap_height: integer() | nil,
  os2_weight_class: non_neg_integer() | nil,
  os2_width_class: non_neg_integer() | nil,
  os2_family_class: integer() | nil,
  os2_vendor_id: String.t() | nil,
  os2_version: non_neg_integer() | nil,
  os2_fs_selection: non_neg_integer() | nil,
  os2_fs_type: non_neg_integer() | nil,
  os2_subscript_x_size: integer() | nil,
  os2_subscript_y_size: integer() | nil,
  os2_subscript_x_offset: integer() | nil,
  os2_subscript_y_offset: integer() | nil,
  os2_superscript_x_size: integer() | nil,
  os2_superscript_y_size: integer() | nil,
  os2_superscript_x_offset: integer() | nil,
  os2_superscript_y_offset: integer() | nil,
  os2_strikeout_size: integer() | nil,
  os2_strikeout_position: integer() | nil,
  os2_unicode_ranges:
    {non_neg_integer(), non_neg_integer(), non_neg_integer(), non_neg_integer()}
    | nil,
  os2_code_page_ranges: {non_neg_integer(), non_neg_integer()} | nil,
  os2_first_char_index: non_neg_integer() | nil,
  os2_last_char_index: non_neg_integer() | nil,
  os2_default_char: non_neg_integer() | nil,
  os2_break_char: non_neg_integer() | nil,
  os2_max_context: non_neg_integer() | nil,
  os2_lower_optical_point_size: non_neg_integer() | nil,
  os2_upper_optical_point_size: non_neg_integer() | nil,
  os2_win_ascent: non_neg_integer() | nil,
  os2_win_descent: non_neg_integer() | nil,
  os2_italic: boolean(),
  os2_oblique: boolean(),
  os2_bold: boolean(),
  os2_panose: binary() | nil,
  cff_stem_h: non_neg_integer() | nil,
  cff_stem_v: non_neg_integer() | nil,
  cff_force_bold: boolean() | nil,
  cff_weight_class: non_neg_integer() | nil,
  font_family: String.t() | nil,
  index_to_loc_format: 0 | 1,
  glyph_offsets: [non_neg_integer()],
  glyph_bboxes_by_id: %{
    optional(non_neg_integer()) => {integer(), integer(), integer(), integer()}
  },
  glyph_contour_counts_by_id: %{
    optional(non_neg_integer()) => non_neg_integer()
  },
  glyph_point_counts_by_id: %{optional(non_neg_integer()) => pos_integer()},
  glyph_simple_instruction_lengths_by_id: %{
    optional(non_neg_integer()) => non_neg_integer()
  },
  glyph_composite_instruction_lengths_by_id: %{
    optional(non_neg_integer()) => non_neg_integer()
  },
  glyph_outline_types_by_id: %{
    optional(non_neg_integer()) => :simple | :composite
  },
  glyph_component_counts_by_id: %{
    optional(non_neg_integer()) => non_neg_integer()
  },
  glyph_component_glyph_ids_by_id: %{
    optional(non_neg_integer()) => [non_neg_integer()]
  },
  cff_charstring_count: non_neg_integer(),
  cff_charstring_lengths_by_id: %{
    optional(non_neg_integer()) => non_neg_integer()
  },
  font_bbox: {integer(), integer(), integer(), integer()} | nil
}

Functions

parse_basic_tables(data)

@spec parse_basic_tables(binary()) :: {:ok, basic_metrics()} | :error