30
31
32
33
34
35
36
37
38
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
# File 'lib/ttfunk/subset/base.rb', line 30
def encode(options={})
cmap_table = new_cmap_table(options)
glyphs = collect_glyphs(original_glyph_ids)
old2new_glyph = cmap_table[:charmap].inject({ 0 => 0 }) { |map, (_, ids)| map[ids[:old]] = ids[:new]; map }
next_glyph_id = cmap_table[:max_glyph_id]
glyphs.keys.each do |old_id|
unless old2new_glyph.key?(old_id)
old2new_glyph[old_id] = next_glyph_id
next_glyph_id += 1
end
end
new2old_glyph = old2new_glyph.invert
glyf_table = TTFunk::Table::Glyf.encode(glyphs, new2old_glyph, old2new_glyph)
loca_table = TTFunk::Table::Loca.encode(glyf_table[:offsets])
hmtx_table = TTFunk::Table::Hmtx.encode(original.horizontal_metrics, new2old_glyph)
hhea_table = TTFunk::Table::Hhea.encode(original., hmtx_table)
maxp_table = TTFunk::Table::Maxp.encode(original.maximum_profile, old2new_glyph)
post_table = TTFunk::Table::Post.encode(original.postscript, new2old_glyph)
name_table = TTFunk::Table::Name.encode(original.name)
head_table = TTFunk::Table::Head.encode(original., loca_table)
os2_table = original.os2.raw
cvt_table = TTFunk::Table::Simple.new(original, "cvt ").raw
fpgm_table = TTFunk::Table::Simple.new(original, "fpgm").raw
prep_table = TTFunk::Table::Simple.new(original, "prep").raw
if options[:kerning]
kern_table = TTFunk::Table::Kern.encode(original.kerning, old2new_glyph)
end
tables = { 'cmap' => cmap_table[:table],
'glyf' => glyf_table[:table],
'loca' => loca_table[:table],
'kern' => kern_table,
'hmtx' => hmtx_table[:table],
'hhea' => hhea_table,
'maxp' => maxp_table,
'OS/2' => os2_table,
'post' => post_table,
'name' => name_table,
'head' => head_table,
'prep' => prep_table,
'fpgm' => fpgm_table,
'cvt ' => cvt_table }
tables.delete_if { |tag, table| table.nil? }
search_range = (Math.log(tables.length) / Math.log(2)).to_i * 16
entry_selector = (Math.log(search_range) / Math.log(2)).to_i
range_shift = tables.length * 16 - search_range
newfont = [original.directory.scaler_type, tables.length, search_range, entry_selector, range_shift].pack("Nn*")
directory_size = tables.length * 16
offset = newfont.length + directory_size
table_data = ""
head_offset = nil
tables.each do |tag, data|
newfont << [tag, checksum(data), offset, data.length].pack("A4N*")
table_data << data
head_offset = offset if tag == 'head'
offset += data.length
while offset % 4 != 0
offset += 1
table_data << "\0"
end
end
newfont << table_data
sum = checksum(newfont)
adjustment = 0xB1B0AFBA - sum
newfont[head_offset+8,4] = [adjustment].pack("N")
return newfont
end
|