Class: Arrolio::FontMetrics::TrueTypeMetrics

Inherits:
Object
  • Object
show all
Defined in:
lib/arrolio/font_metrics/true_type_metrics.rb

Overview

Glyph-width lookup from a TrueType/OpenType font file. Reads head, hhea, hmtx, cmap, OS/2 tables via Fontisan. Same interface as AfmMetrics so callers can swap freely.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(font_name, fontisan_font) ⇒ TrueTypeMetrics

Returns a new instance of TrueTypeMetrics.



13
14
15
16
17
18
19
20
21
22
23
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 13

def initialize(font_name, fontisan_font)
  @font_name = font_name.to_s
  @fontisan_font = fontisan_font
  @cmap = fontisan_font.table('cmap')
  @unicode_to_gid = @cmap ? @cmap.unicode_mappings.transform_keys(&:to_i) : {}
  @head = fontisan_font.table('head')
  @hhea = fontisan_font.table('hhea')
  @os2 = fontisan_font.table('OS/2')
  @hmtx = fontisan_font.table('hmtx')
  parse_hmtx
end

Instance Attribute Details

#font_nameObject (readonly)

Returns the value of attribute font_name.



11
12
13
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 11

def font_name
  @font_name
end

#fontisan_fontObject (readonly)

Returns the value of attribute fontisan_font.



11
12
13
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 11

def fontisan_font
  @fontisan_font
end

Class Method Details

.from_file(font_name, path) ⇒ Object



38
39
40
41
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 38

def self.from_file(font_name, path)
  font = Fontisan::FontLoader.load(path)
  new(font_name, font)
end

Instance Method Details

#advance_width(char) ⇒ Object



49
50
51
52
53
54
55
56
57
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 49

def advance_width(char)
  gid = @unicode_to_gid[char.ord]
  return 0 unless gid && @hmtx

  metric = @hmtx.metric_for(gid)
  metric ? metric[:advance_width] : 0
rescue StandardError
  0
end

#ascender(font_size: 12) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 64

def ascender(font_size: 12)
  return font_size * 0.8 unless @hhea

  ((@hhea.ascender || 800).to_f / units_per_em) * font_size.to_f
rescue StandardError
  font_size * 0.8
end

#cap_height(font_size: 12) ⇒ Object



80
81
82
83
84
85
86
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 80

def cap_height(font_size: 12)
  return font_size * 0.7 unless @os2

  ((@os2.cap_height || 700).to_f / units_per_em) * font_size.to_f
rescue StandardError
  font_size * 0.7
end

#descender(font_size: 12) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 72

def descender(font_size: 12)
  return -font_size * 0.2 unless @hhea

  ((@hhea.descender || -200).to_f / units_per_em) * font_size.to_f
rescue StandardError
  -font_size * 0.2
end

#line_height(font_size:, line_spacing: 1.2) ⇒ Object



88
89
90
91
92
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 88

def line_height(font_size:, line_spacing: 1.2)
  # CSS/XSL convention: line-height is a multiplier of font-size,
  # NOT derived from the font ascender/descender ratio.
  font_size.to_f * line_spacing.to_f
end

#parse_hmtxObject



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 25

def parse_hmtx
  return unless @hmtx && @hhea

  maxp = @fontisan_font.table('maxp')
  num_metrics = @hhea.number_of_h_metrics rescue nil
  num_glyphs = maxp&.num_glyphs
  return unless num_metrics && num_glyphs

  @hmtx.parse_with_context(num_metrics, num_glyphs)
rescue StandardError
  nil
end

#units_per_emObject



43
44
45
46
47
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 43

def units_per_em
  @head ? @head.units_per_em : 1000
rescue StandardError
  1000
end

#width_of_string(str, font_size:) ⇒ Object



59
60
61
62
# File 'lib/arrolio/font_metrics/true_type_metrics.rb', line 59

def width_of_string(str, font_size:)
  scale = font_size.to_f / units_per_em
  str.each_char.sum { |c| advance_width(c) * scale }
end