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:
Tincture.Font.TTF.Cmap— codepoint to glyph mappingTincture.Font.TTF.Glyf— outlines and thelocaoffset tableTincture.Font.TTF.Name— family and style namesTincture.Font.CFF— PostScript outlines, for OpenType/CFF fontsTincture.Font.OpenType.GPOSand.GSUB— kerning and ligatures
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
@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
@spec parse_basic_tables(binary()) :: {:ok, basic_metrics()} | :error