Class: TTFunk::TTFEncoder

Inherits:
Object
  • Object
show all
Defined in:
lib/ttfunk/ttf_encoder.rb

Overview

Encodes a TrueType font subset to its binary representation.

Direct Known Subclasses

OTFEncoder

Constant Summary collapse

OPTIMAL_TABLE_ORDER =

Optimal table order according to TrueType specification.

[
  'head', 'hhea', 'maxp', 'OS/2', 'hmtx', 'LTSH', 'VDMX',
  'hdmx', 'cmap', 'fpgm', 'prep', 'cvt ', 'loca', 'glyf',
  'kern', 'name', 'post', 'gasp', 'PCLT',
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(original, subset, options = {}) ⇒ TTFEncoder

Returns a new instance of TTFEncoder.

Parameters:

Options Hash (options):

  • :kerning (Boolean)

    whether to encode Kerning (‘kern`) table.



30
31
32
33
34
# File 'lib/ttfunk/ttf_encoder.rb', line 30

def initialize(original, subset, options = {})
  @original = original
  @subset = subset
  @options = options
end

Instance Attribute Details

#optionsHash (readonly)

Encoding options.

Returns:

  • (Hash)


23
24
25
# File 'lib/ttfunk/ttf_encoder.rb', line 23

def options
  @options
end

#originalTTFunk::File (readonly)

Original font.

Returns:



15
16
17
# File 'lib/ttfunk/ttf_encoder.rb', line 15

def original
  @original
end

#subsetTTFunk::Subset (readonly)

Subset to encode.

Returns:



19
20
21
# File 'lib/ttfunk/ttf_encoder.rb', line 19

def subset
  @subset
end

Instance Method Details

#encodeString

Encode the font subset.

Returns:

  • (String)


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ttfunk/ttf_encoder.rb', line 39

def encode
  # https://www.microsoft.com/typography/otspec/otff.htm#offsetTable
  search_range = (2**Math.log2(tables.length).floor) * 16
  entry_selector = Integer(Math.log2(2**Math.log2(tables.length).floor))
  range_shift = (tables.length * 16) - search_range
  range_shift = 0 if range_shift.negative?

  newfont = EncodedString.new

  newfont << [
    original.directory.scaler_type,
    tables.length,
    search_range,
    entry_selector,
    range_shift,
  ].pack('Nn*')

  # Tables are supposed to be listed in ascending order whereas there is a
  # known optimal order for table data.
  tables.keys.sort.each do |tag|
    newfont << [tag, checksum(tables[tag])].pack('A4N')
    newfont << Placeholder.new(tag, length: 4)
    newfont << [tables[tag].length].pack('N')
  end

  optimal_table_order.each do |optimal_tag|
    next unless tables.include?(optimal_tag)

    newfont.resolve_placeholder(optimal_tag, [newfont.length].pack('N'))
    newfont << tables[optimal_tag]
    newfont.align!(4)
  end

  sum = checksum(newfont)
  adjustment = 0xB1B0AFBA - sum
  newfont.resolve_placeholder(:checksum, [adjustment].pack('N'))

  newfont.string
end