fontisan 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bindata"
4
- require_relative "constants"
3
+ require_relative "base_collection"
5
4
 
6
5
  module Fontisan
7
- # TrueType Collection domain object using BinData
6
+ # TrueType Collection domain object
8
7
  #
9
- # Represents a complete TrueType Collection file using BinData's declarative
10
- # DSL for binary structure definition. The structure definition IS the
11
- # documentation, and BinData handles all low-level reading/writing.
8
+ # Represents a complete TrueType Collection file. Inherits all shared
9
+ # functionality from BaseCollection and implements TTC-specific behavior.
12
10
  #
13
11
  # @example Reading and extracting fonts
14
12
  # File.open("Helvetica.ttc", "rb") do |io|
@@ -16,51 +14,25 @@ module Fontisan
16
14
  # puts ttc.num_fonts # => 6
17
15
  # fonts = ttc.extract_fonts(io) # => [TrueTypeFont, TrueTypeFont, ...]
18
16
  # end
19
- class TrueTypeCollection < BinData::Record
20
- endian :big
21
-
22
- string :tag, length: 4, assert: "ttcf"
23
- uint16 :major_version
24
- uint16 :minor_version
25
- uint32 :num_fonts
26
- array :font_offsets, type: :uint32, initial_length: :num_fonts
27
-
28
- # Read TrueType Collection from a file
17
+ class TrueTypeCollection < BaseCollection
18
+ # Get the font class for TrueType collections
29
19
  #
30
- # @param path [String] Path to the TTC file
31
- # @return [TrueTypeCollection] A new instance
32
- # @raise [ArgumentError] if path is nil or empty
33
- # @raise [Errno::ENOENT] if file does not exist
34
- # @raise [RuntimeError] if file format is invalid
35
- def self.from_file(path)
36
- if path.nil? || path.to_s.empty?
37
- raise ArgumentError,
38
- "path cannot be nil or empty"
39
- end
40
- raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
41
-
42
- File.open(path, "rb") { |io| read(io) }
43
- rescue BinData::ValidityError => e
44
- raise "Invalid TTC file: #{e.message}"
45
- rescue EOFError => e
46
- raise "Invalid TTC file: unexpected end of file - #{e.message}"
20
+ # @return [Class] TrueTypeFont class
21
+ def self.font_class
22
+ require_relative "true_type_font"
23
+ TrueTypeFont
47
24
  end
48
25
 
49
- # Extract fonts as TrueTypeFont objects
26
+ # Get the collection format identifier
50
27
  #
51
- # Reads each font from the TTC file and returns them as TrueTypeFont objects.
52
- #
53
- # @param io [IO] Open file handle to read fonts from
54
- # @return [Array<TrueTypeFont>] Array of font objects
55
- def extract_fonts(io)
56
- require_relative "true_type_font"
57
-
58
- font_offsets.map do |offset|
59
- TrueTypeFont.from_ttc(io, offset)
60
- end
28
+ # @return [String] "TTC" for TrueType Collection
29
+ def self.collection_format
30
+ "TTC"
61
31
  end
62
32
 
63
- # Get a single font from the collection (Fontisan extension)
33
+ # Get a single font from the collection
34
+ #
35
+ # Overrides BaseCollection to use TrueType-specific from_ttc method.
64
36
  #
65
37
  # @param index [Integer] Index of the font (0-based)
66
38
  # @param io [IO] Open file handle
@@ -73,43 +45,27 @@ module Fontisan
73
45
  TrueTypeFont.from_ttc(io, font_offsets[index], mode: mode)
74
46
  end
75
47
 
76
- # Get font count (Fontisan extension)
48
+ # Extract fonts as TrueTypeFont objects
77
49
  #
78
- # @return [Integer] Number of fonts in collection
79
- def font_count
80
- num_fonts
81
- end
82
-
83
- # Validate format correctness
50
+ # Reads each font from the TTC file and returns them as TrueTypeFont objects.
51
+ # This method uses the TTC-specific from_ttc method.
84
52
  #
85
- # @return [Boolean] true if the format is valid, false otherwise
86
- def valid?
87
- tag == Constants::TTC_TAG && num_fonts.positive? && font_offsets.length == num_fonts
88
- rescue StandardError
89
- false
90
- end
53
+ # @param io [IO] Open file handle to read fonts from
54
+ # @return [Array<TrueTypeFont>] Array of font objects
55
+ def extract_fonts(io)
56
+ require_relative "true_type_font"
91
57
 
92
- # Get the TTC version as a single integer
93
- #
94
- # @return [Integer] Version number (e.g., 0x00010000 for version 1.0)
95
- def version
96
- (major_version << 16) | minor_version
58
+ font_offsets.map do |offset|
59
+ TrueTypeFont.from_ttc(io, offset)
60
+ end
97
61
  end
98
62
 
99
63
  # List all fonts in the collection with basic metadata
100
64
  #
101
- # Returns a CollectionListInfo model containing summaries of all fonts.
102
- # This is the API method used by the `ls` command for collections.
65
+ # Overrides BaseCollection to use TrueType-specific from_ttc method.
103
66
  #
104
67
  # @param io [IO] Open file handle to read fonts from
105
68
  # @return [CollectionListInfo] List of fonts with metadata
106
- #
107
- # @example List fonts in collection
108
- # File.open("fonts.ttc", "rb") do |io|
109
- # ttc = TrueTypeCollection.read(io)
110
- # list = ttc.list_fonts(io)
111
- # list.fonts.each { |f| puts "#{f.index}: #{f.family_name}" }
112
- # end
113
69
  def list_fonts(io)
114
70
  require_relative "models/collection_list_info"
115
71
  require_relative "models/collection_font_summary"
@@ -159,51 +115,11 @@ module Fontisan
159
115
  )
160
116
  end
161
117
 
162
- # Get comprehensive collection metadata
163
- #
164
- # Returns a CollectionInfo model with header information, offsets,
165
- # and table sharing statistics.
166
- # This is the API method used by the `info` command for collections.
167
- #
168
- # @param io [IO] Open file handle to read fonts from
169
- # @param path [String] Collection file path (for file size)
170
- # @return [CollectionInfo] Collection metadata
171
- #
172
- # @example Get collection info
173
- # File.open("fonts.ttc", "rb") do |io|
174
- # ttc = TrueTypeCollection.read(io)
175
- # info = ttc.collection_info(io, "fonts.ttc")
176
- # puts "Version: #{info.version_string}"
177
- # end
178
- def collection_info(io, path)
179
- require_relative "models/collection_info"
180
- require_relative "models/table_sharing_info"
181
-
182
- # Calculate table sharing statistics
183
- table_sharing = calculate_table_sharing(io)
184
-
185
- # Get file size
186
- file_size = path ? File.size(path) : 0
187
-
188
- Models::CollectionInfo.new(
189
- collection_path: path,
190
- collection_format: "TTC",
191
- ttc_tag: tag,
192
- major_version: major_version,
193
- minor_version: minor_version,
194
- num_fonts: num_fonts,
195
- font_offsets: font_offsets.to_a,
196
- file_size_bytes: file_size,
197
- table_sharing: table_sharing,
198
- )
199
- end
200
-
201
118
  private
202
119
 
203
120
  # Calculate table sharing statistics
204
121
  #
205
- # Analyzes which tables are shared between fonts and calculates
206
- # space savings from deduplication.
122
+ # Overrides BaseCollection to use TrueType-specific from_ttc method.
207
123
  #
208
124
  # @param io [IO] Open file handle
209
125
  # @return [TableSharingInfo] Sharing statistics
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fontisan
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontisan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -122,6 +122,7 @@ files:
122
122
  - exe/fontisan
123
123
  - fontisan.gemspec
124
124
  - lib/fontisan.rb
125
+ - lib/fontisan/base_collection.rb
125
126
  - lib/fontisan/binary/base_record.rb
126
127
  - lib/fontisan/binary/structures.rb
127
128
  - lib/fontisan/cli.rb