glyph_imager 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +17 -0
  5. data/Rakefile +53 -0
  6. data/VERSION +1 -0
  7. data/glyph_imager.gemspec +90 -0
  8. data/lib/glyph_imager.rb +102 -0
  9. data/test/fonts/DejaVuSerif.ttf +0 -0
  10. data/test/helper.rb +10 -0
  11. data/test/test_glyph_imager.rb +62 -0
  12. data/vendor/graphics_utf +157 -0
  13. data/vendor/ttf-ruby-0.1/AUTHORS +1 -0
  14. data/vendor/ttf-ruby-0.1/COPYING +340 -0
  15. data/vendor/ttf-ruby-0.1/README +49 -0
  16. data/vendor/ttf-ruby-0.1/TODO +23 -0
  17. data/vendor/ttf-ruby-0.1/VERSION +1 -0
  18. data/vendor/ttf-ruby-0.1/lib/ttf/datatypes.rb +189 -0
  19. data/vendor/ttf-ruby-0.1/lib/ttf/encodings.rb +140 -0
  20. data/vendor/ttf-ruby-0.1/lib/ttf/exceptions.rb +28 -0
  21. data/vendor/ttf-ruby-0.1/lib/ttf/font_loader.rb +290 -0
  22. data/vendor/ttf-ruby-0.1/lib/ttf/fontchunk.rb +77 -0
  23. data/vendor/ttf-ruby-0.1/lib/ttf/table/cmap.rb +408 -0
  24. data/vendor/ttf-ruby-0.1/lib/ttf/table/cvt.rb +49 -0
  25. data/vendor/ttf-ruby-0.1/lib/ttf/table/fpgm.rb +48 -0
  26. data/vendor/ttf-ruby-0.1/lib/ttf/table/gasp.rb +88 -0
  27. data/vendor/ttf-ruby-0.1/lib/ttf/table/glyf.rb +452 -0
  28. data/vendor/ttf-ruby-0.1/lib/ttf/table/head.rb +86 -0
  29. data/vendor/ttf-ruby-0.1/lib/ttf/table/hhea.rb +96 -0
  30. data/vendor/ttf-ruby-0.1/lib/ttf/table/hmtx.rb +98 -0
  31. data/vendor/ttf-ruby-0.1/lib/ttf/table/kern.rb +186 -0
  32. data/vendor/ttf-ruby-0.1/lib/ttf/table/loca.rb +75 -0
  33. data/vendor/ttf-ruby-0.1/lib/ttf/table/maxp.rb +81 -0
  34. data/vendor/ttf-ruby-0.1/lib/ttf/table/name.rb +222 -0
  35. data/vendor/ttf-ruby-0.1/lib/ttf/table/os2.rb +172 -0
  36. data/vendor/ttf-ruby-0.1/lib/ttf/table/post.rb +120 -0
  37. data/vendor/ttf-ruby-0.1/lib/ttf/table/prep.rb +27 -0
  38. data/vendor/ttf-ruby-0.1/lib/ttf/table/vhea.rb +45 -0
  39. data/vendor/ttf-ruby-0.1/lib/ttf/table/vmtx.rb +36 -0
  40. data/vendor/ttf-ruby-0.1/lib/ttf.rb +20 -0
  41. data/vendor/ttf-ruby-0.1/setup.rb +1558 -0
  42. data/vendor/ttf-ruby-0.1/tools/README +44 -0
  43. data/vendor/ttf-ruby-0.1/tools/ttfcairoglyphviewer +229 -0
  44. data/vendor/ttf-ruby-0.1/tools/ttfdump +396 -0
  45. data/vendor/ttf-ruby-0.1/tools/ttfglyph2svg +144 -0
  46. data/vendor/ttf-ruby-0.1/tools/ttfsubset +273 -0
  47. metadata +120 -0
@@ -0,0 +1,44 @@
1
+ This directory
2
+ ==============
3
+
4
+ This directory (tools/) contains tools based upon TTF/Ruby.
5
+
6
+ Note: TTF/Ruby does not need to be installed if you run those tools from
7
+ this directory.
8
+
9
+ ttfdump
10
+ =======
11
+
12
+ ttfdump is a command-line tool to extract informations about a font.
13
+
14
+ $ ruby ttfdump file.ttf # Display a summary about the font
15
+ $ ruby ttfdump file.ttf table # Display informations related to table table
16
+ $ ruby ttfdump file.ttf all # Display all informations (very verbose!)
17
+
18
+ ttfsubset
19
+ =========
20
+
21
+ ttfsubset is a tool which from a font and an input file generates a subset from
22
+ this font containing only characters in the input file. Maybe useful to embed a
23
+ lighter version of a font in a document or in an embedded system.
24
+
25
+ $ ruby ttfsubset file.ttf < input_file.txt
26
+
27
+ ttfcairoglyphviewer
28
+ ===================
29
+
30
+ ttfcairoglyphviewer renders a selected glyph using Ruby/GTK, Rcairo and
31
+ TTF/Ruby. It also displays markers for corner points, curve control points, and
32
+ implicit points.
33
+
34
+ $ ruby ttfcairoglyphviewer file.ttf -g glyph_id
35
+ $ ruby ttfcairoglyphviewer file.ttf -c a_character
36
+
37
+ ttfglyph2svg
38
+ ============
39
+
40
+ ttfglyph2svg prints to stdout a selected glyph in SVG format.
41
+
42
+ $ ruby ttfglyph2svg file.ttf -g glyph_id
43
+ $ ruby ttfglyph2svg file.ttf -c a_character
44
+
@@ -0,0 +1,229 @@
1
+ # ttfcairoglyphviewer
2
+ # Copyright (C) 2006 Mathieu Blondel
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ $LOAD_PATH.unshift("../lib/")
19
+
20
+ require 'gtk2'
21
+ require 'cairo'
22
+ require 'ttf'
23
+
24
+ class Cairo::Context
25
+
26
+ def draw_square(x, y)
27
+ rectangle(x-10, y-10, 20, 20)
28
+ set_source_rgb(255.0, 0.0, 0.0)
29
+ fill_preserve
30
+ set_line_join(Cairo::LINE_JOIN_ROUND)
31
+ set_line_width(1)
32
+ stroke
33
+ end
34
+
35
+ def draw_circle(x, y)
36
+ arc(x, y, 10, 0, 2 * Math::PI)
37
+ fill_preserve
38
+ set_line_join(Cairo::LINE_JOIN_ROUND)
39
+ set_line_width(1)
40
+ stroke
41
+ end
42
+
43
+ def draw_blue_circle(x, y)
44
+ set_source_rgb(0.0, 0.0, 255.0)
45
+ draw_circle(x, y)
46
+ end
47
+
48
+ def draw_green_circle(x, y)
49
+ set_source_rgb(0.0, 255.0, 0)
50
+ draw_circle(x, y)
51
+ end
52
+
53
+ def draw_markers(glyph)
54
+ i = 0
55
+ points = glyph.points
56
+ start_new_contour = true
57
+ while i < points.length
58
+ if start_new_contour
59
+ # The -y is needed because the directions of the y-axis
60
+ # with SVG and TrueType are opposed.
61
+ draw_square(points[i].abs_x, -(points[i].abs_y))
62
+ first_point = points[i]
63
+ end
64
+
65
+ if points[i].end_of_contour?
66
+ close_path
67
+ start_new_contour = true
68
+ i += 1
69
+ else
70
+ if points[i].on_curve? and points[i + 1].on_curve?
71
+ draw_square(points[i + 1].abs_x, -(points[i + 1].abs_y))
72
+
73
+ i += 1
74
+ else
75
+ if points[i + 1].end_of_contour?
76
+ # Close the contour
77
+ draw_blue_circle(points[i + 1].abs_x,
78
+ -(points[i + 1].abs_y))
79
+ i += 1
80
+ elsif points[i + 2].on_curve?
81
+ draw_blue_circle(points[i + 1].abs_x,
82
+ -(points[i + 1].abs_y))
83
+
84
+ draw_square(points[i + 2].abs_x,
85
+ -(points[i + 2].abs_y))
86
+ i += 2
87
+ else
88
+ # This is an implied on-curve point
89
+ impl_x = (points[i + 2].abs_x - points[i + 1].abs_x) / 2
90
+ impl_x += points[i + 1].abs_x
91
+ impl_y = (points[i + 2].abs_y - points[i + 1].abs_y) / 2
92
+ impl_y += points[i + 1].abs_y
93
+
94
+ draw_blue_circle(points[i + 1].abs_x,
95
+ -(points[i + 1].abs_y))
96
+ draw_green_circle(impl_x, -(impl_y))
97
+ i += 1
98
+ end
99
+ end
100
+
101
+ start_new_contour = false
102
+ end
103
+
104
+ end
105
+ end
106
+
107
+ def max_y(glyph)
108
+ max_y = 0
109
+ glyph.points.each do |pnt|
110
+ max_y = pnt.abs_y if pnt.abs_y > max_y
111
+ end
112
+ max_y
113
+ end
114
+
115
+ def draw_simple_glyph(glyph)
116
+ set_source_rgba(1.0, 1.0, 1.0)
117
+ paint
118
+ points = glyph.points
119
+
120
+ start_new_contour = true
121
+ i = 0
122
+
123
+ scale(0.25, 0.25)
124
+ translate(0, max_y(glyph) + 20)
125
+
126
+
127
+ # Obviously this could be optimized because almost the same
128
+ # while loop is used twice but I had troubles to draw markers
129
+ # and paths at the same time. FIXME!
130
+ while i < points.length
131
+ if start_new_contour
132
+ # The -y is needed because the directions of the y-axis
133
+ # with SVG and TrueType are opposed.
134
+ move_to(points[i].abs_x, -(points[i].abs_y))
135
+ first_point = points[i]
136
+ end
137
+
138
+ if points[i].end_of_contour?
139
+ close_path
140
+ start_new_contour = true
141
+ i += 1
142
+ else
143
+ if points[i].on_curve? and points[i + 1].on_curve?
144
+ line_to(points[i + 1].abs_x, -(points[i + 1].abs_y))
145
+
146
+ i += 1
147
+ else
148
+ if points[i + 1].end_of_contour?
149
+ # Close the contour
150
+ quad_to(points[i + 1].abs_x,
151
+ -(points[i + 1].abs_y),
152
+ first_point.abs_x,
153
+ -(first_point.abs_y))
154
+ i += 1
155
+ elsif points[i + 2].on_curve?
156
+ quad_to(points[i + 1].abs_x,
157
+ -(points[i + 1].abs_y),
158
+ points[i + 2].abs_x,
159
+ -(points[i + 2].abs_y))
160
+ i += 2
161
+ else
162
+ # This is an implied on-curve point
163
+ impl_x = (points[i + 2].abs_x - points[i + 1].abs_x) / 2
164
+ impl_x += points[i + 1].abs_x
165
+ impl_y = (points[i + 2].abs_y - points[i + 1].abs_y) / 2
166
+ impl_y += points[i + 1].abs_y
167
+
168
+ quad_to(points[i + 1].abs_x,
169
+ -(points[i + 1].abs_y),
170
+ impl_x,
171
+ -(impl_y))
172
+ i += 1
173
+ end
174
+ end
175
+
176
+ start_new_contour = false
177
+ end
178
+
179
+ end
180
+
181
+ set_source_rgb(0.0, 0.0, 0.0)
182
+ #fill_preserve
183
+ set_line_join(Cairo::LINE_JOIN_MITER)
184
+ set_line_width(4)
185
+
186
+ stroke
187
+
188
+ draw_markers(glyph)
189
+ end
190
+ end
191
+
192
+ font = Font::TTF::File.new(ARGV[0])
193
+
194
+ enc_tbl = font.get_table(:cmap).encoding_tables.find do |t|
195
+ t.class == Font::TTF::Table::Cmap::EncodingTable4
196
+ end
197
+
198
+ if ARGV[1] == "-g"
199
+ offs = font.get_table(:loca).glyph_offsets[ARGV[2].to_i]
200
+ glyph = font.get_table(:glyf).get_glyph_at_offset(offs)
201
+ elsif ARGV[1] == "-c"
202
+ char_code = ARGV[2].unpack("U")[0]
203
+ glyph = enc_tbl.get_glyph_for_unicode(char_code)
204
+ else
205
+ exit!
206
+ end
207
+
208
+ if glyph.composite?
209
+ puts "Composite glyph not supported yet"
210
+ exit!
211
+ end
212
+
213
+ Gtk.init
214
+ w = Gtk::Window.new.add(vb = Gtk::VBox.new)
215
+ vb.add(da = Gtk::DrawingArea.new)
216
+ da.set_size_request(300, 300)
217
+
218
+ da.signal_connect("expose-event") do |widget, event|
219
+ cr = widget.window.create_cairo_context
220
+ cr.draw_simple_glyph(glyph)
221
+ end
222
+
223
+ w.show_all
224
+
225
+ w.signal_connect("delete-event") do
226
+ Gtk.main_quit
227
+ end
228
+
229
+ Gtk.main
@@ -0,0 +1,396 @@
1
+ # ttfdump
2
+ # Copyright (C) 2006 Mathieu Blondel
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ $LOAD_PATH.unshift("../lib/")
19
+
20
+ require 'ttf'
21
+ require 'pp'
22
+
23
+ def title_box(title)
24
+ puts ""
25
+ bar = "-" * (title.length + 4)
26
+ puts bar
27
+ puts " " + title
28
+ puts "#{bar}\n\n"
29
+ end
30
+
31
+ def define(title, definition)
32
+ if definition.class == Float
33
+ puts "%s: %d" % [title, definition]
34
+ elsif definition.kind_of? Array
35
+ puts(title + ": " + definition.join(", "))
36
+ else
37
+ puts(title + ": " + definition.to_s)
38
+ end
39
+ end
40
+
41
+ def define_methods(obj, methods=nil)
42
+ methods = obj.class.instance_methods(false) if methods.nil?
43
+ methods = methods.find_all { |m| m !~ /=$/ and m != "dump" }
44
+ methods.sort.each do |meth|
45
+ define(meth, obj.send(meth))
46
+ end
47
+ end
48
+
49
+ def usage
50
+ puts "Usage:"
51
+ puts "ttfdump ttf_file [table]"
52
+ puts "Ex: ttfdump font.ttf name"
53
+ end
54
+
55
+ if ARGV.length == 0 or ["h", "-h", "help", "--help"].include? ARGV[0]
56
+ usage
57
+ exit!
58
+ else
59
+ ttf = Font::TTF::File.new(ARGV[0])
60
+ end
61
+
62
+ if ARGV.length == 1 or (ARGV.length == 2 and ARGV[1] == "all")
63
+ # General Informations
64
+ title_box("General informations")
65
+ define("File dumped", ARGV[0])
66
+
67
+
68
+ define("Version", ttf.version)
69
+ if ttf.tables_include? :name
70
+ name = ttf.get_table(:name)
71
+
72
+ fontname = name.name_records.find do |nr|
73
+ [Font::TTF::Table::Name::NameRecord::UNIQUE_FONT_IDENTIFIER,
74
+ Font::TTF::Table::Name::NameRecord::FONT_FAMILY_NAME,
75
+ Font::TTF::Table::Name::NameRecord::FULL_FONT_NAME,
76
+ Font::TTF::Table::Name::NameRecord::POSTSCRIPT_NAME].include? \
77
+ nr.name_id and (nr.unicode? or nr.roman?)
78
+ end
79
+
80
+ define("Font Name", fontname.utf8_str) unless fontname.nil?
81
+
82
+ fontcopyright = name.name_records.find do |nr|
83
+ nr.name_id == Font::TTF::Table::Name::NameRecord::COPYRIGHT_NOTICE \
84
+ and (nr.unicode? or nr.roman?)
85
+ end
86
+
87
+ define("Copyright", fontcopyright.utf8_str) unless fontcopyright.nil?
88
+ end
89
+ define("Number of tables", ttf.table_list.length)
90
+ define("Tables", "")
91
+ ttf.table_list.each_with_index do |key, i|
92
+ val = ttf.tables_infos[key.to_sym]
93
+ puts "%2u. %4s - checksum = 0x%08x, offset = 0x%08x, len = %9u \n" % \
94
+ [i, key, val[:checksum], val[:offset], val[:len]]
95
+ end
96
+ end
97
+
98
+ if ARGV.length == 2 and (ARGV[1] == "cmap" or ARGV[1] == "all") and
99
+ ttf.tables_include? :cmap
100
+ # Cmap
101
+ title_box("Character to Glyph mapping (cmap) table")
102
+ cmap = ttf.get_table(:cmap)
103
+ define("Version", cmap.version)
104
+ define("Number of encoding tables", cmap.encoding_tables.length)
105
+ define("Encoding tables summary", "")
106
+ tables = cmap.encoding_tables
107
+ tables.each_with_index do |tbl, i|
108
+ puts "%2u. format = %2u offset = 0x%08x, len = %d" %
109
+ [i, tbl.format, tbl.offset_from_table, tbl.len]
110
+ end
111
+ puts ""
112
+
113
+ tables.each_with_index do |tbl, i|
114
+ define("Encoding table", i)
115
+ define("Format", tbl.format)
116
+ define("Platform ID", tbl.platform_id)
117
+ define("Encoding ID", tbl.encoding_id)
118
+ define("Unicode?", tbl.unicode?)
119
+ define("Offset from table", "0x%08x" % tbl.offset_from_table)
120
+ define("Length", tbl.len)
121
+
122
+
123
+ if tbl.format == 0
124
+ define("Version", tbl.version)
125
+ puts ""
126
+ tbl.glyph_id_array.each_with_index do |glyph_index, char_code|
127
+ puts "Char %d -> Glyph Index %d" % [char_code, glyph_index]
128
+ end
129
+ elsif tbl.format == 4
130
+ define("Version", tbl.version)
131
+ define("Segment count", tbl.segments.length)
132
+ define("Search range", tbl.search_range)
133
+ define("Entry selector", tbl.entry_selector)
134
+ define("Range shift", tbl.range_shift)
135
+ puts ""
136
+ tbl.segments.length.times do |i|
137
+ puts \
138
+ "Segment %4d. start = %d, end = %d, delta = %d, range = %d" %
139
+ [i, tbl.start_count_array[i], tbl.end_count_array[i],
140
+ tbl.id_delta_array[i], tbl.id_range_offset_array[i]]
141
+ end
142
+ puts ""
143
+ if tbl.glyph_index_array.length > 0
144
+ define("Number of glyph indices", tbl.glyph_index_array.length)
145
+ tbl.glyph_index_array.each_with_index do |glyph_index, i|
146
+ puts "glyph_index_array[%d] = %d" % [i, glyph_index]
147
+ end
148
+ end
149
+ tbl.segments.each_with_index do |seg, i|
150
+ puts "Segment #{i.to_s}"
151
+ seg.keys.sort.each do |char_code|
152
+ glyph_index = seg[char_code]
153
+ puts "Char %d (%s) (%s)-> Glyph index %d" % \
154
+ [char_code, "0x%08x" % char_code, [char_code].pack("U"),
155
+ glyph_index]
156
+ end
157
+ puts ""
158
+ end
159
+ end
160
+ puts ""
161
+ end
162
+ end
163
+
164
+ if ARGV.length == 2 and (ARGV[1] == "cvt" or ARGV[1] == "all") and
165
+ ttf.tables_include? :cvt
166
+ # Cvt
167
+ title_box("Control Value table (cvt)")
168
+ cvt = ttf.get_table(:cvt)
169
+ cvt.instructions.each_with_index do |inst, i|
170
+ puts "Instruction %d: %d" % [i, inst]
171
+ end
172
+ end
173
+
174
+ if ARGV.length == 2 and (ARGV[1] == "gasp" or ARGV[1] == "all") and
175
+ ttf.tables_include? :gasp
176
+ # gasp
177
+ title_box("Grid-fitting and scan-conversion procedure (gasp)")
178
+ gasp = ttf.get_table(:gasp)
179
+ gasp.gasp_ranges.each_with_index do |gr, i|
180
+ define("Gasp range", i)
181
+ define("Range max ppem", gr.range_max_ppem)
182
+ define("Range gasp behavior", gr.range_gasp_behavior)
183
+ puts ""
184
+ end
185
+ end
186
+
187
+ if ARGV.length == 2 and (ARGV[1] == "glyf" or ARGV[1] == "all") and
188
+ ttf.tables_include? :glyf
189
+ # glyf
190
+ title_box("Glyph data (glyf)")
191
+ glyf = ttf.get_table(:glyf)
192
+ i = 0
193
+ glyf.each_glyph do |glyph|
194
+ define("Glyph index", i)
195
+ define("Glyph type", glyph.class.to_s)
196
+ if glyph.simple?
197
+ methods = glyph.class.instance_methods(false) + \
198
+ glyph.class.superclass.instance_methods(false)
199
+ define_methods(glyph, methods)
200
+ else
201
+ methods = glyph.class.superclass.instance_methods(false)
202
+ define_methods(glyph, methods)
203
+ print("Glyph components: ")
204
+ pp glyph.components
205
+ end
206
+ puts ""
207
+ i += 1
208
+ end
209
+ end
210
+
211
+ if ARGV.length == 4 and ARGV[1] == "glyf" and
212
+ ttf.tables_include? :glyf
213
+ # glyf
214
+ title_box("Glyph data (glyf)")
215
+ glyf = ttf.get_table(:glyf)
216
+
217
+ enc_tbl = ttf.get_table(:cmap).encoding_tables.find do |t|
218
+ t.class == Font::TTF::Table::Cmap::EncodingTable4
219
+ end
220
+
221
+ if ARGV[2] == "-g"
222
+ offs = ttf.get_table(:loca).glyph_offsets[ARGV[3].to_i]
223
+ glyph = glyf.get_glyph_at_offset(offs)
224
+ elsif ARGV[2] == "-c"
225
+ char_code = ARGV[3].unpack("U")[0]
226
+ glyph = enc_tbl.get_glyph_for_unicode(char_code)
227
+ elsif ARGV[2] == "-o"
228
+ glyph = glyf.get_glyph_at_offset(ARGV[3].hex)
229
+ else
230
+ exit!
231
+ end
232
+
233
+ define("Glyph type", glyph.class.to_s)
234
+ if glyph.simple?
235
+ methods = glyph.class.instance_methods(false) + \
236
+ glyph.class.superclass.instance_methods(false)
237
+ define_methods(glyph, methods)
238
+ else
239
+ methods = glyph.class.superclass.instance_methods(false)
240
+ define_methods(glyph, methods)
241
+ print("Glyph components: ")
242
+ pp glyph.components
243
+ end
244
+ puts ""
245
+ end
246
+
247
+ if ARGV.length == 2 and (ARGV[1] == "head" or ARGV[1] == "all") and
248
+ ttf.tables_include? :head
249
+ # Head
250
+ title_box("Head table")
251
+ head = ttf.get_table(:head)
252
+ define_methods(head)
253
+ end
254
+
255
+ if ARGV.length == 2 and (ARGV[1] == "hhea" or ARGV[1] == "all") and
256
+ ttf.tables_include? :hhea
257
+ # Hhea
258
+ title_box("Horizontal header table")
259
+ hhea = ttf.get_table(:hhea)
260
+ methods = ["version", "ascender", "descender", "line_gap",
261
+ "advance_width_max", "min_left_side_bearing",
262
+ "min_right_side_bearing", "x_max_extent",
263
+ "caret_slope_rise", "caret_slope_run",
264
+ "metric_data_format", "number_of_hmetrics"]
265
+ define_methods(hhea, methods)
266
+ end
267
+
268
+ if ARGV.length == 2 and (ARGV[1] == "hmtx" or ARGV[1] == "all") and
269
+ ttf.tables_include? :hmtx
270
+ # Hmtx
271
+ title_box("Horizontal metrics table")
272
+ hmtx = ttf.get_table(:hmtx)
273
+ hmetrics = hmtx.hmetrics
274
+ define("Number of Hmetrics", hmetrics.length)
275
+
276
+ define("Hmetrics", "")
277
+ hmetrics.each_with_index do |hmetric, i|
278
+ puts "%2u. advanced width = %5u, left side bearing = %5d" % \
279
+ [i, hmetric[0], hmetric[1]]
280
+ end
281
+ end
282
+
283
+ if ARGV.length == 2 and (ARGV[1] == "kern" or ARGV[1] == "all") and
284
+ ttf.tables_include? :kern
285
+ # Kern
286
+ title_box("Kerning (kern)")
287
+ kern = ttf.get_table(:kern)
288
+ kern.subtables.each do |subtbl|
289
+ if subtbl.format == 0
290
+ subtbl.kerning_pairs.each do |kp|
291
+ puts "left = %5d, right = %5d, value = %5d" % \
292
+ [kp.left, kp.right, kp.value]
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ if ARGV.length == 2 and (ARGV[1] == "loca" or ARGV[1] == "all") and
299
+ ttf.tables_include? :loca
300
+ # Loca
301
+ title_box("Index to location table (loca)")
302
+ loca = ttf.get_table(:loca)
303
+ loca.glyph_offsets.each_with_index do |off, i|
304
+ puts "Glyph index %6d -> Offset 0x%08x" % [i, off]
305
+ end
306
+ end
307
+
308
+ if ARGV.length == 2 and (ARGV[1] == "maxp" or ARGV[1] == "all") and
309
+ ttf.tables_include? :maxp
310
+ # Maxp
311
+ title_box("Max Profile table")
312
+ maxp = ttf.get_table(:maxp)
313
+ define_methods(maxp)
314
+ end
315
+
316
+ if ARGV.length == 2 and (ARGV[1] == "name" or ARGV[1] == "all") and
317
+ ttf.tables_include? :name
318
+ # Name
319
+ title_box("Name table")
320
+ name = ttf.get_table(:name)
321
+ define("Number of name records", name.name_records.length)
322
+ name.name_records.each_with_index do |nr, i|
323
+ define("Name record number", i)
324
+ define("Platform id", "%d (%s)" % [nr.platform_id,
325
+ Font::TTF::Encodings::Platform::ID2NAME[nr.platform_id]])
326
+
327
+ if nr.platform_id == \
328
+ Font::TTF::Encodings::Platform::MICROSOFT
329
+ define("Encoding id", "%d (%s)" % [nr.encoding_id,
330
+ Font::TTF::Encodings::MicrosoftEncoding::ID2NAME[nr.encoding_id]])
331
+ elsif nr.platform_id == \
332
+ Font::TTF::Encodings::Platform::MACINTOSH
333
+ define("Encoding id", "%d (%s)" % [nr.encoding_id,
334
+ Font::TTF::Encodings::MacintoshEncoding::ID2NAME[nr.encoding_id]])
335
+ end
336
+
337
+ define("Language id", nr.language_id)
338
+ define("Name id", "%d (%s)" % [nr.name_id,
339
+ Font::TTF::Table::Name::NameRecord::ID2NAME[nr.name_id]])
340
+ define("String length", nr.to_s.length)
341
+ define("String offset", nr.str_offset)
342
+ define("String value", nr.utf8_str)
343
+ puts ""
344
+ end
345
+ end
346
+
347
+ if ARGV.length == 2 and (ARGV[1] == "os2" or ARGV[1] == "all") and
348
+ ttf.tables_include? :"OS/2"
349
+ # Post
350
+ title_box("OS/2 and Windows metrics")
351
+ os2 = ttf.get_table(:"OS/2")
352
+ define_methods(os2)
353
+ end
354
+
355
+ if ARGV.length == 2 and (ARGV[1] == "post" or ARGV[1] == "all") and
356
+ ttf.tables_include? :post
357
+ # Post
358
+ title_box("Postscript (post)")
359
+ post = ttf.get_table(:post)
360
+ methods = %w[format_type italic_angle underline_position
361
+ underline_thickness is_fixed_pitch
362
+ min_mem_type_42 max_mem_type_42
363
+ min_mem_type_1 max_mem_type_1]
364
+ define_methods(post, methods)
365
+ post.names.each_with_index do |name, i|
366
+ puts "Glyph %6d: %s (postscript id: %d)" % [i, name.str, name.id]
367
+ end
368
+ end
369
+
370
+ if ARGV.length == 2 and (ARGV[1] == "vhea" or ARGV[1] == "all") and
371
+ ttf.tables_include? :vhea
372
+ # Vhea
373
+ title_box("Vertical header table")
374
+ vhea = ttf.get_table(:vhea)
375
+ methods = ["version", "ascender", "descender", "line_gap",
376
+ "advance_height_max", "min_top_side_bearing",
377
+ "min_bottom_side_bearing", "y_max_extent",
378
+ "caret_slope_rise", "caret_slope_run",
379
+ "metric_data_format", "number_of_vmetrics"]
380
+ define_methods(vhea, methods)
381
+ end
382
+
383
+ if ARGV.length == 2 and (ARGV[1] == "vmtx" or ARGV[1] == "all") and
384
+ ttf.tables_include? :vmtx
385
+ # Vmtx
386
+ title_box("Vertical metrics table")
387
+ vmtx = ttf.get_table(:vmtx)
388
+ vmetrics = vmtx.vmetrics
389
+ define("Number of Vmetrics", vmetrics.length)
390
+
391
+ define("Vmetrics", "")
392
+ vmetrics.each_with_index do |vmetric, i|
393
+ puts "%2u. advanced width = %5u, top side bearing = %5d" % \
394
+ [i, vmetric[0], vmetric[1]]
395
+ end
396
+ end