Module: Fontisan::Ufo::Compile::CbdtCblc
- Defined in:
- lib/fontisan/ufo/compile/cbdt_cblc.rb
Overview
Builds the OpenType CBDT (Color Bitmap Data) and
CBLC (Color Bitmap Location) tables.
Together they describe per-strike bitmap strikes for color emoji fonts (Noto Color Emoji, Twemoji Mozilla). Each strike stores a bitmap glyph at a specific ppem + resolution.
This implementation handles the common case: one strike per ppem, with indexSubTable format 3 (variable) and bitmaps stored directly in the CBDT.
Constant Summary collapse
- VERSION =
3
Class Method Summary collapse
-
.build(strikes:) ⇒ Hash<String,String>
{ "CBDT" => bytes, "CBLC" => bytes }.
-
.build_cbdt(strikes) ⇒ Object
CBDT: version(2) + numStrikes(4) + strike data.
-
.build_cblc(strikes) ⇒ Object
CBLC: version(2) + numSizes(4) + size offsets(4*N) + size tables.
-
.build_index_sub_table_array(strike) ⇒ Object
indexSubTableArray + indexSubTable (format 3, variable).
-
.build_sbit_line_metrics(ppem, num_glyphs) ⇒ Object
SbitLineMetrics (12 bytes): height, width, hori/vert bearings.
- .serialize_strike(strike) ⇒ Object
Class Method Details
.build(strikes:) ⇒ Hash<String,String>
Returns { "CBDT" => bytes, "CBLC" => bytes }.
27 28 29 30 31 |
# File 'lib/fontisan/ufo/compile/cbdt_cblc.rb', line 27 def self.build(strikes:) return nil if strikes.nil? || strikes.empty? { "CBDT" => build_cbdt(strikes), "CBLC" => build_cblc(strikes) } end |
.build_cbdt(strikes) ⇒ Object
CBDT: version(2) + numStrikes(4) + strike data
34 35 36 37 38 39 |
# File 'lib/fontisan/ufo/compile/cbdt_cblc.rb', line 34 def self.build_cbdt(strikes) io = +"" io << [VERSION, strikes.size].pack("nN") strikes.each { |s| io << serialize_strike(s) } io end |
.build_cblc(strikes) ⇒ Object
CBLC: version(2) + numSizes(4) + size offsets(4*N) + size tables
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/fontisan/ufo/compile/cbdt_cblc.rb', line 42 def self.build_cblc(strikes) num_sizes = strikes.size header = [VERSION, num_sizes].pack("nN") offsets_placeholder = Array.new(num_sizes, 0).pack("N*") io = +"" io << header io << offsets_placeholder size_table_start = io.bytesize strike_offsets = [] strikes.each do |s| strike_offsets << (io.bytesize - size_table_start) io << build_sbit_line_metrics(s[:ppem] || 16, s[:glyphs]&.size || 0) io << build_index_sub_table_array(s) end # Patch offsets real_offsets = strike_offsets.map { |o| o + size_table_start } io[8, real_offsets.pack("N*").bytesize] = real_offsets.pack("N*") io end |
.build_index_sub_table_array(strike) ⇒ Object
indexSubTableArray + indexSubTable (format 3, variable)
74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/fontisan/ufo/compile/cbdt_cblc.rb', line 74 def self.build_index_sub_table_array(strike) glyphs = strike[:glyphs] || [] num_glyphs = [glyphs.size, 1].max # indexSubTableArray: firstGlyphID(2) + lastGlyphID(2) + additionalOffset(4) array_header = [0, num_glyphs - 1, 8].pack("nnN") # indexSubTable format 3: format(2) + imageFormat(2) + imageDataOffset(4) # + bigGlyphMetrics(8) + offsetArray(numGlyphs × 4) subtable = +"" subtable << [3, 1, 4 + 8 + num_glyphs * 4].pack("nnN") subtable << [16, 16, 0, 12, 16, 8, 0, 16].pack("C8") offsets = Array.new(num_glyphs) { |i| i * 100 } subtable << offsets.pack("N*") array_header + subtable end |
.build_sbit_line_metrics(ppem, num_glyphs) ⇒ Object
SbitLineMetrics (12 bytes): height, width, hori/vert bearings
66 67 68 69 70 71 |
# File 'lib/fontisan/ufo/compile/cbdt_cblc.rb', line 66 def self.build_sbit_line_metrics(ppem, num_glyphs) io = +"" io << [ppem & 0xFF, 0, ppem & 0xFF, 0, 0, 0, ppem & 0xFF, 0, 0, 0, 0].pack("C11") io << [12 + num_glyphs * 8].pack("n") io end |
.serialize_strike(strike) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/fontisan/ufo/compile/cbdt_cblc.rb', line 89 def self.serialize_strike(strike) glyphs = strike[:glyphs] || [] io = +"" glyphs.each do |g| next if g.nil? io << [g[:origin_x] || 0, g[:origin_y] || 0].pack("nn") io << (g[:data] || "") end io end |