fontisan 0.1.0
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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +217 -0
- data/Gemfile +15 -0
- data/LICENSE +24 -0
- data/README.adoc +984 -0
- data/Rakefile +95 -0
- data/exe/fontisan +7 -0
- data/fontisan.gemspec +44 -0
- data/lib/fontisan/binary/base_record.rb +57 -0
- data/lib/fontisan/binary/structures.rb +84 -0
- data/lib/fontisan/cli.rb +192 -0
- data/lib/fontisan/commands/base_command.rb +82 -0
- data/lib/fontisan/commands/dump_table_command.rb +71 -0
- data/lib/fontisan/commands/features_command.rb +94 -0
- data/lib/fontisan/commands/glyphs_command.rb +50 -0
- data/lib/fontisan/commands/info_command.rb +120 -0
- data/lib/fontisan/commands/optical_size_command.rb +41 -0
- data/lib/fontisan/commands/scripts_command.rb +59 -0
- data/lib/fontisan/commands/tables_command.rb +52 -0
- data/lib/fontisan/commands/unicode_command.rb +76 -0
- data/lib/fontisan/commands/variable_command.rb +61 -0
- data/lib/fontisan/config/features.yml +143 -0
- data/lib/fontisan/config/scripts.yml +42 -0
- data/lib/fontisan/constants.rb +78 -0
- data/lib/fontisan/error.rb +15 -0
- data/lib/fontisan/font_loader.rb +109 -0
- data/lib/fontisan/formatters/text_formatter.rb +314 -0
- data/lib/fontisan/models/all_scripts_features_info.rb +21 -0
- data/lib/fontisan/models/features_info.rb +42 -0
- data/lib/fontisan/models/font_info.rb +99 -0
- data/lib/fontisan/models/glyph_info.rb +26 -0
- data/lib/fontisan/models/optical_size_info.rb +33 -0
- data/lib/fontisan/models/scripts_info.rb +39 -0
- data/lib/fontisan/models/table_info.rb +55 -0
- data/lib/fontisan/models/unicode_mappings.rb +42 -0
- data/lib/fontisan/models/variable_font_info.rb +82 -0
- data/lib/fontisan/open_type_collection.rb +97 -0
- data/lib/fontisan/open_type_font.rb +292 -0
- data/lib/fontisan/parsers/tag.rb +77 -0
- data/lib/fontisan/tables/cmap.rb +284 -0
- data/lib/fontisan/tables/fvar.rb +157 -0
- data/lib/fontisan/tables/gpos.rb +111 -0
- data/lib/fontisan/tables/gsub.rb +111 -0
- data/lib/fontisan/tables/head.rb +114 -0
- data/lib/fontisan/tables/layout_common.rb +73 -0
- data/lib/fontisan/tables/name.rb +188 -0
- data/lib/fontisan/tables/os2.rb +175 -0
- data/lib/fontisan/tables/post.rb +148 -0
- data/lib/fontisan/true_type_collection.rb +98 -0
- data/lib/fontisan/true_type_font.rb +313 -0
- data/lib/fontisan/utilities/checksum_calculator.rb +89 -0
- data/lib/fontisan/version.rb +5 -0
- data/lib/fontisan.rb +80 -0
- metadata +150 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# FontInfo model represents comprehensive font metadata
|
|
8
|
+
# extracted from various font tables (name, head, OS/2, etc.)
|
|
9
|
+
#
|
|
10
|
+
# This model provides a unified interface for accessing font information
|
|
11
|
+
# and supports serialization to YAML and JSON formats through lutaml-model.
|
|
12
|
+
class FontInfo < Lutaml::Model::Serializable
|
|
13
|
+
attribute :font_format, :string
|
|
14
|
+
attribute :is_variable, Lutaml::Model::Type::Boolean
|
|
15
|
+
attribute :family_name, :string
|
|
16
|
+
attribute :subfamily_name, :string
|
|
17
|
+
attribute :full_name, :string
|
|
18
|
+
attribute :postscript_name, :string
|
|
19
|
+
attribute :postscript_cid_name, :string
|
|
20
|
+
attribute :preferred_family, :string
|
|
21
|
+
attribute :preferred_subfamily, :string
|
|
22
|
+
attribute :mac_font_menu_name, :string
|
|
23
|
+
attribute :version, :string
|
|
24
|
+
attribute :unique_id, :string
|
|
25
|
+
attribute :description, :string
|
|
26
|
+
attribute :designer, :string
|
|
27
|
+
attribute :designer_url, :string
|
|
28
|
+
attribute :manufacturer, :string
|
|
29
|
+
attribute :vendor_url, :string
|
|
30
|
+
attribute :vendor_id, :string
|
|
31
|
+
attribute :trademark, :string
|
|
32
|
+
attribute :copyright, :string
|
|
33
|
+
attribute :license_description, :string
|
|
34
|
+
attribute :license_url, :string
|
|
35
|
+
attribute :sample_text, :string
|
|
36
|
+
attribute :font_revision, :float
|
|
37
|
+
attribute :permissions, :string
|
|
38
|
+
attribute :units_per_em, :integer
|
|
39
|
+
|
|
40
|
+
json do
|
|
41
|
+
map "font_format", to: :font_format
|
|
42
|
+
map "is_variable", to: :is_variable
|
|
43
|
+
map "family_name", to: :family_name
|
|
44
|
+
map "subfamily_name", to: :subfamily_name
|
|
45
|
+
map "full_name", to: :full_name
|
|
46
|
+
map "postscript_name", to: :postscript_name
|
|
47
|
+
map "postscript_cid_name", to: :postscript_cid_name
|
|
48
|
+
map "preferred_family", to: :preferred_family
|
|
49
|
+
map "preferred_subfamily", to: :preferred_subfamily
|
|
50
|
+
map "mac_font_menu_name", to: :mac_font_menu_name
|
|
51
|
+
map "version", to: :version
|
|
52
|
+
map "unique_id", to: :unique_id
|
|
53
|
+
map "description", to: :description
|
|
54
|
+
map "designer", to: :designer
|
|
55
|
+
map "designer_url", to: :designer_url
|
|
56
|
+
map "manufacturer", to: :manufacturer
|
|
57
|
+
map "vendor_url", to: :vendor_url
|
|
58
|
+
map "vendor_id", to: :vendor_id
|
|
59
|
+
map "trademark", to: :trademark
|
|
60
|
+
map "copyright", to: :copyright
|
|
61
|
+
map "license_description", to: :license_description
|
|
62
|
+
map "license_url", to: :license_url
|
|
63
|
+
map "sample_text", to: :sample_text
|
|
64
|
+
map "font_revision", to: :font_revision
|
|
65
|
+
map "permissions", to: :permissions
|
|
66
|
+
map "units_per_em", to: :units_per_em
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
yaml do
|
|
70
|
+
map "font_format", to: :font_format
|
|
71
|
+
map "is_variable", to: :is_variable
|
|
72
|
+
map "family_name", to: :family_name
|
|
73
|
+
map "subfamily_name", to: :subfamily_name
|
|
74
|
+
map "full_name", to: :full_name
|
|
75
|
+
map "postscript_name", to: :postscript_name
|
|
76
|
+
map "postscript_cid_name", to: :postscript_cid_name
|
|
77
|
+
map "preferred_family", to: :preferred_family
|
|
78
|
+
map "preferred_subfamily", to: :preferred_subfamily
|
|
79
|
+
map "mac_font_menu_name", to: :mac_font_menu_name
|
|
80
|
+
map "version", to: :version
|
|
81
|
+
map "unique_id", to: :unique_id
|
|
82
|
+
map "description", to: :description
|
|
83
|
+
map "designer", to: :designer
|
|
84
|
+
map "designer_url", to: :designer_url
|
|
85
|
+
map "manufacturer", to: :manufacturer
|
|
86
|
+
map "vendor_url", to: :vendor_url
|
|
87
|
+
map "vendor_id", to: :vendor_id
|
|
88
|
+
map "trademark", to: :trademark
|
|
89
|
+
map "copyright", to: :copyright
|
|
90
|
+
map "license_description", to: :license_description
|
|
91
|
+
map "license_url", to: :license_url
|
|
92
|
+
map "sample_text", to: :sample_text
|
|
93
|
+
map "font_revision", to: :font_revision
|
|
94
|
+
map "permissions", to: :permissions
|
|
95
|
+
map "units_per_em", to: :units_per_em
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# Model for glyph information
|
|
8
|
+
class GlyphInfo < Lutaml::Model::Serializable
|
|
9
|
+
attribute :glyph_count, :integer
|
|
10
|
+
attribute :glyph_names, :string, collection: true
|
|
11
|
+
attribute :source, :string
|
|
12
|
+
|
|
13
|
+
json do
|
|
14
|
+
map "glyph_count", to: :glyph_count
|
|
15
|
+
map "glyph_names", to: :glyph_names
|
|
16
|
+
map "source", to: :source
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
yaml do
|
|
20
|
+
map "glyph_count", to: :glyph_count
|
|
21
|
+
map "glyph_names", to: :glyph_names
|
|
22
|
+
map "source", to: :source
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# OpticalSizeInfo model represents optical size information from a font
|
|
8
|
+
#
|
|
9
|
+
# Optical size information indicates the design size range for which a font
|
|
10
|
+
# is optimized. This can come from the OS/2 table (version 5+) or from the
|
|
11
|
+
# GPOS 'size' feature.
|
|
12
|
+
class OpticalSizeInfo < Lutaml::Model::Serializable
|
|
13
|
+
attribute :has_optical_size, Lutaml::Model::Type::Boolean
|
|
14
|
+
attribute :source, :string
|
|
15
|
+
attribute :lower_point_size, :float
|
|
16
|
+
attribute :upper_point_size, :float
|
|
17
|
+
|
|
18
|
+
json do
|
|
19
|
+
map "has_optical_size", to: :has_optical_size
|
|
20
|
+
map "source", to: :source
|
|
21
|
+
map "lower_point_size", to: :lower_point_size
|
|
22
|
+
map "upper_point_size", to: :upper_point_size
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
yaml do
|
|
26
|
+
map "has_optical_size", to: :has_optical_size
|
|
27
|
+
map "source", to: :source
|
|
28
|
+
map "lower_point_size", to: :lower_point_size
|
|
29
|
+
map "upper_point_size", to: :upper_point_size
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# Represents a single script record
|
|
8
|
+
class ScriptRecord < Lutaml::Model::Serializable
|
|
9
|
+
attribute :tag, :string
|
|
10
|
+
attribute :description, :string
|
|
11
|
+
|
|
12
|
+
json do
|
|
13
|
+
map "tag", to: :tag
|
|
14
|
+
map "description", to: :description
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
yaml do
|
|
18
|
+
map "tag", to: :tag
|
|
19
|
+
map "description", to: :description
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Represents scripts information from GSUB/GPOS tables
|
|
24
|
+
class ScriptsInfo < Lutaml::Model::Serializable
|
|
25
|
+
attribute :script_count, :integer
|
|
26
|
+
attribute :scripts, ScriptRecord, collection: true
|
|
27
|
+
|
|
28
|
+
json do
|
|
29
|
+
map "script_count", to: :script_count
|
|
30
|
+
map "scripts", to: :scripts
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
yaml do
|
|
34
|
+
map "script_count", to: :script_count
|
|
35
|
+
map "scripts", to: :scripts
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# TableEntry represents a single table directory entry in a font file
|
|
8
|
+
#
|
|
9
|
+
# Each entry contains metadata about a font table including its tag,
|
|
10
|
+
# length, offset within the file, and checksum for validation.
|
|
11
|
+
class TableEntry < Lutaml::Model::Serializable
|
|
12
|
+
attribute :tag, :string
|
|
13
|
+
attribute :length, :integer
|
|
14
|
+
attribute :offset, :integer
|
|
15
|
+
attribute :checksum, :integer
|
|
16
|
+
|
|
17
|
+
json do
|
|
18
|
+
map "tag", to: :tag
|
|
19
|
+
map "length", to: :length
|
|
20
|
+
map "offset", to: :offset
|
|
21
|
+
map "checksum", to: :checksum
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
yaml do
|
|
25
|
+
map "tag", to: :tag
|
|
26
|
+
map "length", to: :length
|
|
27
|
+
map "offset", to: :offset
|
|
28
|
+
map "checksum", to: :checksum
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# TableInfo represents the table directory information from a font file
|
|
33
|
+
#
|
|
34
|
+
# This model contains the SFNT version identifier, the number of tables,
|
|
35
|
+
# and a collection of TableEntry objects representing each table in the font.
|
|
36
|
+
# It supports serialization to YAML and JSON formats through lutaml-model.
|
|
37
|
+
class TableInfo < Lutaml::Model::Serializable
|
|
38
|
+
attribute :sfnt_version, :string
|
|
39
|
+
attribute :num_tables, :integer
|
|
40
|
+
attribute :tables, TableEntry, collection: true
|
|
41
|
+
|
|
42
|
+
json do
|
|
43
|
+
map "sfnt_version", to: :sfnt_version
|
|
44
|
+
map "num_tables", to: :num_tables
|
|
45
|
+
map "tables", to: :tables
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
yaml do
|
|
49
|
+
map "sfnt_version", to: :sfnt_version
|
|
50
|
+
map "num_tables", to: :num_tables
|
|
51
|
+
map "tables", to: :tables
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# Model for a single Unicode to glyph mapping
|
|
8
|
+
class UnicodeMapping < Lutaml::Model::Serializable
|
|
9
|
+
attribute :codepoint, :string
|
|
10
|
+
attribute :glyph_index, :integer
|
|
11
|
+
attribute :glyph_name, :string
|
|
12
|
+
|
|
13
|
+
json do
|
|
14
|
+
map "codepoint", to: :codepoint
|
|
15
|
+
map "glyph_index", to: :glyph_index
|
|
16
|
+
map "glyph_name", to: :glyph_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
yaml do
|
|
20
|
+
map "codepoint", to: :codepoint
|
|
21
|
+
map "glyph_index", to: :glyph_index
|
|
22
|
+
map "glyph_name", to: :glyph_name
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Model for collection of Unicode mappings
|
|
27
|
+
class UnicodeMappings < Lutaml::Model::Serializable
|
|
28
|
+
attribute :count, :integer
|
|
29
|
+
attribute :mappings, UnicodeMapping, collection: true
|
|
30
|
+
|
|
31
|
+
json do
|
|
32
|
+
map "count", to: :count
|
|
33
|
+
map "mappings", to: :mappings
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
yaml do
|
|
37
|
+
map "count", to: :count
|
|
38
|
+
map "mappings", to: :mappings
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# AxisInfo model represents a single variation axis in a variable font
|
|
8
|
+
#
|
|
9
|
+
# Each axis defines a design dimension along which the font can vary,
|
|
10
|
+
# such as weight (wght), width (wdth), italic (ital), or slant (slnt).
|
|
11
|
+
class AxisInfo < Lutaml::Model::Serializable
|
|
12
|
+
attribute :tag, :string
|
|
13
|
+
attribute :name, :string
|
|
14
|
+
attribute :min_value, :float
|
|
15
|
+
attribute :default_value, :float
|
|
16
|
+
attribute :max_value, :float
|
|
17
|
+
|
|
18
|
+
json do
|
|
19
|
+
map "tag", to: :tag
|
|
20
|
+
map "name", to: :name
|
|
21
|
+
map "min_value", to: :min_value
|
|
22
|
+
map "default_value", to: :default_value
|
|
23
|
+
map "max_value", to: :max_value
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
yaml do
|
|
27
|
+
map "tag", to: :tag
|
|
28
|
+
map "name", to: :name
|
|
29
|
+
map "min_value", to: :min_value
|
|
30
|
+
map "default_value", to: :default_value
|
|
31
|
+
map "max_value", to: :max_value
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# InstanceInfo model represents a named instance in a variable font
|
|
36
|
+
#
|
|
37
|
+
# Each instance defines a predefined combination of axis values,
|
|
38
|
+
# representing a named style/weight/width combination.
|
|
39
|
+
class InstanceInfo < Lutaml::Model::Serializable
|
|
40
|
+
attribute :name, :string
|
|
41
|
+
attribute :coordinates, :float, collection: true
|
|
42
|
+
|
|
43
|
+
json do
|
|
44
|
+
map "name", to: :name
|
|
45
|
+
map "coordinates", to: :coordinates
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
yaml do
|
|
49
|
+
map "name", to: :name
|
|
50
|
+
map "coordinates", to: :coordinates
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# VariableFontInfo model represents comprehensive variable font metadata
|
|
55
|
+
#
|
|
56
|
+
# This model provides information about variation axes and named instances
|
|
57
|
+
# for variable fonts (OpenType Font Variations).
|
|
58
|
+
class VariableFontInfo < Lutaml::Model::Serializable
|
|
59
|
+
attribute :is_variable, Lutaml::Model::Type::Boolean
|
|
60
|
+
attribute :axis_count, :integer
|
|
61
|
+
attribute :instance_count, :integer
|
|
62
|
+
attribute :axes, AxisInfo, collection: true
|
|
63
|
+
attribute :instances, InstanceInfo, collection: true
|
|
64
|
+
|
|
65
|
+
json do
|
|
66
|
+
map "is_variable", to: :is_variable
|
|
67
|
+
map "axis_count", to: :axis_count
|
|
68
|
+
map "instance_count", to: :instance_count
|
|
69
|
+
map "axes", to: :axes
|
|
70
|
+
map "instances", to: :instances
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
yaml do
|
|
74
|
+
map "is_variable", to: :is_variable
|
|
75
|
+
map "axis_count", to: :axis_count
|
|
76
|
+
map "instance_count", to: :instance_count
|
|
77
|
+
map "axes", to: :axes
|
|
78
|
+
map "instances", to: :instances
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bindata"
|
|
4
|
+
require_relative "constants"
|
|
5
|
+
|
|
6
|
+
module Fontisan
|
|
7
|
+
# OpenType Collection domain object using BinData
|
|
8
|
+
#
|
|
9
|
+
# Represents a complete OpenType Collection file (OTC) using BinData's declarative
|
|
10
|
+
# DSL for binary structure definition. Parallel to TrueTypeCollection but for OpenType fonts.
|
|
11
|
+
#
|
|
12
|
+
# @example Reading and extracting fonts
|
|
13
|
+
# File.open("fonts.otc", "rb") do |io|
|
|
14
|
+
# otc = OpenTypeCollection.read(io)
|
|
15
|
+
# puts otc.num_fonts # => 4
|
|
16
|
+
# fonts = otc.extract_fonts(io) # => [OpenTypeFont, OpenTypeFont, ...]
|
|
17
|
+
# end
|
|
18
|
+
class OpenTypeCollection < BinData::Record
|
|
19
|
+
endian :big
|
|
20
|
+
|
|
21
|
+
string :tag, length: 4, assert: "ttcf"
|
|
22
|
+
uint16 :major_version
|
|
23
|
+
uint16 :minor_version
|
|
24
|
+
uint32 :num_fonts
|
|
25
|
+
array :font_offsets, type: :uint32, initial_length: :num_fonts
|
|
26
|
+
|
|
27
|
+
# Read OpenType Collection from a file
|
|
28
|
+
#
|
|
29
|
+
# @param path [String] Path to the OTC file
|
|
30
|
+
# @return [OpenTypeCollection] A new instance
|
|
31
|
+
# @raise [ArgumentError] if path is nil or empty
|
|
32
|
+
# @raise [Errno::ENOENT] if file does not exist
|
|
33
|
+
# @raise [RuntimeError] if file format is invalid
|
|
34
|
+
def self.from_file(path)
|
|
35
|
+
if path.nil? || path.to_s.empty?
|
|
36
|
+
raise ArgumentError,
|
|
37
|
+
"path cannot be nil or empty"
|
|
38
|
+
end
|
|
39
|
+
raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
|
|
40
|
+
|
|
41
|
+
File.open(path, "rb") { |io| read(io) }
|
|
42
|
+
rescue BinData::ValidityError => e
|
|
43
|
+
raise "Invalid OTC file: #{e.message}"
|
|
44
|
+
rescue EOFError => e
|
|
45
|
+
raise "Invalid OTC file: unexpected end of file - #{e.message}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Extract fonts as OpenTypeFont objects
|
|
49
|
+
#
|
|
50
|
+
# Reads each font from the OTC file and returns them as OpenTypeFont objects.
|
|
51
|
+
#
|
|
52
|
+
# @param io [IO] Open file handle to read fonts from
|
|
53
|
+
# @return [Array<OpenTypeFont>] Array of font objects
|
|
54
|
+
def extract_fonts(io)
|
|
55
|
+
require_relative "open_type_font"
|
|
56
|
+
|
|
57
|
+
font_offsets.map do |offset|
|
|
58
|
+
OpenTypeFont.from_collection(io, offset)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Get a single font from the collection
|
|
63
|
+
#
|
|
64
|
+
# @param index [Integer] Index of the font (0-based)
|
|
65
|
+
# @param io [IO] Open file handle
|
|
66
|
+
# @return [OpenTypeFont, nil] Font object or nil if index out of range
|
|
67
|
+
def font(index, io)
|
|
68
|
+
return nil if index >= num_fonts
|
|
69
|
+
|
|
70
|
+
require_relative "open_type_font"
|
|
71
|
+
OpenTypeFont.from_collection(io, font_offsets[index])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Get font count
|
|
75
|
+
#
|
|
76
|
+
# @return [Integer] Number of fonts in collection
|
|
77
|
+
def font_count
|
|
78
|
+
num_fonts
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Validate format correctness
|
|
82
|
+
#
|
|
83
|
+
# @return [Boolean] true if the format is valid, false otherwise
|
|
84
|
+
def valid?
|
|
85
|
+
tag == Constants::TTC_TAG && num_fonts.positive? && font_offsets.length == num_fonts
|
|
86
|
+
rescue StandardError
|
|
87
|
+
false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Get the OTC version as a single integer
|
|
91
|
+
#
|
|
92
|
+
# @return [Integer] Version number (e.g., 0x00010000 for version 1.0)
|
|
93
|
+
def version
|
|
94
|
+
(major_version << 16) | minor_version
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|