Class: Fontisan::Subset::TableSubsetter
- Inherits:
-
Object
- Object
- Fontisan::Subset::TableSubsetter
- Defined in:
- lib/fontisan/subset/table_subsetter.rb
Overview
Table-specific subsetting strategies
This class provides methods for subsetting individual font tables according to the glyph mapping. Each table type has different subsetting requirements:
- maxp: Update glyph count
- hhea: Update horizontal metrics count
- hmtx: Subset horizontal metrics
- glyf: Subset glyph data and remap component references
- loca: Rebuild glyph location index
- cmap: Remap character to glyph mappings
- post: Optionally drop glyph names
- name: Pass through (no subsetting needed)
- head: Update checksum adjustment (handled by FontWriter)
- OS/2: Optionally prune Unicode ranges
The subsetting process preserves font validity by updating all references and recalculating offsets and checksums.
Instance Attribute Summary collapse
-
#font ⇒ TrueTypeFont, OpenTypeFont
readonly
Font instance being subset.
-
#mapping ⇒ GlyphMapping
readonly
Glyph ID mapping (old GID → new GID).
-
#options ⇒ Options
readonly
Subsetting options.
Instance Method Summary collapse
-
#initialize(font, mapping, options) ⇒ TableSubsetter
constructor
Initialize table subsetter.
-
#subset_cmap(table) ⇒ String
Subset cmap table (remap character to glyph mappings).
-
#subset_glyf(table) ⇒ String
Subset glyf table (subset glyph data).
-
#subset_head(_table) ⇒ String
Subset head table (pass through).
-
#subset_hhea(table, hmtx = nil) ⇒ String
Subset hhea table (update numberOfHMetrics).
-
#subset_hmtx(table) ⇒ String
Subset hmtx table (subset horizontal metrics).
-
#subset_loca(_table) ⇒ String
Subset loca table (rebuild glyph location index).
-
#subset_maxp(table) ⇒ String
Subset maxp table (update numGlyphs).
-
#subset_name(_table) ⇒ String
Subset name table (pass through).
-
#subset_os2(_table) ⇒ String
Subset OS/2 table (optionally prune Unicode ranges).
-
#subset_post(table) ⇒ String
Subset post table (optionally drop glyph names).
-
#subset_table(tag, table) ⇒ String
Subset a table by tag.
Constructor Details
#initialize(font, mapping, options) ⇒ TableSubsetter
Initialize table subsetter
53 54 55 56 57 58 59 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 53 def initialize(font, mapping, ) @font = font @mapping = mapping @options = @glyf_data = nil @loca_offsets = nil end |
Instance Attribute Details
#font ⇒ TrueTypeFont, OpenTypeFont (readonly)
Font instance being subset
38 39 40 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 38 def font @font end |
#mapping ⇒ GlyphMapping (readonly)
Glyph ID mapping (old GID → new GID)
42 43 44 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 42 def mapping @mapping end |
#options ⇒ Options (readonly)
Subsetting options
46 47 48 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 46 def @options end |
Instance Method Details
#subset_cmap(table) ⇒ String
Subset cmap table (remap character to glyph mappings)
Builds new cmap table with only mappings for glyphs in the subset. Updates glyph IDs to new values from the mapping.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 218 def subset_cmap(table) # Get old mappings old_mappings = table.unicode_mappings new_mappings = {} # Remap to new glyph IDs old_mappings.each do |char_code, old_gid| new_gid = mapping.new_id(old_gid) new_mappings[char_code] = new_gid if new_gid end # Build cmap binary with new mappings build_cmap_binary(new_mappings) end |
#subset_glyf(table) ⇒ String
Subset glyf table (subset glyph data)
Extracts glyph data for subset glyphs and remaps component references in compound glyphs. Also builds loca offsets.
173 174 175 176 177 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 173 def subset_glyf(table) # Build glyf and loca together build_glyf_and_loca(table) @glyf_data end |
#subset_head(_table) ⇒ String
Subset head table (pass through)
head table will have checksum updated by FontWriter, no subsetting needed.
267 268 269 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 267 def subset_head(_table) font.table_data["head"] end |
#subset_hhea(table, hmtx = nil) ⇒ String
Subset hhea table (update numberOfHMetrics)
Updates the numberOfHMetrics field to reflect the number of horizontal metrics in the subset font.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 121 def subset_hhea(table, hmtx = nil) data = table.to_binary_s.dup # Calculate new numberOfHMetrics new_num_h_metrics = if hmtx&.h_metrics hmtx.h_metrics.size else calculate_number_of_h_metrics end # Update numberOfHMetrics field (at offset 34, uint16) data[34, 2] = [new_num_h_metrics].pack("n") data end |
#subset_hmtx(table) ⇒ String
Subset hmtx table (subset horizontal metrics)
Builds new hmtx table with metrics for subset glyphs only, preserving the order of the glyph mapping.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 144 def subset_hmtx(table) # Ensure hmtx is parsed unless table.parsed? hhea = font.table("hhea") maxp = font.table("maxp") table.parse_with_context(hhea.number_of_h_metrics, maxp.num_glyphs) end # Build new hmtx data data = String.new(encoding: Encoding::BINARY) mapping.old_ids.each do |old_id| metric = table.metric_for(old_id) next unless metric data << [metric[:advance_width]].pack("n") data << [metric[:lsb]].pack("n") end data end |
#subset_loca(_table) ⇒ String
Subset loca table (rebuild glyph location index)
Builds new loca table based on subset glyph offsets. Must be called after subset_glyf.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 186 def subset_loca(_table) # Build glyf and loca together if not already done glyf = font.table("glyf") build_glyf_and_loca(glyf) unless @loca_offsets head = font.table("head") format = head.index_to_loc_format data = String.new(encoding: Encoding::BINARY) if format.zero? # Short format: offsets / 2 as uint16 @loca_offsets.each do |offset| data << [offset / 2].pack("n") end else # Long format: offsets as uint32 @loca_offsets.each do |offset| data << [offset].pack("N") end end data end |
#subset_maxp(table) ⇒ String
Subset maxp table (update numGlyphs)
Updates the numGlyphs field to reflect the number of glyphs in the subset font.
104 105 106 107 108 109 110 111 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 104 def subset_maxp(table) data = table.to_binary_s.dup # Update numGlyphs field (at offset 4, uint16) data[4, 2] = [mapping.size].pack("n") data end |
#subset_name(_table) ⇒ String
Subset name table (pass through)
Name table doesn't require subsetting, pass through unchanged.
256 257 258 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 256 def subset_name(_table) font.table_data["name"] end |
#subset_os2(_table) ⇒ String
Subset OS/2 table (optionally prune Unicode ranges)
If unicode_ranges option is set, updates Unicode range bits to reflect only the characters in the subset.
278 279 280 281 282 283 284 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 278 def subset_os2(_table) if .unicode_ranges # TODO: Implement Unicode range pruning # For now, pass through end font.table_data["OS/2"] end |
#subset_post(table) ⇒ String
Subset post table (optionally drop glyph names)
If drop_names option is set, converts to post version 3.0 (no glyph names). Otherwise passes through unchanged.
240 241 242 243 244 245 246 247 248 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 240 def subset_post(table) if .drop_names # Build post table version 3.0 (no glyph names) build_post_v3(table) else # Keep as-is font.table_data["post"] end end |
#subset_table(tag, table) ⇒ String
Subset a table by tag
Delegates to table-specific subsetting methods. Unknown tables are passed through unchanged.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/fontisan/subset/table_subsetter.rb', line 69 def subset_table(tag, table) case tag when "maxp" subset_maxp(table) when "hhea" subset_hhea(table) when "hmtx" subset_hmtx(table) when "loca" subset_loca(table) when "glyf" subset_glyf(table) when "cmap" subset_cmap(table) when "post" subset_post(table) when "name" subset_name(table) when "head" subset_head(table) when "OS/2" subset_os2(table) else # Unknown tables pass through unchanged font.table_data[tag] end end |