Class: Fontisan::Variation::InstanceGenerator
- Inherits:
-
Object
- Object
- Fontisan::Variation::InstanceGenerator
- Includes:
- TableAccessor
- Defined in:
- lib/fontisan/variation/instance_generator.rb
Overview
Generates static font instances from variable fonts
This class creates static font instances by applying variation deltas at specific design space coordinates. It supports both TrueType (gvar) and PostScript (CFF2) variable fonts.
Process:
-
Extract variation data (axes, deltas, regions)
-
Calculate interpolation scalars for given coordinates
-
Apply deltas to outlines (gvar or CFF2)
-
Apply deltas to metrics (HVAR, VVAR, MVAR)
-
Remove variation tables to create static font
Instance Attribute Summary collapse
-
#context ⇒ VariationContext
readonly
Variation context.
-
#coordinates ⇒ Hash<String, Float>
readonly
Design space coordinates.
-
#font ⇒ TrueTypeFont, OpenTypeFont
readonly
Variable font.
Instance Method Summary collapse
-
#apply_cff2_blend(_tables) ⇒ Object
Apply CFF2 blend operators.
-
#apply_glyph_deltas(glyph_id, gvar, _glyf) ⇒ Object
Apply deltas to a specific glyph.
-
#apply_gvar_deltas(_tables) ⇒ Object
Apply gvar deltas to TrueType outlines.
-
#apply_hvar_deltas(_tables) ⇒ Object
Apply HVAR deltas to horizontal metrics.
-
#apply_metrics_deltas(tables) ⇒ Object
Apply metrics variations.
-
#apply_mvar_deltas(_tables) ⇒ Object
Apply MVAR deltas to font-wide metrics.
-
#apply_vvar_deltas(_tables) ⇒ Object
Apply VVAR deltas to vertical metrics.
-
#calculate_variation_scalars ⇒ Array<Float>
Calculate variation scalars for current coordinates.
-
#generate ⇒ Hash<String, String>
Generate static font instance.
-
#generate_named_instance(instance_index) ⇒ Hash<String, String>
Generate a named instance.
-
#initialize(font, coordinates = {}, options = {}) ⇒ InstanceGenerator
constructor
Initialize generator with font and optional coordinates.
-
#interpolate_point(base_point, delta_points, scalars) ⇒ Hash
Interpolate a point.
-
#interpolate_value(base_value, deltas, scalars) ⇒ Float
Interpolate a single value.
-
#remove_variation_tables(tables) ⇒ Object
Remove variation tables from static font.
Methods included from TableAccessor
#clear_variation_cache, #clear_variation_table, #has_variation_table?, #require_variation_table, #variation_table
Constructor Details
#initialize(font, coordinates = {}, options = {}) ⇒ InstanceGenerator
Initialize generator with font and optional coordinates
49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/fontisan/variation/instance_generator.rb', line 49 def initialize(font, coordinates = {}, = {}) @font = font @coordinates = coordinates # Initialize variation context @context = VariationContext.new(@font) @context.validate! unless [:skip_validation] # Initialize table cache for lazy loading @variation_tables = {} end |
Instance Attribute Details
#context ⇒ VariationContext (readonly)
Returns Variation context.
41 42 43 |
# File 'lib/fontisan/variation/instance_generator.rb', line 41 def context @context end |
#coordinates ⇒ Hash<String, Float> (readonly)
Returns Design space coordinates.
38 39 40 |
# File 'lib/fontisan/variation/instance_generator.rb', line 38 def coordinates @coordinates end |
#font ⇒ TrueTypeFont, OpenTypeFont (readonly)
Returns Variable font.
35 36 37 |
# File 'lib/fontisan/variation/instance_generator.rb', line 35 def font @font end |
Instance Method Details
#apply_cff2_blend(_tables) ⇒ Object
Apply CFF2 blend operators
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/fontisan/variation/instance_generator.rb', line 156 def apply_cff2_blend(_tables) cff2 = variation_table("CFF2") return unless cff2 # Set number of axes for CFF2 cff2.num_axes = @context.axis_count # Process each glyph's CharString glyph_count = cff2.glyph_count return if glyph_count.zero? # Calculate variation scalars once calculate_variation_scalars # Apply blend to each glyph # This is a placeholder - full implementation would: # 1. Parse CharString with blend operators # 2. Apply scalars to blend operands # 3. Rebuild CharStrings without blend operators # 4. Update CFF2 table end |
#apply_glyph_deltas(glyph_id, gvar, _glyf) ⇒ Object
Apply deltas to a specific glyph
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/fontisan/variation/instance_generator.rb', line 131 def apply_glyph_deltas(glyph_id, gvar, _glyf) # Get tuple variations for this glyph tuple_data = gvar.glyph_tuple_variations(glyph_id) return unless tuple_data # Match tuples to current coordinates matches = @context.region_matcher.match_tuples( coordinates: @coordinates, tuples: tuple_data[:tuples], ) nil if matches.empty? # Get base glyph outline # Apply matched deltas with their scalars # This is a placeholder - full implementation would: # 1. Parse glyph outline points # 2. Parse delta data for each tuple # 3. Apply: new_point = base_point + Σ(delta * scalar) # 4. Update glyph outline end |
#apply_gvar_deltas(_tables) ⇒ Object
Apply gvar deltas to TrueType outlines
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/fontisan/variation/instance_generator.rb', line 108 def apply_gvar_deltas(_tables) gvar = variation_table("gvar") glyf = @font.table("glyf") return unless gvar && glyf # Get glyph count maxp = @font.table("maxp") glyph_count = maxp ? maxp.num_glyphs : gvar.glyph_count # Process each glyph glyph_count.times do |glyph_id| apply_glyph_deltas(glyph_id, gvar, glyf) end # Rebuild glyf and loca tables with adjusted outlines # This is a placeholder - full implementation would reconstruct tables end |
#apply_hvar_deltas(_tables) ⇒ Object
Apply HVAR deltas to horizontal metrics
205 206 207 208 |
# File 'lib/fontisan/variation/instance_generator.rb', line 205 def apply_hvar_deltas(_tables) adjuster = MetricsAdjuster.new(@font, @context.interpolator) adjuster.apply_hvar_deltas(@coordinates) end |
#apply_metrics_deltas(tables) ⇒ Object
Apply metrics variations
191 192 193 194 195 196 197 198 199 200 |
# File 'lib/fontisan/variation/instance_generator.rb', line 191 def apply_metrics_deltas(tables) # Apply HVAR (horizontal metrics) apply_hvar_deltas(tables) if has_variation_table?("HVAR") # Apply VVAR (vertical metrics) apply_vvar_deltas(tables) if has_variation_table?("VVAR") # Apply MVAR (font-wide metrics) apply_mvar_deltas(tables) if has_variation_table?("MVAR") end |
#apply_mvar_deltas(_tables) ⇒ Object
Apply MVAR deltas to font-wide metrics
221 222 223 224 |
# File 'lib/fontisan/variation/instance_generator.rb', line 221 def apply_mvar_deltas(_tables) adjuster = MetricsAdjuster.new(@font, @context.interpolator) adjuster.apply_mvar_deltas(@coordinates) end |
#apply_vvar_deltas(_tables) ⇒ Object
Apply VVAR deltas to vertical metrics
213 214 215 216 |
# File 'lib/fontisan/variation/instance_generator.rb', line 213 def apply_vvar_deltas(_tables) adjuster = MetricsAdjuster.new(@font, @context.interpolator) adjuster.apply_vvar_deltas(@coordinates) end |
#calculate_variation_scalars ⇒ Array<Float>
Calculate variation scalars for current coordinates
181 182 183 184 185 186 |
# File 'lib/fontisan/variation/instance_generator.rb', line 181 def calculate_variation_scalars @context.axes.map do |axis| coord = @coordinates[axis.axis_tag] || axis.default_value @context.interpolator.normalize_coordinate(coord, axis.axis_tag) end end |
#generate ⇒ Hash<String, String>
Generate static font instance
Applies variation deltas and returns static font tables.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/fontisan/variation/instance_generator.rb', line 66 def generate # Start with base font tables tables = @font.table_data.dup # Determine variation type if has_variation_table?("gvar") # TrueType outlines with gvar apply_gvar_deltas(tables) elsif has_variation_table?("CFF2") # PostScript outlines with CFF2 blend apply_cff2_blend(tables) end # Apply metrics variations if present apply_metrics_deltas(tables) if @context.has_metrics_variations? # Remove variation-specific tables to create static font remove_variation_tables(tables) tables end |
#generate_named_instance(instance_index) ⇒ Hash<String, String>
Generate a named instance
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/fontisan/variation/instance_generator.rb', line 92 def generate_named_instance(instance_index) # Extract instance coordinates from fvar return generate if instance_index.nil? || !@context.fvar instances = @context.fvar.instances return generate if instance_index >= instances.length instance = instances[instance_index] @coordinates = build_coordinates_from_instance(instance, @context.axes) generate end |
#interpolate_point(base_point, delta_points, scalars) ⇒ Hash
Interpolate a point
250 251 252 253 |
# File 'lib/fontisan/variation/instance_generator.rb', line 250 def interpolate_point(base_point, delta_points, scalars) @context.interpolator.interpolate_point(base_point, delta_points, scalars) end |
#interpolate_value(base_value, deltas, scalars) ⇒ Float
Interpolate a single value
240 241 242 |
# File 'lib/fontisan/variation/instance_generator.rb', line 240 def interpolate_value(base_value, deltas, scalars) @context.interpolator.interpolate_value(base_value, deltas, scalars) end |
#remove_variation_tables(tables) ⇒ Object
Remove variation tables from static font
229 230 231 232 |
# File 'lib/fontisan/variation/instance_generator.rb', line 229 def remove_variation_tables(tables) variation_tables = %w[fvar gvar cvar HVAR VVAR MVAR avar STAT] variation_tables.each { |tag| tables.delete(tag) } end |