class HexaPDF::Font::TrueType::Subsetter
This means in particular that the resulting font file cannot be used outside of the PDF.
composite font.
subsetter implements the functionality needed when embedding a TrueType subset for a
TrueType fonts can be embedded into PDF either as a simple font or as a composite font. This
Subsets a TrueType font in the context of PDF.
def add_glyph_components
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
def build_font
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
def build_glyf_table
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
def build_head_table(modified:, loca_type:)
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
def build_hhea_table(num_of_long_hor_metrics)
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
def build_hmtx_table
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
def build_loca_table(locations)
def build_loca_table(locations) locations.pack('N*') end
def build_maxp_table(nr_of_glyphs)
def build_maxp_table(nr_of_glyphs) data = @font[:maxp].raw_data data[4, 2] = [nr_of_glyphs].pack('n') data end
def initialize(font)
def initialize(font) @font = font @glyph_map = {0 => 0} @last_id = 0 end
def subset_glyph_id(glyph_id)
Returns the new subset glyph ID for the given glyph ID, or +nil+ if the glyph isn't
def subset_glyph_id(glyph_id) @glyph_map[glyph_id] end
def use_glyph(glyph_id)
Can be called multiple times with the same glyph ID, always returning the correct new
Includes the glyph with the given ID in the subset and returns the new subset glyph ID.
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