Bitmap Color Fonts
Bitmap color fonts store pixel images at specific sizes.
Formats
| Format | Tables | Platform |
|---|---|---|
| sbix | sbix | Apple |
| CBDT/CBLC | CBDT, CBLC | Google/Android |
sbix (Apple)
sbix stores bitmap images at multiple resolutions.
Structure
sbix = font.tables['sbix']
# Strikes (image sets at different sizes)
sbix.strikes.each do |strike|
puts "Strike at #{strike.ppem} ppem"
strike.glyphs.each do |glyph_id, image|
puts " Glyph #{glyph_id}: #{image.format}"
end
endImage Formats
png— PNG imagejpg— JPEG imagetiff— TIFF imagedupe— Duplicate of another glyph
Accessing Images
sbix = font.tables['sbix']
strike = sbix.strikes.first
glyph_id = 42
image = strike.image_for(glyph_id)
puts "Format: #{image.format}"
puts "Data size: #{image.data.length} bytes"CBDT/CBLC (Android)
CBDT/CBLC stores bitmap images for Android.
Structure
cbdt = font.tables['CBDT']
cblc = font.tables['CBLC']
# CBLC has location data
cblc.strikes.each do |strike|
puts "Strike at #{strike.ppem}x#{strike.ppem}"
strike.glyph_ranges.each do |range|
puts " Glyphs #{range.start}..#{range.end}"
end
end
# CBDT has actual bitmap dataBitmap Formats
- Small metrics — For small glyphs
- Big metrics — For larger glyphs
- Bit aligned — 1, 2, 4, or 8 bits per pixel
Accessing Bitmaps
cbdt = font.tables['CBDT']
cblc = font.tables['CBLC']
glyph_id = 42
strike_index = 0
# Get bitmap location
location = cblc.location(strike_index, glyph_id)
if location
# Get bitmap data
bitmap = cbdt.bitmap(location)
puts "Size: #{bitmap.width}x#{bitmap.height}"
puts "Data: #{bitmap.data.length} bytes"
endWorking with Bitmaps
List Available Sizes
sbix = font.tables['sbix']
if sbix
puts "Available sizes:"
sbix.strikes.each do |strike|
puts " #{strike.ppem} ppem"
end
endExport Bitmaps
sbix = font.tables['sbix']
strike = sbix.strikes.first
sbix.glyphs.each do |glyph_id, image|
if image.format == 'png '
File.write("glyph-#{glyph_id}.png", image.data)
end
endConversion
Preserve Bitmaps
# Bitmaps preserved during same-format conversion
fontisan convert bitmap-font.ttf --to ttf --output bitmap-font.ttfRemove Bitmaps
# Create outline-only version
fontisan convert bitmap-font.ttf --to ttf --no-bitmaps --output outline-only.ttfSubsetting color-emoji fonts
The web subsetting profile retains CBDT and CBLC tables and rewrites them to keep only the bitmaps for retained glyphs. Use it when subsetting a color-emoji source for browser delivery:
# Keep only 😀 + 😁 bitmaps; output WOFF2 for web
fontisan subset NotoColorEmoji.ttf \
--chars "😀😁" \
--profile web \
--output-format woff2 \
--output emoji-subset.woff2Other profiles (pdf, minimal, full) drop CBDT/CBLC — pick them when the subset doesn't need color-emoji rendering (e.g. PDF embedding where the subsetter is just selecting glyphs for outlines).
See the subset CLI docs and docs/STITCHER_GUIDE.adoc (CBDT/CBLC passthrough section) for the full story, including the GID-stability caveat when CBDT and outline donors cover overlapping codepoint ranges in stitch mode.
Comparison
| Feature | sbix | CBDT/CBLC |
|---|---|---|
| Platform | Apple | Android |
| Image formats | PNG, JPEG, TIFF | Raw bitmap |
| Scalability | No | No |
| File size | Larger | Smaller |
| Quality | Photo-realistic | Limited |
Limitations
Bitmap Scaling
Bitmap fonts don't scale well:
- Each strike is designed for a specific ppem
- Scaling up causes pixelation
- Scaling down causes aliasing
Variable Fonts
Bitmap fonts don't work with variation:
- No interpolation possible
- Must provide strikes for each instance
Best Practices
- Provide multiple strikes — Cover common sizes
- Use PNG for sbix — Best quality/size tradeoff
- Test on target platforms — Rendering varies
- Consider outline fallback — For unavailable sizes