Appearance
Carrot.Text.Fonts
net
.NET library for parsing TrueType font files and baking SDF glyph atlas textures. Targets NetStandard 2.1 for Unity compatibility. Produces the font assets consumed by FlexUI's text rendering system.
Installation
Project reference in a .NET solution:
xml
<ProjectReference Include="..\Carrot.NetStandard21.Text.Fonts\Carrot.NetStandard21.Text.Fonts.csproj" />Architecture
Font Parsing
TtfReader reads a TTF binary file via a seekable IHasBinaryReader, parses the table directory, then loads each table chunk in dependency order (header → metrics → character map → glyph outlines → colour layers → kerning → positioning).
Each TTF table has a TtfChunk<TData> / TtfChunkData pair. The chunk handles binary reading; the data object holds the parsed result. Table-specific subtable formats (e.g. cmap format 0/4/6/12/14, GPOS format 2/4/5/6) are each implemented as separate classes.
After all chunks are parsed, TtfBuilder assembles the final Ttf object using specialised sub-builders (names, glyphs, kerning, adjustments, palettes). The Ttf is the high-level data model - it owns TtfGlyphs (with contour outlines), TtfKerning (kern pairs), TtfAdjustments (GPOS positioning), and TtfPalettes (COLRv0/v1 colour data).
Glyph Types
- Simple - contour-based outlines with on/off-curve control points forming quadratic Bézier segments
- Composite - assembled from component references to other glyphs with transform matrices
- Blank - no outline (whitespace characters)
Atlas Baking
TtfAtlas<TPacker> extends the generic ImageAtlas from Carrot.Images. It takes a TtfGlyphFontSet (font + selected glyphs) and packs them into a texture atlas using a configurable IRectPacker. Each entry stores the glyph, font size, and scale factor. The atlas can be serialized to JSON for consumption by Unity or TypeScript.
Shape Render Pipeline
The SDF rendering pipeline is a multi-stage chain:
Glyph outlines → Sample → Coverage/HitPositions/SignedDistance
→ Normalize → NormalizedCoverage/HitPositions/SignedDistance
→ Paint → PaintedCoverageThe same pipeline works at both per-glyph and per-atlas granularity. Each stage is a separate class enabling pipeline configuration (e.g. skip hit positions if you only need coverage). The pipeline operates on the shape graph from Carrot.Shapes, not directly on TTF data - so it's reusable for non-font shapes.
TrueType Hinting
TtfBytecodeReader and TtfHintingReader parse the fpgm/prep bytecode tables. The execution model (TtfExecutionState, TtfInstruction, TtfOpcode) represents the TrueType hinting VM. This is used for grid-fitted rendering at small sizes.
File Structure
Text/Fonts/
├── TtfReader.cs # TTF file parser
├── TtcReader.cs # TTC collection parser
├── TtfChunk.cs # Base chunk/table abstraction
├── Tables/ # Table directory entry
├── Chunks/ # Per-table chunk parsers
│ ├── CharacterMap/ # cmap (formats 0, 4, 6, 12, 14)
│ ├── GlyphTable/ # glyf outlines
│ ├── Glyphs/ # loca glyph locations
│ ├── GlyphPositioning/ # GPOS (formats 2, 4, 5, 6)
│ ├── ColorLayers/ # COLR v0/v1
│ ├── ColorPalette/ # CPAL v0/v1
│ ├── Execution/ # fpgm/prep bytecode
│ └── StandardBitmapGraphics/ # sbix
├── Data/
│ ├── Ttf.cs # High-level font model
│ ├── Builder/ # Chunk → Ttf assembly
│ ├── Glyphs/ # Glyph types + contours
│ ├── Palettes/ # Colour palettes
│ └── Execution/ # Hinting VM types
├── Atlas/ # Atlas generation + serialization
├── Renderers/ # SDF renderer (WIP)
├── Readers/ # Bytecode/hinting readers
└── Sets/ # Glyph sets + Unicode character lists
Shapes/
├── ShapeGraphExtensions.cs # Shape graph → pipeline
├── ShapeLayerExtensions.cs
├── ShapeNodeGroupExtensions.cs
└── RenderPipeline/
├── Glyphs/ # Per-glyph pipeline stages
├── Atlases/ # Per-atlas pipeline stages
└── Rendering/ # Final raster outputDependencies
| Dependency | Kind |
|---|---|
Carrot.NetStandard21 | project (core utilities) |
Carrot.NetStandard21.Colors | project (colour types) |
Carrot.NetStandard21.Images | project (atlas, rasterisation) |
Carrot.NetStandard21.Maths | project (geometry, bounds) |
Carrot.NetStandard21.Text.Json | project (serialization) |
Build
bash
dotnet buildTargets netstandard2.1 for Unity compatibility. Assembly name: Carrot.Text.Fonts.
Usage Guide
Parse TTF/TTC fonts, extract glyph data, and bake SDF atlas textures for FlexUI text rendering.
Common Patterns
1. Parse a TTF font
csharp
using Carrot.Text.Fonts;
using Carrot.Text.Fonts.Data;
using TtfReader reader = TtfReader.Load("path/to/font.ttf");
Ttf font = reader.Parse();
// Access font data
string family = font.Names.Family;
float unitsPerEm = font.UnitsPerEm;
int glyphCount = font.Glyphs.Count;2. Parse from bytes
csharp
byte[] fontData = File.ReadAllBytes("font.ttf");
using TtfReader reader = TtfReader.Load(fontData);
Ttf font = reader.Parse();3. Parse a TTC collection
csharp
using TtcReader reader = TtcReader.Load("path/to/collection.ttc");
// Access individual fonts within the collection4. Access glyph data
csharp
TtfGlyph glyph = font.Glyphs[glyphIndex];
// Simple glyph - contour outlines
if (glyph is TtfGlyphSimple simple)
{
foreach (TtfGlyphContour contour in simple.Contours)
{
foreach (TtfGlyphContourBezier segment in contour.Beziers)
{
// Quadratic Bézier control points
}
}
}
// Composite glyph - component references
if (glyph is TtfGlyphComposite composite)
{
foreach (TtfGlyphComponent component in composite.Components)
{
// Referenced glyph + transform
}
}5. Kerning and positioning
csharp
// Kerning pairs
float kern = font.Kerning.Get(leftGlyphIndex, rightGlyphIndex);
// GPOS adjustments
var adjustment = font.Adjustments.Get(leftGlyphIndex, rightGlyphIndex);6. Build a glyph atlas
csharp
using Carrot.Text.Fonts.Atlas;
using Carrot.Text.Fonts.Sets;
// Select glyphs
var glyphSet = new TtfGlyphFontSet(font, UnicodeCharacters.BasicLatin);
// Create atlas with rect packing
var atlas = new TtfAtlas<ShelfPacker>("my-font", (config, packer) =>
{
config.FontSizePx = 48;
config.EntryPadding = 2;
}, glyphSet);
// Serialize for runtime consumption
TtfAtlasSerialized serialized = atlas.Serialize();7. Colour fonts (COLRv0)
csharp
if (glyph is TtfGlyphColorSimple colorGlyph)
{
foreach (TtfGlyphColorSimpleLayer layer in colorGlyph.Layers)
{
// layer.GlyphIndex - the outline to render
// layer.PaletteIndex - colour from font.Palettes
}
}Tips
- The reader is disposable - wrap
TtfReaderinusingto release the file handle or memory. - Atlas serialization outputs JSON - consumed by the FlexUI font baker in Unity and by the TS engine.
UnicodeCharactershas prebuilt sets - BasicLatin, Latin1Supplement, etc. Combine them for your character coverage needs.