ttfunk 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|