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



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

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:



40
41
42
# File 'lib/fontisan/metrics_calculator.rb', line 40

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



67
68
69
# File 'lib/fontisan/metrics_calculator.rb', line 67

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



80
81
82
# File 'lib/fontisan/metrics_calculator.rb', line 80

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



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

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



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

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



211
212
213
# File 'lib/fontisan/metrics_calculator.rb', line 211

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



93
94
95
# File 'lib/fontisan/metrics_calculator.rb', line 93

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



191
192
193
194
195
# File 'lib/fontisan/metrics_calculator.rb', line 191

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



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

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



106
107
108
# File 'lib/fontisan/metrics_calculator.rb', line 106

def units_per_em
  head&.units_per_em
end