Class: Fontisan::MetricsCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/metrics_calculator.rb

Overview

High-level utility class for accessing font metrics

MetricsCalculator provides a convenient API for querying font metrics from multiple OpenType tables without needing to work with the low-level table structures directly. It wraps access to hhea, hmtx, head, maxp, and cmap tables.

The calculator handles missing tables gracefully and provides both individual glyph metrics and string-level calculations.

Examples:

Basic usage

font = FontLoader.from_file("path/to/font.ttf")
calc = MetricsCalculator.new(font)

puts calc.ascent          # => 2048
puts calc.descent         # => -512
puts calc.line_height     # => 2650
puts calc.units_per_em    # => 2048

Glyph metrics

width = calc.glyph_width(42)
lsb = calc.glyph_left_side_bearing(42)

String width calculation

width = calc.string_width("Hello")

Checking for metrics support

if calc.has_metrics?
  puts "Font has complete horizontal metrics"
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(font) ⇒ MetricsCalculator

Initialize a new MetricsCalculator

Parameters:

Raises:

  • (ArgumentError)

    if font is nil



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/fontisan/metrics_calculator.rb', line 44

def initialize(font)
  raise ArgumentError, "Font cannot be nil" if font.nil?

  @font = font
  @hhea_table = nil
  @hmtx_table = nil
  @head_table = nil
  @maxp_table = nil
  @cmap_table = nil
  @hmtx_parsed = false
end

Instance Attribute Details

#fontOpenTypeFont, TrueTypeFont (readonly)

The font object this calculator operates on

Returns:



38
39
40
# File 'lib/fontisan/metrics_calculator.rb', line 38

def font
  @font
end

Instance Method Details

#ascentInteger?

Get typographic ascent from hhea table

The ascent is the distance from the baseline to the highest ascender. It is a positive value in font units (FUnits).

Examples:

calc.ascent # => 2048

Returns:

  • (Integer, nil)

    Ascent value in FUnits, or nil if hhea table is missing



65
66
67
# File 'lib/fontisan/metrics_calculator.rb', line 65

def ascent
  hhea&.ascent
end

#descentInteger?

Get typographic descent from hhea table

The descent is the distance from the baseline to the lowest descender. It is typically a negative value in font units (FUnits).

Examples:

calc.descent # => -512

Returns:

  • (Integer, nil)

    Descent value in FUnits, or nil if hhea table is missing



78
79
80
# File 'lib/fontisan/metrics_calculator.rb', line 78

def descent
  hhea&.descent
end

#glyph_left_side_bearing(glyph_id) ⇒ Integer?

Get left side bearing for a specific glyph

The left side bearing (LSB) is the horizontal distance from the pen position to the leftmost point of the glyph. It can be negative if the glyph extends to the left of the pen position.

Examples:

calc.glyph_left_side_bearing(42) # => 50

Parameters:

  • glyph_id (Integer)

    The glyph ID (0-based)

Returns:

  • (Integer, nil)

    Left side bearing in FUnits, or nil if not available



143
144
145
146
147
148
149
# File 'lib/fontisan/metrics_calculator.rb', line 143

def glyph_left_side_bearing(glyph_id)
  ensure_hmtx_parsed
  return nil unless hmtx

  metric = hmtx.metric_for(glyph_id)
  metric&.dig(:lsb)
end

#glyph_width(glyph_id) ⇒ Integer? Also known as: glyph_advance_width

Get advance width for a specific glyph

The advance width is the horizontal distance to advance the pen position after rendering this glyph. It is in font units (FUnits).

Examples:

calc.glyph_width(42) # => 1234

Parameters:

  • glyph_id (Integer)

    The glyph ID (0-based)

Returns:

  • (Integer, nil)

    Advance width in FUnits, or nil if not available



118
119
120
121
122
123
124
# File 'lib/fontisan/metrics_calculator.rb', line 118

def glyph_width(glyph_id)
  ensure_hmtx_parsed
  return nil unless hmtx

  metric = hmtx.metric_for(glyph_id)
  metric&.dig(:advance_width)
end

#has_metrics?Boolean

Check if font has complete horizontal metrics

Returns true if the font has all required tables for horizontal metrics: hhea, hmtx, head, and maxp tables.

Examples:

calc.has_metrics? # => true

Returns:

  • (Boolean)

    True if all metrics tables are present



209
210
211
# File 'lib/fontisan/metrics_calculator.rb', line 209

def has_metrics?
  !hhea.nil? && !hmtx.nil? && !head.nil? && !maxp.nil?
end

#line_gapInteger?

Get line gap from hhea table

The line gap is additional vertical space between lines of text. It is a non-negative value in font units (FUnits).

Examples:

calc.line_gap # => 90

Returns:

  • (Integer, nil)

    Line gap value in FUnits, or nil if hhea table is missing



91
92
93
# File 'lib/fontisan/metrics_calculator.rb', line 91

def line_gap
  hhea&.line_gap
end

#line_heightInteger?

Calculate line height

Line height is calculated as: ascent - descent + line_gap This represents the recommended spacing between consecutive baselines.

Examples:

calc.line_height # => 2650 (when ascent=2048, descent=-512, line_gap=90)

Returns:

  • (Integer, nil)

    Line height in FUnits, or nil if hhea table is missing



189
190
191
192
193
# File 'lib/fontisan/metrics_calculator.rb', line 189

def line_height
  return nil unless hhea

  ascent - descent + line_gap
end

#string_width(string) ⇒ Integer?

Calculate total width for a string

Calculates the sum of advance widths for all characters in the string. This is a simplified calculation that does not account for kerning, ligatures, or other advanced typography features.

Characters not mapped in the font are skipped.

Examples:

calc.string_width("Hello") # => 5420

Parameters:

  • string (String)

    The string to measure

Returns:

  • (Integer, nil)

    Total width in FUnits, or nil if metrics unavailable



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/fontisan/metrics_calculator.rb', line 164

def string_width(string)
  return nil unless has_metrics?
  return 0 if string.nil? || string.empty?

  total_width = 0
  string.each_codepoint do |codepoint|
    glyph_id = codepoint_to_glyph_id(codepoint)
    next unless glyph_id

    width = glyph_width(glyph_id)
    total_width += width if width
  end

  total_width
end

#units_per_emInteger? Also known as: em_height

Get units per em from head table

This value defines the font's coordinate system scale. Common values are 1000 (PostScript fonts) or 2048 (TrueType fonts).

Examples:

calc.units_per_em # => 2048

Returns:

  • (Integer, nil)

    Units per em value, or nil if head table is missing



104
105
106
# File 'lib/fontisan/metrics_calculator.rb', line 104

def units_per_em
  head&.units_per_em
end