ttfunk 1.7.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +74 -0
- data/README.md +17 -15
- data/lib/ttfunk/aggregate.rb +5 -0
- data/lib/ttfunk/bin_utils.rb +27 -8
- data/lib/ttfunk/bit_field.rb +25 -2
- data/lib/ttfunk/collection.rb +27 -3
- data/lib/ttfunk/directory.rb +7 -1
- data/lib/ttfunk/encoded_string.rb +58 -4
- data/lib/ttfunk/max.rb +14 -0
- data/lib/ttfunk/min.rb +14 -0
- data/lib/ttfunk/one_based_array.rb +20 -0
- data/lib/ttfunk/otf_encoder.rb +5 -14
- data/lib/ttfunk/placeholder.rb +15 -1
- data/lib/ttfunk/reader.rb +6 -4
- data/lib/ttfunk/resource_file.rb +29 -5
- data/lib/ttfunk/sci_form.rb +20 -3
- data/lib/ttfunk/sub_table.rb +29 -4
- data/lib/ttfunk/subset/base.rb +48 -0
- data/lib/ttfunk/subset/code_page.rb +49 -2
- data/lib/ttfunk/subset/mac_roman.rb +2 -0
- data/lib/ttfunk/subset/unicode.rb +32 -0
- data/lib/ttfunk/subset/unicode_8bit.rb +32 -0
- data/lib/ttfunk/subset/windows_1252.rb +2 -0
- data/lib/ttfunk/subset.rb +8 -0
- data/lib/ttfunk/subset_collection.rb +39 -14
- data/lib/ttfunk/sum.rb +13 -0
- data/lib/ttfunk/table/cff/charset.rb +96 -18
- data/lib/ttfunk/table/cff/charsets/expert.rb +3 -2
- data/lib/ttfunk/table/cff/charsets/expert_subset.rb +3 -2
- data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +3 -2
- data/lib/ttfunk/table/cff/charsets/standard_strings.rb +3 -2
- data/lib/ttfunk/table/cff/charsets.rb +1 -0
- data/lib/ttfunk/table/cff/charstring.rb +33 -12
- data/lib/ttfunk/table/cff/charstrings_index.rb +17 -11
- data/lib/ttfunk/table/cff/dict.rb +53 -23
- data/lib/ttfunk/table/cff/encoding.rb +82 -24
- data/lib/ttfunk/table/cff/encodings/expert.rb +3 -2
- data/lib/ttfunk/table/cff/encodings/standard.rb +3 -2
- data/lib/ttfunk/table/cff/encodings.rb +1 -0
- data/lib/ttfunk/table/cff/fd_selector.rb +61 -21
- data/lib/ttfunk/table/cff/font_dict.rb +30 -18
- data/lib/ttfunk/table/cff/font_index.rb +22 -10
- data/lib/ttfunk/table/cff/header.rb +16 -3
- data/lib/ttfunk/table/cff/index.rb +97 -65
- data/lib/ttfunk/table/cff/one_based_index.rb +11 -1
- data/lib/ttfunk/table/cff/path.rb +43 -4
- data/lib/ttfunk/table/cff/private_dict.rb +31 -11
- data/lib/ttfunk/table/cff/subr_index.rb +7 -2
- data/lib/ttfunk/table/cff/top_dict.rb +82 -59
- data/lib/ttfunk/table/cff/top_index.rb +10 -6
- data/lib/ttfunk/table/cff.rb +41 -21
- data/lib/ttfunk/table/cmap/format00.rb +27 -6
- data/lib/ttfunk/table/cmap/format04.rb +34 -14
- data/lib/ttfunk/table/cmap/format06.rb +28 -1
- data/lib/ttfunk/table/cmap/format10.rb +29 -2
- data/lib/ttfunk/table/cmap/format12.rb +29 -2
- data/lib/ttfunk/table/cmap/subtable.rb +50 -6
- data/lib/ttfunk/table/cmap.rb +21 -0
- data/lib/ttfunk/table/dsig.rb +47 -6
- data/lib/ttfunk/table/glyf/compound.rb +73 -6
- data/lib/ttfunk/table/glyf/path_based.rb +40 -3
- data/lib/ttfunk/table/glyf/simple.rb +50 -5
- data/lib/ttfunk/table/glyf.rb +15 -7
- data/lib/ttfunk/table/head.rb +84 -6
- data/lib/ttfunk/table/hhea.rb +71 -10
- data/lib/ttfunk/table/hmtx.rb +32 -5
- data/lib/ttfunk/table/kern/format0.rb +25 -7
- data/lib/ttfunk/table/kern.rb +16 -4
- data/lib/ttfunk/table/loca.rb +21 -8
- data/lib/ttfunk/table/maxp.rb +195 -10
- data/lib/ttfunk/table/name.rb +126 -9
- data/lib/ttfunk/table/os2.rb +150 -26
- data/lib/ttfunk/table/post/format10.rb +7 -0
- data/lib/ttfunk/table/post/format20.rb +9 -0
- data/lib/ttfunk/table/post/format30.rb +6 -0
- data/lib/ttfunk/table/post/format40.rb +5 -0
- data/lib/ttfunk/table/post.rb +63 -7
- data/lib/ttfunk/table/sbix.rb +50 -14
- data/lib/ttfunk/table/simple.rb +5 -0
- data/lib/ttfunk/table/vorg.rb +31 -3
- data/lib/ttfunk/table.rb +20 -1
- data/lib/ttfunk/ttf_encoder.rb +39 -41
- data/lib/ttfunk.rb +154 -1
- data.tar.gz.sig +0 -0
- metadata +50 -28
- metadata.gz.sig +0 -0
@@ -3,10 +3,30 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cmap
|
6
|
+
# Format 12: Segmented coverage.
|
7
|
+
#
|
8
|
+
# This module conditionally extends {TTFunk::Table::Cmap::Subtable}.
|
6
9
|
module Format12
|
10
|
+
# Language.
|
11
|
+
# @return [Integer]
|
7
12
|
attr_reader :language
|
13
|
+
|
14
|
+
# Code map.
|
15
|
+
# @return [Hash{Integer => Integer}]
|
8
16
|
attr_reader :code_map
|
9
17
|
|
18
|
+
# Encode the encoding record to format 12.
|
19
|
+
#
|
20
|
+
# @param charmap [Hash{Integer => Integer}] a hash mapping character
|
21
|
+
# codes to glyph IDs from the original font.
|
22
|
+
# @return [Hash]
|
23
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
|
24
|
+
# `charset`, values are hashes:
|
25
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
26
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
27
|
+
# that maps the characters in charmap to a
|
28
|
+
# * `:subtable` (<tt>String</tt>) - serialized encoding record.
|
29
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
|
10
30
|
def self.encode(charmap)
|
11
31
|
next_id = 0
|
12
32
|
glyph_map = { 0 => 0 }
|
@@ -32,23 +52,30 @@ module TTFunk
|
|
32
52
|
end
|
33
53
|
|
34
54
|
subtable = [
|
35
|
-
12, 0, 16 + 12 * range_lengths.size, 0, range_lengths.size
|
55
|
+
12, 0, 16 + (12 * range_lengths.size), 0, range_lengths.size,
|
36
56
|
].pack('nnNNN')
|
37
57
|
range_lengths.each_with_index do |length, i|
|
38
58
|
firstglyph = range_firstglyphs[i]
|
39
59
|
firstcode = range_firstcodes[i]
|
40
60
|
subtable << [
|
41
|
-
firstcode, firstcode + length - 1, firstglyph
|
61
|
+
firstcode, firstcode + length - 1, firstglyph,
|
42
62
|
].pack('NNN')
|
43
63
|
end
|
44
64
|
|
45
65
|
{ charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
|
46
66
|
end
|
47
67
|
|
68
|
+
# Get glyph ID for character code.
|
69
|
+
#
|
70
|
+
# @param code [Integer] character code.
|
71
|
+
# @return [Integer] glyph ID.
|
48
72
|
def [](code)
|
49
73
|
@code_map[code] || 0
|
50
74
|
end
|
51
75
|
|
76
|
+
# Is this encoding record format supported?
|
77
|
+
#
|
78
|
+
# @return [true]
|
52
79
|
def supported?
|
53
80
|
true
|
54
81
|
end
|
@@ -5,21 +5,54 @@ require_relative '../../reader'
|
|
5
5
|
module TTFunk
|
6
6
|
class Table
|
7
7
|
class Cmap
|
8
|
+
# Character to Glyph Index encoding record.
|
9
|
+
# This class can be extended with a format-specific
|
10
|
+
#
|
11
|
+
# @see TTFunk::Table::Cmap::Format00
|
12
|
+
# @see TTFunk::Table::Cmap::Format04
|
13
|
+
# @see TTFunk::Table::Cmap::Format06
|
14
|
+
# @see TTFunk::Table::Cmap::Format10
|
15
|
+
# @see TTFunk::Table::Cmap::Format12
|
8
16
|
class Subtable
|
9
17
|
include Reader
|
10
18
|
|
19
|
+
# Platform ID.
|
20
|
+
# @return [Integer]
|
11
21
|
attr_reader :platform_id
|
22
|
+
|
23
|
+
# Platform-specific encoding ID.
|
24
|
+
# @return [Integere]
|
12
25
|
attr_reader :encoding_id
|
26
|
+
|
27
|
+
# Record encoding format.
|
28
|
+
# @return [Integer]
|
13
29
|
attr_reader :format
|
14
30
|
|
31
|
+
# Most used encoding mappings.
|
15
32
|
ENCODING_MAPPINGS = {
|
16
33
|
mac_roman: { platform_id: 1, encoding_id: 0 }.freeze,
|
17
34
|
# Use microsoft unicode, instead of generic unicode, for optimal
|
18
35
|
# Windows support
|
19
36
|
unicode: { platform_id: 3, encoding_id: 1 }.freeze,
|
20
|
-
unicode_ucs4: { platform_id: 3, encoding_id: 10 }.freeze
|
37
|
+
unicode_ucs4: { platform_id: 3, encoding_id: 10 }.freeze,
|
21
38
|
}.freeze
|
22
39
|
|
40
|
+
# Encode encoding record.
|
41
|
+
#
|
42
|
+
# @param charmap [Hash{Integer => Integer}] keys are code points in the
|
43
|
+
# used encoding, values are Unicode code points.
|
44
|
+
# @param encoding [Symbol] - one of the encodign mapping in
|
45
|
+
# {ENCODING_MAPPINGS}
|
46
|
+
# @return [Hash]
|
47
|
+
# * `:platform_id` (<tt>Integer</tt>) - Platform ID of this encoding record.
|
48
|
+
# * `:encoding_id` (<tt>Integer</tt>) - Encodign ID of this encoding record.
|
49
|
+
# * `:subtable` (<tt>String</tt>) - encoded encoding record.
|
50
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in this encoding
|
51
|
+
# record.
|
52
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) - keys are codepoints in this
|
53
|
+
# encoding record, values are hashes:
|
54
|
+
# * `:new` - new glyph ID.
|
55
|
+
# * `:old` - glyph ID in the original font.
|
23
56
|
def self.encode(charmap, encoding)
|
24
57
|
case encoding
|
25
58
|
when :mac_roman
|
@@ -43,11 +76,13 @@ module TTFunk
|
|
43
76
|
mapping[:platform_id],
|
44
77
|
mapping[:encoding_id],
|
45
78
|
12,
|
46
|
-
result[:subtable]
|
47
|
-
].pack('nnNA*')
|
79
|
+
result[:subtable],
|
80
|
+
].pack('nnNA*'),
|
48
81
|
)
|
49
82
|
end
|
50
83
|
|
84
|
+
# @param file [TTFunk::File]
|
85
|
+
# @param table_start [Integer]
|
51
86
|
def initialize(file, table_start)
|
52
87
|
@file = file
|
53
88
|
@platform_id, @encoding_id, @offset = read(8, 'nnN')
|
@@ -68,16 +103,25 @@ module TTFunk
|
|
68
103
|
end
|
69
104
|
end
|
70
105
|
|
106
|
+
# Is this an encoding record for Unicode?
|
107
|
+
#
|
108
|
+
# @return [Boolean]
|
71
109
|
def unicode?
|
72
|
-
platform_id == 3 && (encoding_id == 1 || encoding_id == 10) &&
|
73
|
-
format != 0
|
74
|
-
platform_id.zero? && format != 0
|
110
|
+
(platform_id == 3 && (encoding_id == 1 || encoding_id == 10) && format != 0) ||
|
111
|
+
(platform_id.zero? && format != 0)
|
75
112
|
end
|
76
113
|
|
114
|
+
# Is this encoding record format supported?
|
115
|
+
#
|
116
|
+
# @return [Boolean]
|
77
117
|
def supported?
|
78
118
|
false
|
79
119
|
end
|
80
120
|
|
121
|
+
# Get glyph ID for character code.
|
122
|
+
#
|
123
|
+
# @param _code [Integer] character code.
|
124
|
+
# @return [Integer] glyph ID.
|
81
125
|
def [](_code)
|
82
126
|
raise NotImplementedError, "cmap format #{@format} is not supported"
|
83
127
|
end
|
data/lib/ttfunk/table/cmap.rb
CHANGED
@@ -2,10 +2,28 @@
|
|
2
2
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
|
+
# Character to Glyph Index Mapping (`cmap`) table.
|
5
6
|
class Cmap < Table
|
7
|
+
# Table version.
|
8
|
+
# @return [Integer]
|
6
9
|
attr_reader :version
|
10
|
+
|
11
|
+
# Encoding tables.
|
12
|
+
# @return [Array<TTFunk::Table::Cmap::Subtable>]
|
7
13
|
attr_reader :tables
|
8
14
|
|
15
|
+
# Encode table.
|
16
|
+
#
|
17
|
+
# @param charmap [Hash{Integer => Integer}]
|
18
|
+
# @param encoding [Symbol]
|
19
|
+
# @return [Hash]
|
20
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
|
21
|
+
# `charset`, values are hashes:
|
22
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
23
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
24
|
+
# that maps the characters in charmap to a
|
25
|
+
# * `:table` (<tt>String</tt>) - serialized table.
|
26
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
|
9
27
|
def self.encode(charmap, encoding)
|
10
28
|
result = Cmap::Subtable.encode(charmap, encoding)
|
11
29
|
|
@@ -14,6 +32,9 @@ module TTFunk
|
|
14
32
|
result
|
15
33
|
end
|
16
34
|
|
35
|
+
# Get Unicode encoding records.
|
36
|
+
#
|
37
|
+
# @return [Array<TTFunk::Table::Cmap::Subtable>]
|
17
38
|
def unicode
|
18
39
|
# Because most callers just call .first on the result, put tables with
|
19
40
|
# highest-number format first. Unsupported formats will be ignored.
|
data/lib/ttfunk/table/dsig.rb
CHANGED
@@ -2,10 +2,30 @@
|
|
2
2
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
|
+
# Digital Signature (`DSIG`) table.
|
5
6
|
class Dsig < Table
|
7
|
+
# Signature record.
|
6
8
|
class SignatureRecord
|
7
|
-
|
9
|
+
# Format of the signature.
|
10
|
+
# @return [Integer]
|
11
|
+
attr_reader :format
|
8
12
|
|
13
|
+
# Length of signature in bytes.
|
14
|
+
# @return [Integer]
|
15
|
+
attr_reader :length
|
16
|
+
|
17
|
+
# Offset to the signature block from the beginning of the table.
|
18
|
+
# @return [Integer]
|
19
|
+
attr_reader :offset
|
20
|
+
|
21
|
+
# Signature PKCS#7 packet.
|
22
|
+
# @return [String]
|
23
|
+
attr_reader :signature
|
24
|
+
|
25
|
+
# @param format [Integer]
|
26
|
+
# @param length [Integer]
|
27
|
+
# @param offset [Integer]
|
28
|
+
# @param signature [String]
|
9
29
|
def initialize(format, length, offset, signature)
|
10
30
|
@format = format
|
11
31
|
@length = length
|
@@ -14,10 +34,28 @@ module TTFunk
|
|
14
34
|
end
|
15
35
|
end
|
16
36
|
|
17
|
-
|
37
|
+
# Version umber of this table.
|
38
|
+
# @return [Integer]
|
39
|
+
attr_reader :version
|
40
|
+
|
41
|
+
# Permission flags.
|
42
|
+
# @return [Integer]
|
43
|
+
attr_reader :flags
|
44
|
+
|
45
|
+
# Signature records.
|
46
|
+
# @return [Array<SignatureRecord>]
|
47
|
+
attr_reader :signatures
|
18
48
|
|
49
|
+
# Table tag.
|
19
50
|
TAG = 'DSIG'
|
20
51
|
|
52
|
+
# Encode table.
|
53
|
+
#
|
54
|
+
# **Note**: all signatures will be lost. This encodes an empty table
|
55
|
+
# regardless whether the supplied table contains any signtaures or not.
|
56
|
+
#
|
57
|
+
# @param dsig [TTFunk::Table::Dsig]
|
58
|
+
# @return [String]
|
21
59
|
def self.encode(dsig)
|
22
60
|
return unless dsig
|
23
61
|
|
@@ -26,6 +64,9 @@ module TTFunk
|
|
26
64
|
[dsig.version, 0, 0].pack('Nnn')
|
27
65
|
end
|
28
66
|
|
67
|
+
# Table tag.
|
68
|
+
#
|
69
|
+
# @return [String]
|
29
70
|
def tag
|
30
71
|
TAG
|
31
72
|
end
|
@@ -36,16 +77,16 @@ module TTFunk
|
|
36
77
|
@version, num_signatures, @flags = read(8, 'Nnn')
|
37
78
|
|
38
79
|
@signatures =
|
39
|
-
Array.new(num_signatures)
|
80
|
+
Array.new(num_signatures) {
|
40
81
|
format, length, sig_offset = read(12, 'N3')
|
41
82
|
signature =
|
42
|
-
parse_from(offset + sig_offset)
|
83
|
+
parse_from(offset + sig_offset) {
|
43
84
|
_, _, sig_length = read(8, 'nnN')
|
44
85
|
read(sig_length, 'C*')
|
45
|
-
|
86
|
+
}
|
46
87
|
|
47
88
|
SignatureRecord.new(format, length, sig_offset, signature)
|
48
|
-
|
89
|
+
}
|
49
90
|
end
|
50
91
|
end
|
51
92
|
end
|
@@ -5,32 +5,92 @@ require_relative '../../reader'
|
|
5
5
|
module TTFunk
|
6
6
|
class Table
|
7
7
|
class Glyf
|
8
|
+
# Composite TrueType glyph.
|
8
9
|
class Compound
|
9
10
|
include Reader
|
10
11
|
|
12
|
+
# Flags bit 0: arg1 and arg2 are words.
|
11
13
|
ARG_1_AND_2_ARE_WORDS = 0x0001
|
14
|
+
|
15
|
+
# Flags bit 3: there is a simple scale for the component.
|
12
16
|
WE_HAVE_A_SCALE = 0x0008
|
17
|
+
|
18
|
+
# Flags bit 5: at least one more glyph after this one.
|
13
19
|
MORE_COMPONENTS = 0x0020
|
20
|
+
|
21
|
+
# Flags bit 6: the x direction will use a different scale from the
|
22
|
+
# y direction.
|
14
23
|
WE_HAVE_AN_X_AND_Y_SCALE = 0x0040
|
24
|
+
|
25
|
+
# Flags bit 7: there is a 2 by 2 transformation that will be used to
|
26
|
+
# scale the component.
|
15
27
|
WE_HAVE_A_TWO_BY_TWO = 0x0080
|
28
|
+
|
29
|
+
# Flags bit 8: following the last component are instructions for the
|
30
|
+
# composite character.
|
16
31
|
WE_HAVE_INSTRUCTIONS = 0x0100
|
17
32
|
|
18
|
-
|
33
|
+
# Glyph ID.
|
34
|
+
# @return [Integer]
|
35
|
+
attr_reader :id
|
36
|
+
|
37
|
+
# Binary serialization of this glyph.
|
38
|
+
# @return [String]
|
39
|
+
attr_reader :raw
|
40
|
+
|
41
|
+
# Number of contours in this glyph.
|
42
|
+
# @return [Integer]
|
19
43
|
attr_reader :number_of_contours
|
20
|
-
|
44
|
+
|
45
|
+
# Minimum x for coordinate.
|
46
|
+
# @return [Integer]
|
47
|
+
attr_reader :x_min
|
48
|
+
|
49
|
+
# Minimum y for coordinate.
|
50
|
+
# @return [Integer]
|
51
|
+
attr_reader :y_min
|
52
|
+
|
53
|
+
# Maximum x for coordinate.
|
54
|
+
# @return [Integer]
|
55
|
+
attr_reader :x_max
|
56
|
+
|
57
|
+
# Maximum y for coordinate.
|
58
|
+
# @return [Integer]
|
59
|
+
attr_reader :y_max
|
60
|
+
|
61
|
+
# IDs of compound glyphs.
|
21
62
|
attr_reader :glyph_ids
|
22
63
|
|
64
|
+
# Component glyph.
|
65
|
+
#
|
66
|
+
# @!attribute [rw] flags
|
67
|
+
# Component flag.
|
68
|
+
# @return [Integer]
|
69
|
+
# @!attribute [rw] glyph_index
|
70
|
+
# Glyph index of component.
|
71
|
+
# @return [Integer]
|
72
|
+
# @!attribute [rw] arg1
|
73
|
+
# x-offset for component or point number.
|
74
|
+
# @return [Integer]
|
75
|
+
# @!attribute [rw] arg2
|
76
|
+
# y-offset for component or point number.
|
77
|
+
# @return [Integer]
|
78
|
+
# @!attribute [rw] transform
|
79
|
+
# Transformation.
|
80
|
+
# @return []
|
23
81
|
Component = Struct.new(:flags, :glyph_index, :arg1, :arg2, :transform)
|
24
82
|
|
83
|
+
# @param id [Integer] glyph ID.
|
84
|
+
# @param raw [String]
|
25
85
|
def initialize(id, raw)
|
26
86
|
@id = id
|
27
87
|
@raw = raw
|
28
88
|
io = StringIO.new(raw)
|
29
89
|
|
30
90
|
@number_of_contours, @x_min, @y_min, @x_max, @y_max =
|
31
|
-
io.read(10).unpack('n*').map
|
91
|
+
io.read(10).unpack('n*').map { |i|
|
32
92
|
BinUtils.twos_comp_to_int(i, bit_width: 16)
|
33
|
-
|
93
|
+
}
|
34
94
|
|
35
95
|
# Because TTFunk only cares about glyphs insofar as they (1) provide
|
36
96
|
# a bounding box for each glyph, and (2) can be rewritten into a
|
@@ -48,9 +108,9 @@ module TTFunk
|
|
48
108
|
loop do
|
49
109
|
flags, glyph_id = @raw[offset, 4].unpack('n*')
|
50
110
|
@glyph_ids << glyph_id
|
51
|
-
@glyph_id_offsets << offset + 2
|
111
|
+
@glyph_id_offsets << (offset + 2)
|
52
112
|
|
53
|
-
break
|
113
|
+
break if (flags & MORE_COMPONENTS).zero?
|
54
114
|
|
55
115
|
offset += 4
|
56
116
|
|
@@ -71,10 +131,17 @@ module TTFunk
|
|
71
131
|
end
|
72
132
|
end
|
73
133
|
|
134
|
+
# Is this a composite glyph?
|
135
|
+
# @return [true]
|
74
136
|
def compound?
|
75
137
|
true
|
76
138
|
end
|
77
139
|
|
140
|
+
# Recode glyph.
|
141
|
+
#
|
142
|
+
# @param mapping [Hash{Integer => Integer}] a hash mapping old glyph IDs
|
143
|
+
# to new glyph IDs.
|
144
|
+
# @return [String]
|
78
145
|
def recode(mapping)
|
79
146
|
result = raw.dup
|
80
147
|
new_ids = glyph_ids.map { |id| mapping[id] }
|
@@ -3,11 +3,42 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Glyf
|
6
|
+
# TrueType-compatible representation of a CFF glyph.
|
6
7
|
class PathBased
|
7
|
-
|
8
|
-
|
9
|
-
attr_reader :
|
8
|
+
# Glyph outline.
|
9
|
+
# @return [TTFunk::Table::Cff::Path]
|
10
|
+
attr_reader :path
|
10
11
|
|
12
|
+
# Glyph horizontal metrics.
|
13
|
+
# @return [TTFunk::Table::Hmtx::HorizontalMetric]
|
14
|
+
attr_reader :horizontal_metrics
|
15
|
+
|
16
|
+
# Minimum X.
|
17
|
+
# @return [Integer, Float]
|
18
|
+
attr_reader :x_min
|
19
|
+
|
20
|
+
# Minimum Y.
|
21
|
+
# @return [Integer, Float]
|
22
|
+
attr_reader :y_min
|
23
|
+
|
24
|
+
# Maximum X.
|
25
|
+
# @return [Integer, Float]
|
26
|
+
attr_reader :x_max
|
27
|
+
|
28
|
+
# Maximum Y.
|
29
|
+
# @return [Integer, Float]
|
30
|
+
attr_reader :y_max
|
31
|
+
|
32
|
+
# Left side bearing.
|
33
|
+
# @return [Integer, Float]
|
34
|
+
attr_reader :left_side_bearing
|
35
|
+
|
36
|
+
# Rigth side bearing.
|
37
|
+
# @return [Integer, Float]
|
38
|
+
attr_reader :right_side_bearing
|
39
|
+
|
40
|
+
# @param path [TTFunk::Table::Cff::Path]
|
41
|
+
# @param horizontal_metrics [TTFunk::Table::Hmtx::HorizontalMetric]
|
11
42
|
def initialize(path, horizontal_metrics)
|
12
43
|
@path = path
|
13
44
|
@horizontal_metrics = horizontal_metrics
|
@@ -34,10 +65,16 @@ module TTFunk
|
|
34
65
|
(@x_max - @x_min)
|
35
66
|
end
|
36
67
|
|
68
|
+
# Number of contour.
|
69
|
+
#
|
70
|
+
# @return [Integer]
|
37
71
|
def number_of_contours
|
38
72
|
path.number_of_contours
|
39
73
|
end
|
40
74
|
|
75
|
+
# Is this glyph compound?
|
76
|
+
#
|
77
|
+
# @return [false]
|
41
78
|
def compound?
|
42
79
|
false
|
43
80
|
end
|
@@ -5,36 +5,81 @@ require_relative '../../reader'
|
|
5
5
|
module TTFunk
|
6
6
|
class Table
|
7
7
|
class Glyf
|
8
|
+
# Simple TrueType glyph
|
8
9
|
class Simple
|
9
|
-
|
10
|
+
# Glyph ID.
|
11
|
+
# @return [Integer]
|
12
|
+
attr_reader :id
|
13
|
+
|
14
|
+
# Binary serialization of this glyph.
|
15
|
+
# @return [String]
|
16
|
+
attr_reader :raw
|
17
|
+
|
18
|
+
# Number of contours in this glyph.
|
19
|
+
# @return [Integer]
|
10
20
|
attr_reader :number_of_contours
|
11
|
-
|
21
|
+
|
22
|
+
# Minimum x for coordinate.
|
23
|
+
# @return [Integer]
|
24
|
+
attr_reader :x_min
|
25
|
+
|
26
|
+
# Minimum y for coordinate.
|
27
|
+
# @return [Integer]
|
28
|
+
attr_reader :y_min
|
29
|
+
|
30
|
+
# Maximum x for coordinate.
|
31
|
+
# @return [Integer]
|
32
|
+
attr_reader :x_max
|
33
|
+
|
34
|
+
# Maximum y for coordinate.
|
35
|
+
# @return [Integer]
|
36
|
+
attr_reader :y_max
|
37
|
+
|
38
|
+
# Point indices for the last point of each contour.
|
39
|
+
# @return [Array<Integer>]
|
12
40
|
attr_reader :end_points_of_contours
|
13
|
-
attr_reader :instruction_length, :instructions
|
14
41
|
|
42
|
+
# Total number of bytes for instructions.
|
43
|
+
# @return [Integer]
|
44
|
+
attr_reader :instruction_length
|
45
|
+
|
46
|
+
# Instruction byte code.
|
47
|
+
# @return [Array<Integer>]
|
48
|
+
attr_reader :instructions
|
49
|
+
|
50
|
+
# @param id [Integer] glyph ID.
|
51
|
+
# @param raw [String]
|
15
52
|
def initialize(id, raw)
|
16
53
|
@id = id
|
17
54
|
@raw = raw
|
18
55
|
io = StringIO.new(raw)
|
19
56
|
|
20
57
|
@number_of_contours, @x_min, @y_min, @x_max, @y_max =
|
21
|
-
io.read(10).unpack('n*').map
|
58
|
+
io.read(10).unpack('n*').map { |i|
|
22
59
|
BinUtils.twos_comp_to_int(i, bit_width: 16)
|
23
|
-
|
60
|
+
}
|
24
61
|
|
25
62
|
@end_points_of_contours = io.read(number_of_contours * 2).unpack('n*')
|
26
63
|
@instruction_length = io.read(2).unpack1('n')
|
27
64
|
@instructions = io.read(instruction_length).unpack('C*')
|
28
65
|
end
|
29
66
|
|
67
|
+
# Is this glyph compound?
|
68
|
+
# @return [false]
|
30
69
|
def compound?
|
31
70
|
false
|
32
71
|
end
|
33
72
|
|
73
|
+
# Recode glyph.
|
74
|
+
#
|
75
|
+
# @param _mapping Unused, here for API compatibility.
|
76
|
+
# @return [String]
|
34
77
|
def recode(_mapping)
|
35
78
|
raw
|
36
79
|
end
|
37
80
|
|
81
|
+
# End point index of last contour.
|
82
|
+
# @return [Integer]
|
38
83
|
def end_point_of_last_contour
|
39
84
|
end_points_of_contours.last + 1
|
40
85
|
end
|
data/lib/ttfunk/table/glyf.rb
CHANGED
@@ -4,15 +4,18 @@ require_relative '../table'
|
|
4
4
|
|
5
5
|
module TTFunk
|
6
6
|
class Table
|
7
|
+
# Glyph Data (`glyf`) table.
|
7
8
|
class Glyf < Table
|
8
|
-
#
|
9
|
-
# mapping old glyph-ids to new glyph-ids.
|
9
|
+
# Encode table.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
11
|
+
# @param glyphs [Hash] a hash mapping (old) glyph-ids to glyph objects
|
12
|
+
# @param new_to_old [Hash{Integer => Integer}] a hash mapping new glyph
|
13
|
+
# IDs to glyph IDs in the original font.
|
14
|
+
# @param old_to_new [Hash{Integer => Integer}] a hash mapping old glyph
|
15
|
+
# IDs to new glyph IDs.
|
16
|
+
# @return [Hash]
|
17
|
+
# * `:table` (<tt>String</tt>) - encoded table.
|
18
|
+
# * `:offsets` (<tt>Array\<Integer></tt>) - glyph offsets in the table.
|
16
19
|
def self.encode(glyphs, new_to_old, old_to_new)
|
17
20
|
result = { table: +'', offsets: [] }
|
18
21
|
|
@@ -28,6 +31,11 @@ module TTFunk
|
|
28
31
|
result
|
29
32
|
end
|
30
33
|
|
34
|
+
# Get glyph by ID.
|
35
|
+
#
|
36
|
+
# @param glyph_id [Integer]
|
37
|
+
# @return [TTFunk::Table::Glyf::Simple, TTFunk::Table::Glyf::Compound,
|
38
|
+
# nil]
|
31
39
|
def for(glyph_id)
|
32
40
|
return @cache[glyph_id] if @cache.key?(glyph_id)
|
33
41
|
|