fontisan 0.2.2 → 0.2.4
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 +4 -4
- data/.rubocop_todo.yml +94 -48
- data/README.adoc +293 -3
- data/Rakefile +20 -7
- data/lib/fontisan/base_collection.rb +296 -0
- data/lib/fontisan/commands/base_command.rb +2 -19
- data/lib/fontisan/commands/convert_command.rb +16 -13
- data/lib/fontisan/commands/info_command.rb +156 -50
- data/lib/fontisan/config/conversion_matrix.yml +58 -20
- data/lib/fontisan/converters/outline_converter.rb +6 -3
- data/lib/fontisan/converters/svg_generator.rb +45 -0
- data/lib/fontisan/converters/woff2_encoder.rb +106 -13
- data/lib/fontisan/font_loader.rb +109 -26
- data/lib/fontisan/formatters/text_formatter.rb +72 -19
- data/lib/fontisan/models/bitmap_glyph.rb +123 -0
- data/lib/fontisan/models/bitmap_strike.rb +94 -0
- data/lib/fontisan/models/collection_brief_info.rb +6 -0
- data/lib/fontisan/models/collection_info.rb +6 -1
- data/lib/fontisan/models/color_glyph.rb +57 -0
- data/lib/fontisan/models/color_layer.rb +53 -0
- data/lib/fontisan/models/color_palette.rb +60 -0
- data/lib/fontisan/models/font_info.rb +26 -0
- data/lib/fontisan/models/svg_glyph.rb +89 -0
- data/lib/fontisan/open_type_collection.rb +17 -220
- data/lib/fontisan/open_type_font.rb +6 -0
- data/lib/fontisan/optimizers/charstring_rewriter.rb +19 -8
- data/lib/fontisan/optimizers/pattern_analyzer.rb +4 -2
- data/lib/fontisan/optimizers/subroutine_builder.rb +6 -5
- data/lib/fontisan/optimizers/subroutine_optimizer.rb +5 -2
- data/lib/fontisan/pipeline/output_writer.rb +2 -2
- data/lib/fontisan/tables/cbdt.rb +169 -0
- data/lib/fontisan/tables/cblc.rb +290 -0
- data/lib/fontisan/tables/cff.rb +6 -12
- data/lib/fontisan/tables/colr.rb +291 -0
- data/lib/fontisan/tables/cpal.rb +281 -0
- data/lib/fontisan/tables/glyf/glyph_builder.rb +5 -1
- data/lib/fontisan/tables/sbix.rb +379 -0
- data/lib/fontisan/tables/svg.rb +301 -0
- data/lib/fontisan/true_type_collection.rb +29 -113
- data/lib/fontisan/true_type_font.rb +6 -0
- data/lib/fontisan/validation/woff2_header_validator.rb +278 -0
- data/lib/fontisan/validation/woff2_table_validator.rb +270 -0
- data/lib/fontisan/validation/woff2_validator.rb +248 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/woff2/directory.rb +40 -11
- data/lib/fontisan/woff2/table_transformer.rb +506 -73
- data/lib/fontisan/woff2_font.rb +29 -9
- data/lib/fontisan/woff_font.rb +17 -4
- data/lib/fontisan.rb +12 -0
- metadata +18 -2
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# Bitmap strike representation model
|
|
8
|
+
#
|
|
9
|
+
# Represents a bitmap strike (size) from the CBLC table. Each strike contains
|
|
10
|
+
# bitmap glyphs at a specific ppem (pixels per em) size.
|
|
11
|
+
#
|
|
12
|
+
# This model uses lutaml-model for structured serialization to YAML/JSON/XML.
|
|
13
|
+
#
|
|
14
|
+
# @example Creating a bitmap strike
|
|
15
|
+
# strike = BitmapStrike.new
|
|
16
|
+
# strike.ppem = 16
|
|
17
|
+
# strike.start_glyph_id = 10
|
|
18
|
+
# strike.end_glyph_id = 100
|
|
19
|
+
# strike.bit_depth = 32
|
|
20
|
+
#
|
|
21
|
+
# @example Serializing to JSON
|
|
22
|
+
# json = strike.to_json
|
|
23
|
+
# # {
|
|
24
|
+
# # "ppem": 16,
|
|
25
|
+
# # "start_glyph_id": 10,
|
|
26
|
+
# # "end_glyph_id": 100,
|
|
27
|
+
# # "bit_depth": 32
|
|
28
|
+
# # }
|
|
29
|
+
class BitmapStrike < Lutaml::Model::Serializable
|
|
30
|
+
# @!attribute ppem
|
|
31
|
+
# @return [Integer] Pixels per em (square pixels)
|
|
32
|
+
attribute :ppem, :integer
|
|
33
|
+
|
|
34
|
+
# @!attribute start_glyph_id
|
|
35
|
+
# @return [Integer] First glyph ID in this strike
|
|
36
|
+
attribute :start_glyph_id, :integer
|
|
37
|
+
|
|
38
|
+
# @!attribute end_glyph_id
|
|
39
|
+
# @return [Integer] Last glyph ID in this strike
|
|
40
|
+
attribute :end_glyph_id, :integer
|
|
41
|
+
|
|
42
|
+
# @!attribute bit_depth
|
|
43
|
+
# @return [Integer] Bit depth (1, 2, 4, 8, or 32)
|
|
44
|
+
attribute :bit_depth, :integer
|
|
45
|
+
|
|
46
|
+
# @!attribute num_glyphs
|
|
47
|
+
# @return [Integer] Number of glyphs in this strike
|
|
48
|
+
attribute :num_glyphs, :integer
|
|
49
|
+
|
|
50
|
+
# Get glyph IDs covered by this strike
|
|
51
|
+
#
|
|
52
|
+
# @return [Range] Range of glyph IDs
|
|
53
|
+
def glyph_range
|
|
54
|
+
start_glyph_id..end_glyph_id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Check if this strike covers a specific glyph ID
|
|
58
|
+
#
|
|
59
|
+
# @param glyph_id [Integer] Glyph ID to check
|
|
60
|
+
# @return [Boolean] True if glyph is in range
|
|
61
|
+
def includes_glyph?(glyph_id)
|
|
62
|
+
glyph_range.include?(glyph_id)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Get the color depth description
|
|
66
|
+
#
|
|
67
|
+
# @return [String] Human-readable color depth
|
|
68
|
+
def color_depth
|
|
69
|
+
case bit_depth
|
|
70
|
+
when 1 then "1-bit (monochrome)"
|
|
71
|
+
when 2 then "2-bit (4 colors)"
|
|
72
|
+
when 4 then "4-bit (16 colors)"
|
|
73
|
+
when 8 then "8-bit (256 colors)"
|
|
74
|
+
when 32 then "32-bit (full color with alpha)"
|
|
75
|
+
else "#{bit_depth}-bit"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Check if this is a color strike (32-bit)
|
|
80
|
+
#
|
|
81
|
+
# @return [Boolean] True if 32-bit color
|
|
82
|
+
def color?
|
|
83
|
+
bit_depth == 32
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Check if this is a monochrome strike (1-bit)
|
|
87
|
+
#
|
|
88
|
+
# @return [Boolean] True if 1-bit monochrome
|
|
89
|
+
def monochrome?
|
|
90
|
+
bit_depth == 1
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -13,16 +13,22 @@ module Fontisan
|
|
|
13
13
|
# @example Creating collection brief info
|
|
14
14
|
# info = CollectionBriefInfo.new(
|
|
15
15
|
# collection_path: "fonts.ttc",
|
|
16
|
+
# collection_type: "TTC",
|
|
17
|
+
# collection_version: "1.0",
|
|
16
18
|
# num_fonts: 3,
|
|
17
19
|
# fonts: [font_info1, font_info2, font_info3]
|
|
18
20
|
# )
|
|
19
21
|
class CollectionBriefInfo < Lutaml::Model::Serializable
|
|
20
22
|
attribute :collection_path, :string
|
|
23
|
+
attribute :collection_type, :string
|
|
24
|
+
attribute :collection_version, :string
|
|
21
25
|
attribute :num_fonts, :integer
|
|
22
26
|
attribute :fonts, FontInfo, collection: true
|
|
23
27
|
|
|
24
28
|
key_value do
|
|
25
29
|
map "collection_path", to: :collection_path
|
|
30
|
+
map "collection_type", to: :collection_type
|
|
31
|
+
map "collection_version", to: :collection_version
|
|
26
32
|
map "num_fonts", to: :num_fonts
|
|
27
33
|
map "fonts", to: :fonts
|
|
28
34
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "lutaml/model"
|
|
4
4
|
require_relative "table_sharing_info"
|
|
5
|
+
require_relative "font_info"
|
|
5
6
|
|
|
6
7
|
module Fontisan
|
|
7
8
|
module Models
|
|
@@ -20,7 +21,8 @@ module Fontisan
|
|
|
20
21
|
# num_fonts: 6,
|
|
21
22
|
# font_offsets: [48, 380, 712, 1044, 1376, 1676],
|
|
22
23
|
# file_size_bytes: 2240000,
|
|
23
|
-
# table_sharing: table_sharing_obj
|
|
24
|
+
# table_sharing: table_sharing_obj,
|
|
25
|
+
# fonts: [font_info1, font_info2, ...]
|
|
24
26
|
# )
|
|
25
27
|
class CollectionInfo < Lutaml::Model::Serializable
|
|
26
28
|
attribute :collection_path, :string
|
|
@@ -32,6 +34,7 @@ module Fontisan
|
|
|
32
34
|
attribute :font_offsets, :integer, collection: true
|
|
33
35
|
attribute :file_size_bytes, :integer
|
|
34
36
|
attribute :table_sharing, TableSharingInfo
|
|
37
|
+
attribute :fonts, FontInfo, collection: true
|
|
35
38
|
|
|
36
39
|
yaml do
|
|
37
40
|
map "collection_path", to: :collection_path
|
|
@@ -43,6 +46,7 @@ module Fontisan
|
|
|
43
46
|
map "font_offsets", to: :font_offsets
|
|
44
47
|
map "file_size_bytes", to: :file_size_bytes
|
|
45
48
|
map "table_sharing", to: :table_sharing
|
|
49
|
+
map "fonts", to: :fonts
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
json do
|
|
@@ -55,6 +59,7 @@ module Fontisan
|
|
|
55
59
|
map "font_offsets", to: :font_offsets
|
|
56
60
|
map "file_size_bytes", to: :file_size_bytes
|
|
57
61
|
map "table_sharing", to: :table_sharing
|
|
62
|
+
map "fonts", to: :fonts
|
|
58
63
|
end
|
|
59
64
|
|
|
60
65
|
# Get version as a formatted string
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "color_layer"
|
|
5
|
+
|
|
6
|
+
module Fontisan
|
|
7
|
+
module Models
|
|
8
|
+
# Color glyph information model
|
|
9
|
+
#
|
|
10
|
+
# Represents a complete color glyph from the COLR table, containing
|
|
11
|
+
# multiple layers that are rendered in order to create the final
|
|
12
|
+
# multi-colored glyph.
|
|
13
|
+
#
|
|
14
|
+
# This model uses lutaml-model for structured serialization to YAML/JSON/XML.
|
|
15
|
+
#
|
|
16
|
+
# @example Creating a color glyph
|
|
17
|
+
# glyph = ColorGlyph.new
|
|
18
|
+
# glyph.glyph_id = 100
|
|
19
|
+
# glyph.num_layers = 3
|
|
20
|
+
# glyph.layers = [layer1, layer2, layer3]
|
|
21
|
+
#
|
|
22
|
+
# @example Serializing to JSON
|
|
23
|
+
# json = glyph.to_json
|
|
24
|
+
# # {
|
|
25
|
+
# # "glyph_id": 100,
|
|
26
|
+
# # "num_layers": 3,
|
|
27
|
+
# # "layers": [...]
|
|
28
|
+
# # }
|
|
29
|
+
class ColorGlyph < Lutaml::Model::Serializable
|
|
30
|
+
# @!attribute glyph_id
|
|
31
|
+
# @return [Integer] Base glyph ID
|
|
32
|
+
attribute :glyph_id, :integer
|
|
33
|
+
|
|
34
|
+
# @!attribute num_layers
|
|
35
|
+
# @return [Integer] Number of color layers
|
|
36
|
+
attribute :num_layers, :integer
|
|
37
|
+
|
|
38
|
+
# @!attribute layers
|
|
39
|
+
# @return [Array<ColorLayer>] Array of color layers
|
|
40
|
+
attribute :layers, ColorLayer, collection: true
|
|
41
|
+
|
|
42
|
+
# Check if glyph has color layers
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean] True if glyph has layers
|
|
45
|
+
def has_layers?
|
|
46
|
+
num_layers&.positive? || false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Check if glyph is empty
|
|
50
|
+
#
|
|
51
|
+
# @return [Boolean] True if no layers
|
|
52
|
+
def empty?
|
|
53
|
+
!has_layers?
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# Color layer information model
|
|
8
|
+
#
|
|
9
|
+
# Represents a single color layer in a COLR glyph. Each layer specifies
|
|
10
|
+
# a glyph ID to render and the palette index for its color.
|
|
11
|
+
#
|
|
12
|
+
# This model uses lutaml-model for structured serialization to YAML/JSON/XML.
|
|
13
|
+
#
|
|
14
|
+
# @example Creating a color layer
|
|
15
|
+
# layer = ColorLayer.new
|
|
16
|
+
# layer.glyph_id = 42
|
|
17
|
+
# layer.palette_index = 2
|
|
18
|
+
# layer.color = "#FF0000FF"
|
|
19
|
+
#
|
|
20
|
+
# @example Serializing to YAML
|
|
21
|
+
# yaml = layer.to_yaml
|
|
22
|
+
# # glyph_id: 42
|
|
23
|
+
# # palette_index: 2
|
|
24
|
+
# # color: "#FF0000FF"
|
|
25
|
+
class ColorLayer < Lutaml::Model::Serializable
|
|
26
|
+
# @!attribute glyph_id
|
|
27
|
+
# @return [Integer] Glyph ID of the layer
|
|
28
|
+
attribute :glyph_id, :integer
|
|
29
|
+
|
|
30
|
+
# @!attribute palette_index
|
|
31
|
+
# @return [Integer] Index into CPAL palette (0xFFFF = foreground)
|
|
32
|
+
attribute :palette_index, :integer
|
|
33
|
+
|
|
34
|
+
# @!attribute color
|
|
35
|
+
# @return [String, nil] Hex color from palette (#RRGGBBAA), nil if foreground
|
|
36
|
+
attribute :color, :string
|
|
37
|
+
|
|
38
|
+
# Check if this layer uses the foreground color
|
|
39
|
+
#
|
|
40
|
+
# @return [Boolean] True if using text foreground color
|
|
41
|
+
def uses_foreground_color?
|
|
42
|
+
palette_index == 0xFFFF
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check if this layer uses a palette color
|
|
46
|
+
#
|
|
47
|
+
# @return [Boolean] True if using CPAL palette color
|
|
48
|
+
def uses_palette_color?
|
|
49
|
+
!uses_foreground_color?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# Color palette information model
|
|
8
|
+
#
|
|
9
|
+
# Represents a color palette from the CPAL table. Each palette contains
|
|
10
|
+
# an array of RGBA colors in hex format that can be referenced by
|
|
11
|
+
# COLR layer palette indices.
|
|
12
|
+
#
|
|
13
|
+
# This model uses lutaml-model for structured serialization to YAML/JSON/XML.
|
|
14
|
+
#
|
|
15
|
+
# @example Creating a color palette
|
|
16
|
+
# palette = ColorPalette.new
|
|
17
|
+
# palette.index = 0
|
|
18
|
+
# palette.num_colors = 3
|
|
19
|
+
# palette.colors = ["#FF0000FF", "#00FF00FF", "#0000FFFF"]
|
|
20
|
+
#
|
|
21
|
+
# @example Serializing to YAML
|
|
22
|
+
# yaml = palette.to_yaml
|
|
23
|
+
# # index: 0
|
|
24
|
+
# # num_colors: 3
|
|
25
|
+
# # colors:
|
|
26
|
+
# # - "#FF0000FF"
|
|
27
|
+
# # - "#00FF00FF"
|
|
28
|
+
# # - "#0000FFFF"
|
|
29
|
+
class ColorPalette < Lutaml::Model::Serializable
|
|
30
|
+
# @!attribute index
|
|
31
|
+
# @return [Integer] Palette index (0-based)
|
|
32
|
+
attribute :index, :integer
|
|
33
|
+
|
|
34
|
+
# @!attribute num_colors
|
|
35
|
+
# @return [Integer] Number of colors in this palette
|
|
36
|
+
attribute :num_colors, :integer
|
|
37
|
+
|
|
38
|
+
# @!attribute colors
|
|
39
|
+
# @return [Array<String>] Array of hex color strings (#RRGGBBAA)
|
|
40
|
+
attribute :colors, :string, collection: true
|
|
41
|
+
|
|
42
|
+
# Get a color by index
|
|
43
|
+
#
|
|
44
|
+
# @param color_index [Integer] Color index within palette
|
|
45
|
+
# @return [String, nil] Hex color string or nil if invalid index
|
|
46
|
+
def color_at(color_index)
|
|
47
|
+
return nil if color_index.negative? || color_index >= colors.length
|
|
48
|
+
|
|
49
|
+
colors[color_index]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Check if palette is empty
|
|
53
|
+
#
|
|
54
|
+
# @return [Boolean] True if no colors
|
|
55
|
+
def empty?
|
|
56
|
+
colors.nil? || colors.empty?
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -38,6 +38,22 @@ module Fontisan
|
|
|
38
38
|
attribute :units_per_em, :integer
|
|
39
39
|
attribute :collection_offset, :integer
|
|
40
40
|
|
|
41
|
+
# Color font information (from COLR/CPAL tables)
|
|
42
|
+
attribute :is_color_font, Lutaml::Model::Type::Boolean
|
|
43
|
+
attribute :color_glyphs, :integer
|
|
44
|
+
attribute :color_palettes, :integer
|
|
45
|
+
attribute :colors_per_palette, :integer
|
|
46
|
+
|
|
47
|
+
# SVG table information
|
|
48
|
+
attribute :has_svg_table, Lutaml::Model::Type::Boolean
|
|
49
|
+
attribute :svg_glyph_count, :integer
|
|
50
|
+
|
|
51
|
+
# Bitmap table information (CBDT/CBLC, sbix)
|
|
52
|
+
attribute :has_bitmap_glyphs, Lutaml::Model::Type::Boolean
|
|
53
|
+
attribute :bitmap_strikes, Models::BitmapStrike, collection: true
|
|
54
|
+
attribute :bitmap_ppem_sizes, :integer, collection: true
|
|
55
|
+
attribute :bitmap_formats, :string, collection: true
|
|
56
|
+
|
|
41
57
|
key_value do
|
|
42
58
|
map "font_format", to: :font_format
|
|
43
59
|
map "is_variable", to: :is_variable
|
|
@@ -66,6 +82,16 @@ module Fontisan
|
|
|
66
82
|
map "permissions", to: :permissions
|
|
67
83
|
map "units_per_em", to: :units_per_em
|
|
68
84
|
map "collection_offset", to: :collection_offset
|
|
85
|
+
map "is_color_font", to: :is_color_font
|
|
86
|
+
map "color_glyphs", to: :color_glyphs
|
|
87
|
+
map "color_palettes", to: :color_palettes
|
|
88
|
+
map "colors_per_palette", to: :colors_per_palette
|
|
89
|
+
map "has_svg_table", to: :has_svg_table
|
|
90
|
+
map "svg_glyph_count", to: :svg_glyph_count
|
|
91
|
+
map "has_bitmap_glyphs", to: :has_bitmap_glyphs
|
|
92
|
+
map "bitmap_strikes", to: :bitmap_strikes
|
|
93
|
+
map "bitmap_ppem_sizes", to: :bitmap_ppem_sizes
|
|
94
|
+
map "bitmap_formats", to: :bitmap_formats
|
|
69
95
|
end
|
|
70
96
|
end
|
|
71
97
|
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
module Models
|
|
7
|
+
# SVG glyph representation model
|
|
8
|
+
#
|
|
9
|
+
# Represents an SVG document for a glyph or range of glyphs from the SVG table.
|
|
10
|
+
# Each SVG document can cover multiple glyph IDs and may be compressed.
|
|
11
|
+
#
|
|
12
|
+
# This model uses lutaml-model for structured serialization to YAML/JSON/XML.
|
|
13
|
+
#
|
|
14
|
+
# @example Creating an SVG glyph
|
|
15
|
+
# svg_glyph = SvgGlyph.new
|
|
16
|
+
# svg_glyph.glyph_id = 100
|
|
17
|
+
# svg_glyph.start_glyph_id = 100
|
|
18
|
+
# svg_glyph.end_glyph_id = 105
|
|
19
|
+
# svg_glyph.svg_content = '<svg>...</svg>'
|
|
20
|
+
# svg_glyph.compressed = false
|
|
21
|
+
#
|
|
22
|
+
# @example Serializing to JSON
|
|
23
|
+
# json = svg_glyph.to_json
|
|
24
|
+
# # {
|
|
25
|
+
# # "glyph_id": 100,
|
|
26
|
+
# # "start_glyph_id": 100,
|
|
27
|
+
# # "end_glyph_id": 105,
|
|
28
|
+
# # "svg_content": "<svg>...</svg>",
|
|
29
|
+
# # "compressed": false
|
|
30
|
+
# # }
|
|
31
|
+
class SvgGlyph < Lutaml::Model::Serializable
|
|
32
|
+
# @!attribute glyph_id
|
|
33
|
+
# @return [Integer] Primary glyph ID (usually same as start_glyph_id)
|
|
34
|
+
attribute :glyph_id, :integer
|
|
35
|
+
|
|
36
|
+
# @!attribute start_glyph_id
|
|
37
|
+
# @return [Integer] First glyph ID in range covered by this SVG
|
|
38
|
+
attribute :start_glyph_id, :integer
|
|
39
|
+
|
|
40
|
+
# @!attribute end_glyph_id
|
|
41
|
+
# @return [Integer] Last glyph ID in range covered by this SVG
|
|
42
|
+
attribute :end_glyph_id, :integer
|
|
43
|
+
|
|
44
|
+
# @!attribute svg_content
|
|
45
|
+
# @return [String] SVG XML content (decompressed)
|
|
46
|
+
attribute :svg_content, :string
|
|
47
|
+
|
|
48
|
+
# @!attribute compressed
|
|
49
|
+
# @return [Boolean] Whether the original data was gzip compressed
|
|
50
|
+
attribute :compressed, :boolean, default: -> { false }
|
|
51
|
+
|
|
52
|
+
# Get glyph IDs covered by this SVG document
|
|
53
|
+
#
|
|
54
|
+
# @return [Range] Range of glyph IDs
|
|
55
|
+
def glyph_range
|
|
56
|
+
start_glyph_id..end_glyph_id
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Check if this SVG covers a specific glyph ID
|
|
60
|
+
#
|
|
61
|
+
# @param glyph_id [Integer] Glyph ID to check
|
|
62
|
+
# @return [Boolean] True if glyph is in range
|
|
63
|
+
def includes_glyph?(glyph_id)
|
|
64
|
+
glyph_range.include?(glyph_id)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Check if this SVG covers multiple glyphs
|
|
68
|
+
#
|
|
69
|
+
# @return [Boolean] True if range includes more than one glyph
|
|
70
|
+
def covers_multiple_glyphs?
|
|
71
|
+
start_glyph_id != end_glyph_id
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Get the number of glyphs covered by this SVG
|
|
75
|
+
#
|
|
76
|
+
# @return [Integer] Number of glyphs in range
|
|
77
|
+
def num_glyphs
|
|
78
|
+
end_glyph_id - start_glyph_id + 1
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Check if SVG content is present
|
|
82
|
+
#
|
|
83
|
+
# @return [Boolean] True if svg_content is not nil or empty
|
|
84
|
+
def has_content?
|
|
85
|
+
!svg_content.nil? && !svg_content.empty?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|