Class: Fontisan::OpenTypeCollection
- Inherits:
-
BinData::Record
- Object
- BinData::Record
- Fontisan::OpenTypeCollection
- Defined in:
- lib/fontisan/open_type_collection.rb
Overview
OpenType Collection domain object using BinData
Represents a complete OpenType Collection file (OTC) using BinData’s declarative DSL for binary structure definition. Parallel to TrueTypeCollection but for OpenType fonts.
Class Method Summary collapse
-
.from_file(path) ⇒ OpenTypeCollection
Read OpenType Collection from a file.
Instance Method Summary collapse
-
#collection_info(io, path) ⇒ CollectionInfo
Get comprehensive collection metadata.
-
#extract_fonts(io) ⇒ Array<OpenTypeFont>
Extract fonts as OpenTypeFont objects.
-
#font(index, io, mode: LoadingModes::FULL) ⇒ OpenTypeFont?
Get a single font from the collection.
-
#font_count ⇒ Integer
Get font count.
-
#list_fonts(io) ⇒ CollectionListInfo
List all fonts in the collection with basic metadata.
-
#valid? ⇒ Boolean
Validate format correctness.
-
#version ⇒ Integer
Get the OTC version as a single integer.
Class Method Details
.from_file(path) ⇒ OpenTypeCollection
Read OpenType Collection from a file
34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/fontisan/open_type_collection.rb', line 34 def self.from_file(path) if path.nil? || path.to_s.empty? raise ArgumentError, "path cannot be nil or empty" end raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path) File.open(path, "rb") { |io| read(io) } rescue BinData::ValidityError => e raise "Invalid OTC file: #{e.}" rescue EOFError => e raise "Invalid OTC file: unexpected end of file - #{e.}" end |
Instance Method Details
#collection_info(io, path) ⇒ CollectionInfo
Get comprehensive collection metadata
Returns a CollectionInfo model with header information, offsets, and table sharing statistics. This is the API method used by the ‘info` command for collections.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/fontisan/open_type_collection.rb', line 177 def collection_info(io, path) require_relative "models/collection_info" require_relative "models/table_sharing_info" # Calculate table sharing statistics table_sharing = calculate_table_sharing(io) # Get file size file_size = path ? File.size(path) : 0 Models::CollectionInfo.new( collection_path: path, collection_format: "OTC", ttc_tag: tag, major_version: major_version, minor_version: minor_version, num_fonts: num_fonts, font_offsets: font_offsets.to_a, file_size_bytes: file_size, table_sharing: table_sharing, ) end |
#extract_fonts(io) ⇒ Array<OpenTypeFont>
Extract fonts as OpenTypeFont objects
Reads each font from the OTC file and returns them as OpenTypeFont objects.
54 55 56 57 58 59 60 |
# File 'lib/fontisan/open_type_collection.rb', line 54 def extract_fonts(io) require_relative "open_type_font" font_offsets.map do |offset| OpenTypeFont.from_collection(io, offset) end end |
#font(index, io, mode: LoadingModes::FULL) ⇒ OpenTypeFont?
Get a single font from the collection
68 69 70 71 72 73 |
# File 'lib/fontisan/open_type_collection.rb', line 68 def font(index, io, mode: LoadingModes::FULL) return nil if index >= num_fonts require_relative "open_type_font" OpenTypeFont.from_collection(io, font_offsets[index], mode: mode) end |
#font_count ⇒ Integer
Get font count
78 79 80 |
# File 'lib/fontisan/open_type_collection.rb', line 78 def font_count num_fonts end |
#list_fonts(io) ⇒ CollectionListInfo
List all fonts in the collection with basic metadata
Returns a CollectionListInfo model containing summaries of all fonts. This is the API method used by the ‘ls` command for collections.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/fontisan/open_type_collection.rb', line 112 def list_fonts(io) require_relative "models/collection_list_info" require_relative "models/collection_font_summary" require_relative "open_type_font" require_relative "tables/name" fonts = font_offsets.map.with_index do |offset, index| font = OpenTypeFont.from_collection(io, offset) # Extract basic font info name_table = font.table("name") post_table = font.table("post") family_name = name_table&.english_name(Tables::Name::FAMILY) || "Unknown" subfamily_name = name_table&.english_name(Tables::Name::SUBFAMILY) || "Regular" postscript_name = name_table&.english_name(Tables::Name::POSTSCRIPT_NAME) || "Unknown" # Determine font format sfnt = font.header.sfnt_version font_format = case sfnt when 0x00010000, 0x74727565 # 0x74727565 = 'true' "TrueType" when 0x4F54544F # 'OTTO' "OpenType" else "Unknown" end num_glyphs = post_table&.glyph_names&.length || 0 num_tables = font.table_names.length Models::CollectionFontSummary.new( index: index, family_name: family_name, subfamily_name: subfamily_name, postscript_name: postscript_name, font_format: font_format, num_glyphs: num_glyphs, num_tables: num_tables, ) end Models::CollectionListInfo.new( collection_path: nil, # Will be set by command num_fonts: num_fonts, fonts: fonts, ) end |
#valid? ⇒ Boolean
Validate format correctness
85 86 87 88 89 |
# File 'lib/fontisan/open_type_collection.rb', line 85 def valid? tag == Constants::TTC_TAG && num_fonts.positive? && font_offsets.length == num_fonts rescue StandardError false end |
#version ⇒ Integer
Get the OTC version as a single integer
94 95 96 |
# File 'lib/fontisan/open_type_collection.rb', line 94 def version (major_version << 16) | minor_version end |