ttfunk 1.7.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +74 -0
  4. data/README.md +17 -15
  5. data/lib/ttfunk/aggregate.rb +5 -0
  6. data/lib/ttfunk/bin_utils.rb +27 -8
  7. data/lib/ttfunk/bit_field.rb +25 -2
  8. data/lib/ttfunk/collection.rb +27 -3
  9. data/lib/ttfunk/directory.rb +7 -1
  10. data/lib/ttfunk/encoded_string.rb +58 -4
  11. data/lib/ttfunk/max.rb +14 -0
  12. data/lib/ttfunk/min.rb +14 -0
  13. data/lib/ttfunk/one_based_array.rb +20 -0
  14. data/lib/ttfunk/otf_encoder.rb +5 -14
  15. data/lib/ttfunk/placeholder.rb +15 -1
  16. data/lib/ttfunk/reader.rb +6 -4
  17. data/lib/ttfunk/resource_file.rb +29 -5
  18. data/lib/ttfunk/sci_form.rb +20 -3
  19. data/lib/ttfunk/sub_table.rb +29 -4
  20. data/lib/ttfunk/subset/base.rb +48 -0
  21. data/lib/ttfunk/subset/code_page.rb +49 -2
  22. data/lib/ttfunk/subset/mac_roman.rb +2 -0
  23. data/lib/ttfunk/subset/unicode.rb +32 -0
  24. data/lib/ttfunk/subset/unicode_8bit.rb +32 -0
  25. data/lib/ttfunk/subset/windows_1252.rb +2 -0
  26. data/lib/ttfunk/subset.rb +8 -0
  27. data/lib/ttfunk/subset_collection.rb +39 -14
  28. data/lib/ttfunk/sum.rb +13 -0
  29. data/lib/ttfunk/table/cff/charset.rb +96 -18
  30. data/lib/ttfunk/table/cff/charsets/expert.rb +3 -2
  31. data/lib/ttfunk/table/cff/charsets/expert_subset.rb +3 -2
  32. data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +3 -2
  33. data/lib/ttfunk/table/cff/charsets/standard_strings.rb +3 -2
  34. data/lib/ttfunk/table/cff/charsets.rb +1 -0
  35. data/lib/ttfunk/table/cff/charstring.rb +33 -12
  36. data/lib/ttfunk/table/cff/charstrings_index.rb +17 -11
  37. data/lib/ttfunk/table/cff/dict.rb +53 -23
  38. data/lib/ttfunk/table/cff/encoding.rb +82 -24
  39. data/lib/ttfunk/table/cff/encodings/expert.rb +3 -2
  40. data/lib/ttfunk/table/cff/encodings/standard.rb +3 -2
  41. data/lib/ttfunk/table/cff/encodings.rb +1 -0
  42. data/lib/ttfunk/table/cff/fd_selector.rb +61 -21
  43. data/lib/ttfunk/table/cff/font_dict.rb +30 -18
  44. data/lib/ttfunk/table/cff/font_index.rb +22 -10
  45. data/lib/ttfunk/table/cff/header.rb +16 -3
  46. data/lib/ttfunk/table/cff/index.rb +97 -65
  47. data/lib/ttfunk/table/cff/one_based_index.rb +11 -1
  48. data/lib/ttfunk/table/cff/path.rb +43 -4
  49. data/lib/ttfunk/table/cff/private_dict.rb +31 -11
  50. data/lib/ttfunk/table/cff/subr_index.rb +7 -2
  51. data/lib/ttfunk/table/cff/top_dict.rb +82 -59
  52. data/lib/ttfunk/table/cff/top_index.rb +10 -6
  53. data/lib/ttfunk/table/cff.rb +41 -21
  54. data/lib/ttfunk/table/cmap/format00.rb +27 -6
  55. data/lib/ttfunk/table/cmap/format04.rb +34 -14
  56. data/lib/ttfunk/table/cmap/format06.rb +28 -1
  57. data/lib/ttfunk/table/cmap/format10.rb +29 -2
  58. data/lib/ttfunk/table/cmap/format12.rb +29 -2
  59. data/lib/ttfunk/table/cmap/subtable.rb +50 -6
  60. data/lib/ttfunk/table/cmap.rb +21 -0
  61. data/lib/ttfunk/table/dsig.rb +47 -6
  62. data/lib/ttfunk/table/glyf/compound.rb +73 -6
  63. data/lib/ttfunk/table/glyf/path_based.rb +40 -3
  64. data/lib/ttfunk/table/glyf/simple.rb +50 -5
  65. data/lib/ttfunk/table/glyf.rb +15 -7
  66. data/lib/ttfunk/table/head.rb +84 -6
  67. data/lib/ttfunk/table/hhea.rb +71 -10
  68. data/lib/ttfunk/table/hmtx.rb +32 -5
  69. data/lib/ttfunk/table/kern/format0.rb +25 -7
  70. data/lib/ttfunk/table/kern.rb +16 -4
  71. data/lib/ttfunk/table/loca.rb +21 -8
  72. data/lib/ttfunk/table/maxp.rb +195 -10
  73. data/lib/ttfunk/table/name.rb +126 -9
  74. data/lib/ttfunk/table/os2.rb +150 -26
  75. data/lib/ttfunk/table/post/format10.rb +7 -0
  76. data/lib/ttfunk/table/post/format20.rb +9 -0
  77. data/lib/ttfunk/table/post/format30.rb +6 -0
  78. data/lib/ttfunk/table/post/format40.rb +5 -0
  79. data/lib/ttfunk/table/post.rb +63 -7
  80. data/lib/ttfunk/table/sbix.rb +50 -14
  81. data/lib/ttfunk/table/simple.rb +5 -0
  82. data/lib/ttfunk/table/vorg.rb +31 -3
  83. data/lib/ttfunk/table.rb +20 -1
  84. data/lib/ttfunk/ttf_encoder.rb +39 -41
  85. data/lib/ttfunk.rb +154 -1
  86. data.tar.gz.sig +0 -0
  87. metadata +50 -28
  88. metadata.gz.sig +0 -0
@@ -5,44 +5,147 @@ require 'set'
5
5
 
6
6
  module TTFunk
7
7
  class Table
8
+ # OS/2 and Windows Metrics (`OS/2`) table
8
9
  class OS2 < Table
10
+ # Table version.
11
+ # @return [Integer]
9
12
  attr_reader :version
10
13
 
14
+ # Average weighted escapement.
15
+ # @return [Integer]
11
16
  attr_reader :ave_char_width
17
+
18
+ # Weight class.
19
+ # @return [Integer]
12
20
  attr_reader :weight_class
21
+
22
+ # Width class.
23
+ # @return [Integer]
13
24
  attr_reader :width_class
25
+
26
+ # Type flags.
27
+ # @return [Integer]
14
28
  attr_reader :type
29
+
30
+ # Subscript horizontal font size.
31
+ # @return [Integer]
15
32
  attr_reader :y_subscript_x_size
33
+
34
+ # Subscript vertical font size.
35
+ # @return [Integer]
16
36
  attr_reader :y_subscript_y_size
37
+
38
+ # Subscript x offset.
39
+ # @return [Integer]
17
40
  attr_reader :y_subscript_x_offset
41
+
42
+ # Subscript y offset.
43
+ # @return [Integer]
18
44
  attr_reader :y_subscript_y_offset
45
+
46
+ # Superscript horizontal font size.
47
+ # @return [Integer]
19
48
  attr_reader :y_superscript_x_size
49
+
50
+ # Superscript vertical font size.
51
+ # @return [Integer]
20
52
  attr_reader :y_superscript_y_size
53
+
54
+ # Superscript x offset.
55
+ # @return [Integer]
21
56
  attr_reader :y_superscript_x_offset
57
+
58
+ # Superscript y offset.
59
+ # @return [Integer]
22
60
  attr_reader :y_superscript_y_offset
61
+
62
+ # Strikeout size.
63
+ # @return [Integer]
23
64
  attr_reader :y_strikeout_size
65
+
66
+ # Strikeout position.
67
+ # @return [Integer]
24
68
  attr_reader :y_strikeout_position
69
+
70
+ # Font-family class and subclass.
71
+ # @return [Integer]
25
72
  attr_reader :family_class
73
+
74
+ # PANOSE classification number.
75
+ # @return [Integer]
26
76
  attr_reader :panose
77
+
78
+ # Unicode Character Range.
79
+ # @return [Integer]
27
80
  attr_reader :char_range
81
+
82
+ # Font Vendor Identification.
83
+ # @return [String]
28
84
  attr_reader :vendor_id
85
+
86
+ # Font selection flags.
87
+ # @return [Integer]
29
88
  attr_reader :selection
89
+
90
+ # The minimum Unicode index (character code) in this font.
91
+ # @return [Integer]
30
92
  attr_reader :first_char_index
93
+
94
+ # The maximum Unicode index (character code) in this font.
95
+ # @return [Integer]
31
96
  attr_reader :last_char_index
32
97
 
98
+ # The typographic ascender for this font.
99
+ # @return [Integer]
33
100
  attr_reader :ascent
101
+
102
+ # The typographic descender for this font.
103
+ # @return [Integer]
34
104
  attr_reader :descent
105
+
106
+ # The typographic line gap for this font.
107
+ # @return [Integer]
35
108
  attr_reader :line_gap
109
+
110
+ # The "Windows ascender" metric.
111
+ # @return [Integer]
36
112
  attr_reader :win_ascent
113
+
114
+ # The "Windows descender" metric.
115
+ # @return [Integer]
37
116
  attr_reader :win_descent
117
+
118
+ # Code Page Character Range.
119
+ # @return [Integer]
38
120
  attr_reader :code_page_range
39
121
 
122
+ # The distance between the baseline and the approximate height of
123
+ # non-ascending lowercase letters.
124
+ # @return [Integer]
40
125
  attr_reader :x_height
126
+
127
+ # The distance between the baseline and the approximate height of
128
+ # uppercase letters.
129
+ # @return [Integer]
41
130
  attr_reader :cap_height
131
+
132
+ # The Unicode code point, in UTF-16 encoding, of a character that can be
133
+ # used for a default glyph if a requested character is not supported in
134
+ # the font.
135
+ # @return [Integer]
42
136
  attr_reader :default_char
137
+
138
+ # The Unicode code point, in UTF-16 encoding, of a character that can be
139
+ # used as a default break character.
140
+ # @return [Integer]
43
141
  attr_reader :break_char
142
+
143
+ # The maximum length of a target glyph context for any feature in this
144
+ # font.
145
+ # @return [Integer]
44
146
  attr_reader :max_context
45
147
 
148
+ # Code page bits.
46
149
  CODE_PAGE_BITS = {
47
150
  1252 => 0,
48
151
  1250 => 1,
@@ -75,9 +178,10 @@ module TTFunk
75
178
  737 => 60,
76
179
  708 => 61,
77
180
  850 => 62,
78
- 437 => 63
181
+ 437 => 63,
79
182
  }.freeze
80
183
 
184
+ # Unicode blocks.
81
185
  UNICODE_BLOCKS = {
82
186
  (0x0000..0x007F) => 0,
83
187
  (0x0080..0x00FF) => 1,
@@ -247,17 +351,29 @@ module TTFunk
247
351
  (0x10280..0x1029F) => 121,
248
352
  (0x10920..0x1093F) => 121,
249
353
  (0x1F030..0x1F09F) => 122,
250
- (0x1F000..0x1F02F) => 122
354
+ (0x1F000..0x1F02F) => 122,
251
355
  }.freeze
252
356
 
357
+ # Indicates that font supports supplementary characters.
253
358
  UNICODE_MAX = 0xFFFF
254
- UNICODE_RANGES = UNICODE_BLOCKS.keys.freeze
359
+
360
+ # Unicode block ranges.
361
+ UNICODE_RANGES = UNICODE_BLOCKS.keys.sort_by(&:max).freeze
362
+
363
+ # Start chracter for average character width calculation.
255
364
  LOWERCASE_START = 'a'.ord
365
+
366
+ # End chracter for average character width calculation.
256
367
  LOWERCASE_END = 'z'.ord
368
+
369
+ # Number of chracters for average character width calculation.
257
370
  LOWERCASE_COUNT = (LOWERCASE_END - LOWERCASE_START) + 1
371
+
372
+ # Space character code point.
258
373
  CODEPOINT_SPACE = 32
259
- SPACE_GLYPH_MISSING_ERROR = "Space glyph (0x#{CODEPOINT_SPACE.to_s(16)})"\
260
- ' must be included in the font'
374
+
375
+ # Error message for missing space character.
376
+ SPACE_GLYPH_MISSING_ERROR = "Space glyph (0x#{CODEPOINT_SPACE.to_s(16)}) must be included in the font"
261
377
 
262
378
  # Used to calculate the xAvgCharWidth field.
263
379
  # From https://docs.microsoft.com/en-us/typography/opentype/spec/os2:
@@ -272,16 +388,26 @@ module TTFunk
272
388
  # 26 letters in the Latin alphabet. Each weight is the relative
273
389
  # frequency of that letter in the English language.
274
390
  WEIGHT_SPACE = 166
391
+
392
+ # chracter weights for average character width calculation.
275
393
  WEIGHT_LOWERCASE = [
276
394
  64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20,
277
- 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2
395
+ 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2,
278
396
  ].freeze
279
397
 
398
+ # Table tag.
399
+ # @return [String]
280
400
  def tag
281
401
  'OS/2'
282
402
  end
283
403
 
284
404
  class << self
405
+ # Encode table.
406
+ #
407
+ # @param os2 [TTFunk::Table::OS2]
408
+ # @param subset [TTFunk::Subset::MacRoman, TTFunk::Subset::Windows1252,
409
+ # TTFunk::Subset::Unicode, TTFunk::Subset::Unicode8Bit]
410
+ # @return [String]
285
411
  def encode(os2, subset)
286
412
  result = ''.b
287
413
  result << [
@@ -291,7 +417,7 @@ module TTFunk
291
417
  os2.y_subscript_y_offset, os2.y_superscript_x_size,
292
418
  os2.y_superscript_y_size, os2.y_superscript_x_offset,
293
419
  os2.y_superscript_y_offset, os2.y_strikeout_size,
294
- os2.y_strikeout_position, os2.family_class
420
+ os2.y_strikeout_position, os2.family_class,
295
421
  ].pack('n*')
296
422
 
297
423
  result << os2.panose
@@ -301,7 +427,7 @@ module TTFunk
301
427
  .slice_int(
302
428
  new_char_range.value,
303
429
  bit_width: 32,
304
- slice_count: 4
430
+ slice_count: 4,
305
431
  )
306
432
  .pack('N*')
307
433
 
@@ -322,27 +448,27 @@ module TTFunk
322
448
  last_char_index = [code_points.last || 0, UNICODE_MAX].min
323
449
 
324
450
  result << [
325
- os2.selection, first_char_index, last_char_index
451
+ os2.selection, first_char_index, last_char_index,
326
452
  ].pack('n*')
327
453
 
328
454
  if os2.version.positive?
329
455
  result << [
330
456
  os2.ascent, os2.descent, os2.line_gap,
331
- os2.win_ascent, os2.win_descent
457
+ os2.win_ascent, os2.win_descent,
332
458
  ].pack('n*')
333
459
 
334
460
  result << BinUtils
335
461
  .slice_int(
336
462
  code_pages_for(subset).value,
337
463
  bit_width: 32,
338
- slice_count: 2
464
+ slice_count: 2,
339
465
  )
340
466
  .pack('N*')
341
467
 
342
468
  if os2.version > 1
343
469
  result << [
344
470
  os2.x_height, os2.cap_height, os2.default_char,
345
- os2.break_char, os2.max_context
471
+ os2.break_char, os2.max_context,
346
472
  ].pack('n*')
347
473
  end
348
474
  end
@@ -380,13 +506,15 @@ module TTFunk
380
506
 
381
507
  def group_original_code_points_by_bit(os2)
382
508
  Hash.new { |h, k| h[k] = [] }.tap do |result|
383
- os2.file.cmap.unicode.first.code_map.each_key do |code_point|
384
- # find corresponding bit
385
- range = UNICODE_RANGES.find { |r| r.cover?(code_point) }
386
-
387
- if (bit = UNICODE_BLOCKS[range])
388
- result[bit] << code_point
509
+ code_points = os2.file.cmap.unicode.first.code_map.keys.sort
510
+ UNICODE_RANGES.each do |r|
511
+ code_points = code_points.drop_while { |p| p < r.min }
512
+ code_points.take_while { |p| p <= r.max }.each do |code_point|
513
+ if (bit = UNICODE_BLOCKS[r])
514
+ result[bit] << code_point
515
+ end
389
516
  end
517
+ code_points = code_points.drop_while { |p| p <= r.max }
390
518
  end
391
519
  end
392
520
  end
@@ -405,7 +533,7 @@ module TTFunk
405
533
 
406
534
  # use new -> old glyph mapping in order to include compound glyphs
407
535
  # in the calculation
408
- subset.new_to_old_glyph.each do |_, old_gid|
536
+ subset.new_to_old_glyph.each_value do |old_gid|
409
537
  if (metric = os2.file.horizontal_metrics.for(old_gid))
410
538
  total_width += metric.advance_width
411
539
  num_glyphs += 1 if metric.advance_width.positive?
@@ -456,7 +584,7 @@ module TTFunk
456
584
 
457
585
  # use new -> old glyph mapping in order to include compound glyphs
458
586
  # in the calculation
459
- subset.new_to_old_glyph.each do |_, old_gid|
587
+ subset.new_to_old_glyph.each_value do |old_gid|
460
588
  if (metric = os2.file.horizontal_metrics.for(old_gid))
461
589
  total_width += metric.advance_width
462
590
  end
@@ -481,9 +609,7 @@ module TTFunk
481
609
  @y_strikeout_position, @family_class = read_signed(12)
482
610
  @panose = io.read(10)
483
611
 
484
- @char_range = BitField.new(
485
- BinUtils.stitch_int(read(16, 'N*'), bit_width: 32)
486
- )
612
+ @char_range = BitField.new(BinUtils.stitch_int(read(16, 'N*'), bit_width: 32))
487
613
 
488
614
  @vendor_id = io.read(4)
489
615
  @selection, @first_char_index, @last_char_index = read(6, 'n*')
@@ -491,9 +617,7 @@ module TTFunk
491
617
  if @version.positive?
492
618
  @ascent, @descent, @line_gap = read_signed(3)
493
619
  @win_ascent, @win_descent = read(4, 'nn')
494
- @code_page_range = BitField.new(
495
- BinUtils.stitch_int(read(8, 'N*'), bit_width: 32)
496
- )
620
+ @code_page_range = BitField.new(BinUtils.stitch_int(read(8, 'N*'), bit_width: 32))
497
621
 
498
622
  if @version > 1
499
623
  @x_height, @cap_height = read_signed(2)
@@ -3,7 +3,10 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Post
6
+ # Version 1.0 provides glyph names for standard 258 glyphs in the standard
7
+ # Macintosh TrueType font file.
6
8
  module Format10
9
+ # Glyph names.
7
10
  POSTSCRIPT_GLYPHS = %w[
8
11
  .notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar
9
12
  percent ampersand quotesingle parenleft parenright asterisk plus comma
@@ -36,6 +39,10 @@ module TTFunk
36
39
  scedilla Cacute cacute Ccaron ccaron dcroat
37
40
  ].freeze
38
41
 
42
+ # Get glyph name for character code.
43
+ #
44
+ # @param code [Integer]
45
+ # @return [String]
39
46
  def glyph_for(code)
40
47
  POSTSCRIPT_GLYPHS[code] || '.notdef'
41
48
  end
@@ -6,9 +6,18 @@ require 'stringio'
6
6
  module TTFunk
7
7
  class Table
8
8
  class Post
9
+ # Version 2.0 is used for fonts that use glyph names that are not in the
10
+ # set of Macintosh glyph names. A given font may map some of its glyphs to
11
+ # the standard Macintosh glyph names, and some to its own custom names.
12
+ # A version 2.0 `post` table can be used in fonts with TrueType or CFF
13
+ # version 2 outlines.
9
14
  module Format20
10
15
  include Format10
11
16
 
17
+ # Get glyph name for character code.
18
+ #
19
+ # @param code [Integer]
20
+ # @return [String]
12
21
  def glyph_for(code)
13
22
  index = @glyph_name_index[code]
14
23
  return '.notdef' unless index
@@ -3,7 +3,13 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Post
6
+ # Version 3.0 specifies that no PostScript name information is provided
7
+ # for the glyphs in this font file.
6
8
  module Format30
9
+ # Get glyph name for character code.
10
+ #
11
+ # @param _code [Integer]
12
+ # @return [String]
7
13
  def glyph_for(_code)
8
14
  '.notdef'
9
15
  end
@@ -3,7 +3,12 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Post
6
+ # Version 4.0 names glyphs by their character code.
6
7
  module Format40
8
+ # Get glyph name for character code.
9
+ #
10
+ # @param code [Integer]
11
+ # @return [String]
7
12
  def glyph_for(code)
8
13
  @map[code] || 0xFFFF
9
14
  end
@@ -4,33 +4,93 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # PostScript (`post`) table.
8
+ #
9
+ # This class can be extended with version-specific modules.
10
+ #
11
+ # @see TTFunk::Table::Post::Format10
12
+ # @see TTFunk::Table::Post::Format20
13
+ # @see TTFunk::Table::Post::Format30
14
+ # @see TTFunk::Table::Post::Format40
7
15
  class Post < Table
16
+ # Table version.
17
+ # @return [Integer]
8
18
  attr_reader :format
19
+
20
+ # Italic angle in counter-clockwise degrees from the vertical.
21
+ # @return [Integer]
9
22
  attr_reader :italic_angle
23
+
24
+ # Suggested distance of the top of the underline from the baseline
25
+ # @return [Integer]
10
26
  attr_reader :underline_position
27
+
28
+ # Suggested values for the underline thickness.
29
+ # @return [Integer]
11
30
  attr_reader :underline_thickness
31
+
32
+ # 0 if the font is proportionally spaced, non-zero if the font is not
33
+ # proportionally spaced.
34
+ # @return [Integer]
12
35
  attr_reader :fixed_pitch
36
+
37
+ # Minimum memory usage when an OpenType font is downloaded.
38
+ # @return [Integer]
13
39
  attr_reader :min_mem_type42
40
+
41
+ # Maximum memory usage when an OpenType font is downloaded.
42
+ # @return [Integer]
14
43
  attr_reader :max_mem_type42
44
+
45
+ # Minimum memory usage when an OpenType font is downloaded as
46
+ # a Type 1 font.
47
+ # @return [Integer]
15
48
  attr_reader :min_mem_type1
49
+
50
+ # Maximum memory usage when an OpenType font is downloaded as
51
+ # a Type 1 font.
52
+ # @return [Integer]
16
53
  attr_reader :max_mem_type1
17
54
 
55
+ # Version-specific fields.
56
+ # @return [TTFunk::Table::Post::Format10, TTFunk::Table::Post::Format20,
57
+ # TTFunk::Table::Post::Format30, TTFunk::Table::Post::Format40]
18
58
  attr_reader :subtable
19
59
 
60
+ # Encode table.
61
+ #
62
+ # @param post [TTFunk::Table::Post]
63
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
64
+ # are old glyph IDs
65
+ # @return [String, nil]
20
66
  def self.encode(post, mapping)
21
- return unless post.exists?
67
+ return if post.nil?
22
68
 
23
69
  post.recode(mapping)
24
70
  end
25
71
 
72
+ # Is this font monospaced?
73
+ #
74
+ # @return [Boolean]
26
75
  def fixed_pitch?
27
76
  @fixed_pitch != 0
28
77
  end
29
78
 
79
+ # Get glyph name for character code.
80
+ #
81
+ # This is a placeholder.
82
+ #
83
+ # @param _code [Integer]
84
+ # @return [String]
30
85
  def glyph_for(_code)
31
86
  '.notdef'
32
87
  end
33
88
 
89
+ # Re-encode this table.
90
+ #
91
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
92
+ # are old glyph IDs
93
+ # @return [String]
34
94
  def recode(mapping)
35
95
  return raw if format == 0x00030000
36
96
 
@@ -46,7 +106,7 @@ module TTFunk
46
106
  if position
47
107
  index << position
48
108
  else
49
- index << 257 + strings.length
109
+ index << (257 + strings.length)
50
110
  strings << post_glyph
51
111
  end
52
112
  end
@@ -85,11 +145,7 @@ module TTFunk
85
145
  end
86
146
 
87
147
  def parse_format!
88
- warn(
89
- Kernel.format(
90
- 'postscript table format 0x%08X is not supported', @format
91
- )
92
- )
148
+ warn(Kernel.format('postscript table format 0x%08X is not supported', @format))
93
149
  end
94
150
  end
95
151
  end
@@ -4,14 +4,48 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Standard Bitmap Graphics (`sbix`) table.
7
8
  class Sbix < Table
9
+ # Table version.
10
+ # @return [Integer]
8
11
  attr_reader :version
12
+
13
+ # Flags.
14
+ # @return [Integer]
9
15
  attr_reader :flags
16
+
17
+ # Number of bitmap strikes.
18
+ # @return [Integer]
10
19
  attr_reader :num_strikes
20
+
21
+ # Strikes.
22
+ # @return [Array<Hash>]
11
23
  attr_reader :strikes
12
24
 
25
+ # Bitmap Data.
26
+ #
27
+ # @!attribute [rw] x
28
+ # The horizontal (x-axis) position of the left edge of the bitmap
29
+ # graphic in relation to the glyph design space origin.
30
+ # @!attribute [rw] y
31
+ # The vertical (y-axis) position of the bottom edge of the bitmap
32
+ # graphic in relation to the glyph design space origin.
33
+ # @!attribute [rw] type
34
+ # Indicates the format of the embedded graphic data: one of `jpg `,
35
+ # `png `, `tiff`, or the special format `dupe`.
36
+ # @!attribute [rw] data
37
+ # The actual embedded graphic data.
38
+ # @!attribute [rw] ppem
39
+ # The PPEM size for which this strike was designed.
40
+ # @!attribute [rw] resolution
41
+ # The device pixel density (in PPI) for which this strike was designed.
13
42
  BitmapData = Struct.new(:x, :y, :type, :data, :ppem, :resolution)
14
43
 
44
+ # Get bitmap for glyph strike.
45
+ #
46
+ # @param glyph_id [Integer]
47
+ # @param strike_index [Integer]
48
+ # @return [BitmapData]
15
49
  def bitmap_data_for(glyph_id, strike_index)
16
50
  strike = strikes[strike_index]
17
51
  return if strike.nil?
@@ -22,21 +56,23 @@ module TTFunk
22
56
  if glyph_offset && next_glyph_offset
23
57
  bytes = next_glyph_offset - glyph_offset
24
58
  if bytes.positive?
25
- parse_from(offset + strike[:offset] + glyph_offset) do
59
+ parse_from(offset + strike[:offset] + glyph_offset) {
26
60
  x, y, type = read(8, 's2A4')
27
61
  data = StringIO.new(io.read(bytes - 8))
28
- BitmapData.new(
29
- x, y, type, data, strike[:ppem], strike[:resolution]
30
- )
31
- end
62
+ BitmapData.new(x, y, type, data, strike[:ppem], strike[:resolution])
63
+ }
32
64
  end
33
65
  end
34
66
  end
35
67
 
68
+ # Get all bitmaps for glyph.
69
+ #
70
+ # @param glyph_id [Integer]
71
+ # @return [Array<BitmapData>]
36
72
  def all_bitmap_data_for(glyph_id)
37
- strikes.each_index.map do |strike_index|
73
+ strikes.each_index.filter_map { |strike_index|
38
74
  bitmap_data_for(glyph_id, strike_index)
39
- end.compact
75
+ }
40
76
  end
41
77
 
42
78
  private
@@ -46,21 +82,21 @@ module TTFunk
46
82
  strike_offsets = Array.new(num_strikes) { read(4, 'N').first }
47
83
 
48
84
  @strikes =
49
- strike_offsets.map do |strike_offset|
50
- parse_from(offset + strike_offset) do
85
+ strike_offsets.map { |strike_offset|
86
+ parse_from(offset + strike_offset) {
51
87
  ppem, resolution = read(4, 'n2')
52
88
  data_offsets =
53
- Array.new(file.maximum_profile.num_glyphs + 1) do
89
+ Array.new(file.maximum_profile.num_glyphs + 1) {
54
90
  read(4, 'N').first
55
- end
91
+ }
56
92
  {
57
93
  ppem: ppem,
58
94
  resolution: resolution,
59
95
  offset: strike_offset,
60
- glyph_data_offset: data_offsets
96
+ glyph_data_offset: data_offsets,
61
97
  }
62
- end
63
- end
98
+ }
99
+ }
64
100
  end
65
101
  end
66
102
  end
@@ -4,9 +4,14 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # A table that TTFunk doesn't decode but preserve.
7
8
  class Simple < Table
9
+ # Table tag
10
+ # @return [String]
8
11
  attr_reader :tag
9
12
 
13
+ # @param file [TTFunk::File]
14
+ # @param tag [String]
10
15
  def initialize(file, tag)
11
16
  @tag = tag
12
17
  super(file)