Class: Fontisan::Tables::Cff2::VariationDataExtractor
- Inherits:
-
Object
- Object
- Fontisan::Tables::Cff2::VariationDataExtractor
- Defined in:
- lib/fontisan/tables/cff2/variation_data_extractor.rb
Overview
Variation data extractor for CFF2 Variable Store
Extracts regions and deltas from the Variable Store and provides utilities for working with variation data.
Reference: OpenType spec - Item Variation Store Reference: Adobe Technical Note #5177 (CFF2)
Instance Attribute Summary collapse
-
#item_variation_data ⇒ Array<Hash>
readonly
Item variation data.
-
#regions ⇒ Array<Hash>
readonly
Extracted regions.
-
#variable_store ⇒ Hash
readonly
Variable Store data.
Instance Method Summary collapse
-
#all_deltas(data_index: 0) ⇒ Array<Array<Integer>>
Get all deltas for all items.
-
#axis_count ⇒ Integer
Get number of axes from first region.
-
#blend_value(item_index, base_value, scalars, data_index: 0) ⇒ Float
Calculate blended value for an item at specific coordinates.
-
#deltas_for_item(item_index, data_index: 0) ⇒ Array<Integer>?
Get deltas for a specific item.
-
#has_data? ⇒ Boolean
Check if Variable Store has data.
-
#initialize(variable_store) ⇒ VariationDataExtractor
constructor
Initialize extractor with Variable Store data.
-
#item_count(data_index: 0) ⇒ Integer
Get number of items in item variation data.
-
#region(region_index) ⇒ Hash?
Get region by index.
-
#region_coordinates ⇒ Array<Array<Hash>>
Extract all region coordinates as arrays.
-
#region_count ⇒ Integer
Get number of regions.
-
#region_indices(data_index: 0) ⇒ Array<Integer>
Get region indices for item variation data.
-
#validate ⇒ Array<String>
Validate Variable Store structure.
Constructor Details
#initialize(variable_store) ⇒ VariationDataExtractor
Initialize extractor with Variable Store data
31 32 33 34 35 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 31 def initialize(variable_store) @variable_store = variable_store @regions = variable_store[:regions] || [] @item_variation_data = variable_store[:item_variation_data] || [] end |
Instance Attribute Details
#item_variation_data ⇒ Array<Hash> (readonly)
Returns Item variation data.
26 27 28 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 26 def item_variation_data @item_variation_data end |
#regions ⇒ Array<Hash> (readonly)
Returns Extracted regions.
23 24 25 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 23 def regions @regions end |
#variable_store ⇒ Hash (readonly)
Returns Variable Store data.
20 21 22 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 20 def variable_store @variable_store end |
Instance Method Details
#all_deltas(data_index: 0) ⇒ Array<Array<Integer>>
Get all deltas for all items
75 76 77 78 79 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 75 def all_deltas(data_index: 0) return [] if data_index >= @item_variation_data.size @item_variation_data[data_index][:delta_sets] || [] end |
#axis_count ⇒ Integer
Get number of axes from first region
127 128 129 130 131 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 127 def axis_count return 0 if @regions.empty? @regions.first[:axis_count] || 0 end |
#blend_value(item_index, base_value, scalars, data_index: 0) ⇒ Float
Calculate blended value for an item at specific coordinates
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 88 def blend_value(item_index, base_value, scalars, data_index: 0) deltas = deltas_for_item(item_index, data_index: data_index) return base_value.to_f unless deltas indices = region_indices(data_index: data_index) # Apply blend: result = base + Σ(delta[i] * scalar[region_index[i]]) result = base_value.to_f deltas.each_with_index do |delta, i| region_index = indices[i] next unless region_index scalar = scalars[region_index] || 0.0 result += delta.to_f * scalar end result end |
#deltas_for_item(item_index, data_index: 0) ⇒ Array<Integer>?
Get deltas for a specific item
42 43 44 45 46 47 48 49 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 42 def deltas_for_item(item_index, data_index: 0) return nil if data_index >= @item_variation_data.size item_data = @item_variation_data[data_index] return nil if item_index >= item_data[:delta_sets].size item_data[:delta_sets][item_index] end |
#has_data? ⇒ Boolean
Check if Variable Store has data
136 137 138 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 136 def has_data? !@regions.empty? && !@item_variation_data.empty? end |
#item_count(data_index: 0) ⇒ Integer
Get number of items in item variation data
65 66 67 68 69 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 65 def item_count(data_index: 0) return 0 if data_index >= @item_variation_data.size @item_variation_data[data_index][:item_count] || 0 end |
#region(region_index) ⇒ Hash?
Get region by index
111 112 113 114 115 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 111 def region(region_index) return nil if region_index >= @regions.size @regions[region_index] end |
#region_coordinates ⇒ Array<Array<Hash>>
Extract all region coordinates as arrays
Useful for debugging and validation
145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 145 def region_coordinates @regions.map do |region| region[:axes].map do |axis| { start: axis[:start_coord], peak: axis[:peak_coord], end: axis[:end_coord], } end end end |
#region_count ⇒ Integer
Get number of regions
120 121 122 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 120 def region_count @regions.size end |
#region_indices(data_index: 0) ⇒ Array<Integer>
Get region indices for item variation data
55 56 57 58 59 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 55 def region_indices(data_index: 0) return [] if data_index >= @item_variation_data.size @item_variation_data[data_index][:region_indices] || [] end |
#validate ⇒ Array<String>
Validate Variable Store structure
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/fontisan/tables/cff2/variation_data_extractor.rb', line 160 def validate errors = [] # Check regions consistency if @regions.any? expected_axes = @regions.first[:axis_count] @regions.each_with_index do |region, i| unless region[:axis_count] == expected_axes errors << "Region #{i} has inconsistent axis_count: " \ "#{region[:axis_count]} vs #{expected_axes}" end unless region[:axes].size == expected_axes errors << "Region #{i} has #{region[:axes].size} axes, " \ "expected #{expected_axes}" end end end # Check item variation data @item_variation_data.each_with_index do |item_data, i| item_count = item_data[:item_count] delta_sets = item_data[:delta_sets] region_indices = item_data[:region_indices] unless delta_sets.size == item_count errors << "Item variation data #{i} has #{delta_sets.size} " \ "delta sets, expected #{item_count}" end # Check each delta set has correct number of deltas delta_sets.each_with_index do |deltas, j| unless deltas.size == region_indices.size errors << "Delta set #{j} in data #{i} has #{deltas.size} " \ "deltas, expected #{region_indices.size}" end end # Check region indices are valid region_indices.each_with_index do |idx, j| if idx >= @regions.size errors << "Region index #{idx} at position #{j} in data #{i} " \ "exceeds region count #{@regions.size}" end end end errors end |