Class: Fontisan::Collection::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/collection/reader.rb,
lib/fontisan/collection/reader/stats.rb

Overview

Read-only counterpart to Builder. Opens an existing TTC/OTC/dfont and exposes per-face metadata (glyph count, codepoint count, sfnt version) and the cmap union across all faces.

Delegates header parsing to FontLoader — never hand-rolls the TTC header bytes (that would duplicate BaseCollection.from_file and only handle TTC/OTC, not dfont).

Examples:

Per-face glyph counts

reader = Collection::Reader.open("family.ttc")
reader.stats.map { |s| [s.index, s.glyph_count] }

Cmap union

Collection::Reader.open("family.otc").cmap_union.size

Defined Under Namespace

Classes: Stats

Constant Summary collapse

FORMATS =

Collection formats this reader accepts. Single source of truth — matches FontLoader::COLLECTION_CLASSES.

%i[ttc otc dfont].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Reader

Returns a new instance of Reader.

Parameters:

  • path (String)

    path to a TTC/OTC/dfont file

Raises:

  • (ArgumentError)

    if the file is not a recognized collection



32
33
34
35
36
37
38
39
40
41
# File 'lib/fontisan/collection/reader.rb', line 32

def initialize(path)
  @path = path
  detected = FontLoader.detect_format(path)
  unless FORMATS.include?(detected)
    raise ArgumentError,
          "#{path} is not a TTC/OTC/dfont (detected: #{detected.inspect})"
  end

  @collection = FontLoader.load_collection(path)
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



24
25
26
# File 'lib/fontisan/collection/reader.rb', line 24

def path
  @path
end

Class Method Details

.open(path) ⇒ Reader

Convenience constructor.

Parameters:

  • path (String)

Returns:



46
47
48
# File 'lib/fontisan/collection/reader.rb', line 46

def self.open(path)
  new(path)
end

Instance Method Details

#cmap_unionSet<Integer>

Union of every face's cmap keys.

Returns:

  • (Set<Integer>)


83
84
85
86
87
# File 'lib/fontisan/collection/reader.rb', line 83

def cmap_union
  each_face.with_object(Set.new) do |face, union|
    union.merge((face.table("cmap")&.unicode_mappings || {}).keys)
  end
end

#each_face {|face| ... } ⇒ Enumerator, void

Yields each face as a loaded TTF/OTF font. Without a block, returns an Enumerator (so callers can chain each_with_index). The Enumerator's size is set to face_count so size-based assertions work without consuming it.

Yield Parameters:

Returns:

  • (Enumerator, void)


62
63
64
65
66
# File 'lib/fontisan/collection/reader.rb', line 62

def each_face
  return enum_for(:each_face) { face_count } unless block_given?

  face_count.times { |i| yield FontLoader.load(@path, font_index: i) }
end

#face_countInteger

Returns number of faces in the collection.

Returns:

  • (Integer)

    number of faces in the collection



51
52
53
# File 'lib/fontisan/collection/reader.rb', line 51

def face_count
  @collection.num_fonts
end

#statsArray<Stats>

Returns one Stats per face, in face-index order.

Returns:

  • (Array<Stats>)

    one Stats per face, in face-index order



69
70
71
72
73
74
75
76
77
78
# File 'lib/fontisan/collection/reader.rb', line 69

def stats
  each_face.map.with_index do |face, i|
    Stats.new(
      index: i,
      glyph_count: face.table("maxp")&.num_glyphs || 0,
      codepoint_count: (face.table("cmap")&.unicode_mappings || {}).size,
      sfnt_version: face.header.sfnt_version,
    )
  end
end