Class: Fontisan::Tables::Cblc

Inherits:
Binary::BaseRecord show all
Defined in:
lib/fontisan/tables/cblc.rb

Overview

CBLC (Color Bitmap Location) table.

CBLC indexes glyph IDs into CBDT byte offsets across one or more bitmap strikes (each strike = a ppem + bit depth combination). For each strike, a list of IndexSubTable records describes how to locate the bitmap of each glyph in a contiguous glyph range.

Layout:

uint32 version                (0x00020000 or 0x00030000)
uint32 num_sizes              (number of BitmapSize records)
CblcBitmapSize[num_sizes]     (48 bytes each)
IndexSubTableArray entries    (8 bytes each, per BitmapSize)
IndexSubTable records         (variable, format-specific)

This model parses the header + BitmapSize records via BinData, then lazily walks the IndexSubTableArray / IndexSubTable structures on demand so callers can iterate [(gid, strike) → CBDT location] pairs.

Reference: OpenType CBLC specification. https://learn.microsoft.com/en-us/typography/opentype/spec/cblc

Examples:

Enumerate every glyph's CBDT bitmap location

cblc = Fontisan::Tables::Cblc.read(font.table_data["CBLC"])
cblc.each_glyph_location do |loc|
  puts "gid=#{loc.glyph_id} cbdt_offset=#{loc.cbdt_offset}"
end

Constant Summary collapse

TAG =
"CBLC"
VERSION_2_0 =

CBLC v2.0 — original release

0x00020000
VERSION_3_0 =

CBLC v3.0 — adds PNG image format support

0x00030000

Instance Attribute Summary

Attributes inherited from Binary::BaseRecord

#raw_data

Instance Method Summary collapse

Methods inherited from Binary::BaseRecord

read

Instance Method Details

#bitmap_offset_for_gid(glyph_id, ppem) ⇒ CblcGlyphBitmapLocation?

Locate a glyph's CBDT bitmap at a specific ppem.

Parameters:

  • glyph_id (Integer)

    source glyph ID

  • ppem (Integer)

    strike ppem

Returns:



72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/fontisan/tables/cblc.rb', line 72

def bitmap_offset_for_gid(glyph_id, ppem)
  strike = bitmap_sizes.find do |s|
    s.ppem == ppem && s.includes_glyph?(glyph_id)
  end
  return nil unless strike

  sub_tables_for(strike).each do |sub|
    loc = sub.locations.find { |l| l.glyph_id == glyph_id }
    return loc if loc
  end
  nil
end

#each_glyph_location {|CblcGlyphBitmapLocation| ... } ⇒ Enumerator

Iterate every (glyph_id, strike) → CblcGlyphBitmapLocation pair across all strikes. Each strike's IndexSubTables are walked in turn so the caller sees every glyph's CBDT location exactly once per strike.

Yields:

Returns:

  • (Enumerator)

    if no block given



52
53
54
55
56
57
58
# File 'lib/fontisan/tables/cblc.rb', line 52

def each_glyph_location(&block)
  return enum_for(:each_glyph_location) unless block

  index_sub_tables.each do |sub|
    sub.locations.each(&block)
  end
end

#glyph_ids_with_bitmapsArray<Integer>

All glyph IDs that have any bitmap across every strike.

Returns:

  • (Array<Integer>)


139
140
141
# File 'lib/fontisan/tables/cblc.rb', line 139

def glyph_ids_with_bitmaps
  bitmap_sizes.flat_map { |s| s.glyph_range.to_a }.uniq.sort
end

#index_sub_tablesArray<CblcIndexSubTable>

All IndexSubTable records across every strike.

Returns:



63
64
65
# File 'lib/fontisan/tables/cblc.rb', line 63

def index_sub_tables
  @index_sub_tables ||= bitmap_sizes.flat_map { |s| sub_tables_for(s) }
end

#num_strikesInteger

Number of bitmap strikes.

Returns:

  • (Integer)


116
117
118
# File 'lib/fontisan/tables/cblc.rb', line 116

def num_strikes
  num_sizes
end

#ppem_sizesArray<Integer>

All available ppem sizes across every strike.

Returns:

  • (Array<Integer>)


109
110
111
# File 'lib/fontisan/tables/cblc.rb', line 109

def ppem_sizes
  bitmap_sizes.map(&:ppem).uniq.sort
end

#strikes_for_glyph(glyph_id) ⇒ Array<CblcBitmapSize>

Strikes that cover a given glyph ID.

Parameters:

  • glyph_id (Integer)

Returns:



124
125
126
# File 'lib/fontisan/tables/cblc.rb', line 124

def strikes_for_glyph(glyph_id)
  bitmap_sizes.select { |s| s.includes_glyph?(glyph_id) }
end

#strikes_for_ppem(ppem) ⇒ Array<CblcBitmapSize>

Strikes that match a specific ppem.

Parameters:

  • ppem (Integer)

Returns:



132
133
134
# File 'lib/fontisan/tables/cblc.rb', line 132

def strikes_for_ppem(ppem)
  bitmap_sizes.select { |s| s.ppem == ppem }
end

#sub_tables_for(strike) ⇒ Array<CblcIndexSubTable>

Iterate every IndexSubTable in a single strike.

Parameters:

Returns:



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/fontisan/tables/cblc.rb', line 89

def sub_tables_for(strike)
  return [] if strike.number_of_index_subtables.zero?

  array_offset = strike.index_subtable_array_offset
  entries = read_index_subtable_array(strike, array_offset)

  entries.map do |entry|
    absolute = array_offset + entry.additional_offset_to_index_subtable
    CblcIndexSubTable.parse(
      raw_data,
      index_subtable_offset: absolute,
      first_glyph_index: entry.first_glyph_index,
      last_glyph_index: entry.last_glyph_index,
    )
  end
end

#valid?Boolean

Whether the CBLC header is one fontisan understands and at least the header fields parsed successfully.

Returns:

  • (Boolean)


147
148
149
150
151
152
# File 'lib/fontisan/tables/cblc.rb', line 147

def valid?
  return false if version.nil?
  return false unless [VERSION_2_0, VERSION_3_0].include?(version)

  true
end