Module: Pdfrb::Font::Sfnt
- Defined in:
- lib/pdfrb/font/sfnt.rb
Overview
sfnt container (OpenType/TTF) table directory: the shared seam for reading and rebuilding the wrapper around font outlines. Both subsetters (TrueType glyf and CFF) rebuild the directory around their subset tables; this module owns that format so the two implementations cannot drift (they once disagreed even on whether checksums are computed).
Defined Under Namespace
Classes: Entry
Class Method Summary collapse
- .checksum(data) ⇒ Object
-
.parse_directory(sfnt) ⇒ Object
Parse the table directory of an sfnt byte string.
-
.rebuild(sfnt_version, tables) ⇒ Object
Rebuild an sfnt wrapper:
sfnt_versionis the 4-byte magic (e.g. "\x00\x01\x00\x00" or "OTTO"),tablesan Array of [tag, data] pairs. -
.table_bytes(sfnt, tag) ⇒ Object
Raw bytes of +tag+'s table, or nil.
Class Method Details
.checksum(data) ⇒ Object
65 66 67 68 69 70 |
# File 'lib/pdfrb/font/sfnt.rb', line 65 def checksum(data) padded = data + ("\x00".b * ((4 - (data.bytesize % 4)) % 4)) sum = 0 padded.unpack("N*").each { |w| sum = (sum + w) & 0xFFFFFFFF } sum end |
.parse_directory(sfnt) ⇒ Object
Parse the table directory of an sfnt byte string.
Returns [sfnt_version, Array
18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/pdfrb/font/sfnt.rb', line 18 def parse_directory(sfnt) num_tables = (sfnt.getbyte(4) * 256) + sfnt.getbyte(5) version = sfnt.byteslice(0, 4) entries = (0...num_tables).map do |i| base = 12 + (i * 16) Entry.new( sfnt.byteslice(base, 4), sfnt.byteslice(base + 8, 4).unpack1("N"), sfnt.byteslice(base + 12, 4).unpack1("N") ) end [version, entries] end |
.rebuild(sfnt_version, tables) ⇒ Object
Rebuild an sfnt wrapper: sfnt_version is the 4-byte magic
(e.g. "\x00\x01\x00\x00" or "OTTO"), tables an Array of
[tag, data] pairs. Checksums are computed per the sfnt spec
(sum of big-endian u32s over zero-padded data).
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/pdfrb/font/sfnt.rb', line 42 def rebuild(sfnt_version, tables) num = tables.length search_range = (2**Math.log2(num).floor) * 16 entry_selector = Math.log2(num).floor range_shift = (num * 16) - search_range out = +"".b out << sfnt_version.b out << [num, search_range, entry_selector, range_shift].pack("n4") sorted = tables.sort_by { |tag, _| tag } offset = 12 + (num * 16) sorted.each do |tag, data| out << tag.b << [checksum(data), offset, data.bytesize].pack("NNN") offset += (data.bytesize + 3) & ~3 end sorted.to_h.each_value do |data| out << data.b out << ("\x00".b * ((4 - (out.bytesize % 4)) % 4)) end out end |
.table_bytes(sfnt, tag) ⇒ Object
Raw bytes of +tag+'s table, or nil.
33 34 35 36 |
# File 'lib/pdfrb/font/sfnt.rb', line 33 def table_bytes(sfnt, tag) entry = parse_directory(sfnt)[1].find { |e| e.tag == tag } entry && sfnt.byteslice(entry.offset, entry.byte_length) end |