class HexaPDF::Font::TrueType::Subsetter
Subsets a TrueType
font in the context of PDF.
TrueType
fonts can be embedded into PDF either as a simple font or as a composite font. This subsetter implements the functionality needed when embedding a TrueType
subset for a composite font.
This means in particular that the resulting font file cannot be used outside of the PDF.
Public Class Methods
Public Instance Methods
Builds the subset font file and returns it as a binary string.
# File lib/hexapdf/font/true_type/subsetter.rb, line 85 def build_font glyf, locations = build_glyf_table loca = build_loca_table(locations) hmtx = build_hmtx_table head = build_head_table(modified: Time.now, loca_type: 1) hhea = build_hhea_table(@glyph_map.size) maxp = build_maxp_table(@glyph_map.size) tables = { 'head' => head, 'hhea' => hhea, 'maxp' => maxp, 'glyf' => glyf, 'loca' => loca, 'hmtx' => hmtx, } tables['cvt '] = @font[:"cvt "].raw_data if @font[:"cvt "] tables['fpgm'] = @font[:fpgm].raw_data if @font[:fpgm] tables['prep'] = @font[:prep].raw_data if @font[:prep] Builder.build(tables) end
Returns the new subset glyph ID for the given glyph ID, or nil
if the glyph isn't subset.
# File lib/hexapdf/font/true_type/subsetter.rb, line 80 def subset_glyph_id(glyph_id) @glyph_map[glyph_id] end
Includes the glyph with the given ID in the subset and returns the new subset glyph ID.
Can be called multiple times with the same glyph ID, always returning the correct new subset glyph ID.
# File lib/hexapdf/font/true_type/subsetter.rb, line 62 def use_glyph(glyph_id) return @glyph_map[glyph_id] if @glyph_map.key?(glyph_id) @last_id += 1 # Handle codes for ASCII characters \r (13), (, ) (40, 41) and \ (92) specially so that # they never appear in the output (PDF serialization would need to escape them) if @last_id == 13 || @last_id == 40 || @last_id == 92 @glyph_map[:"s#{@last_id}"] = @last_id if @last_id == 40 @last_id += 1 @glyph_map[:"s#{@last_id}"] = @last_id end @last_id += 1 end @glyph_map[glyph_id] = @last_id end
Private Instance Methods
Adds the components of compound glyphs to the subset.
# File lib/hexapdf/font/true_type/subsetter.rb, line 176 def add_glyph_components glyf = @font[:glyf] @glyph_map.keys.each do |gid| next if gid.kind_of?(Symbol) glyf[gid].components&.each {|cgid| use_glyph(cgid) } end end
Builds the glyf table.
# File lib/hexapdf/font/true_type/subsetter.rb, line 111 def build_glyf_table add_glyph_components orig_glyf = @font[:glyf] table = ''.b locations = [] @glyph_map.each_key do |old_gid| glyph = orig_glyf[old_gid.kind_of?(Symbol) ? 0 : old_gid] locations << table.size data = glyph.raw_data if glyph.compound? data = data.dup glyph.component_offsets.each_with_index do |offset, index| data[offset, 2] = [@glyph_map[glyph.components[index]]].pack('n') end end table << data end locations << table.size [table, locations] end
Builds the head table, adjusting the modification time and location table type.
# File lib/hexapdf/font/true_type/subsetter.rb, line 160 def build_head_table(modified:, loca_type:) data = @font[:head].raw_data data[8, 4] = "\0\0\0\0" data[28, 8] = [(modified - TrueType::Table::TIME_EPOCH).to_i].pack('q>') data[-4, 2] = [loca_type].pack('n') data end
Builds the hhea table, adjusting the value of the number of horizontal metrics.
# File lib/hexapdf/font/true_type/subsetter.rb, line 153 def build_hhea_table(num_of_long_hor_metrics) data = @font[:hhea].raw_data data[-2, 2] = [num_of_long_hor_metrics].pack('n') data end
Builds the hmtx table.
# File lib/hexapdf/font/true_type/subsetter.rb, line 142 def build_hmtx_table hmtx = @font[:hmtx] data = ''.b @glyph_map.each_key do |old_gid| metric = hmtx[old_gid.kind_of?(Symbol) ? 0 : old_gid] data << [metric.advance_width, metric.left_side_bearing].pack('n2') end data end
Builds the loca table given the locations.
# File lib/hexapdf/font/true_type/subsetter.rb, line 137 def build_loca_table(locations) locations.pack('N*') end
Builds the maxp table, adjusting the number of glyphs.
# File lib/hexapdf/font/true_type/subsetter.rb, line 169 def build_maxp_table(nr_of_glyphs) data = @font[:maxp].raw_data data[4, 2] = [nr_of_glyphs].pack('n') data end