You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 3e5f689
Browse filesBrowse the repository at this point in the historyBrowse files
COLR glyphs take their colors from the font's CPAL palette table. Many color fonts ship more than one palette, such as a default and a dark-background variant. [`TextOptions.FontPalette`](xref:SixLabors.Fonts.TextOptions.FontPalette) selects the palette that resolves the colors. Leave the value `null` to keep the font's default palette.
// Resolve COLR glyph colors with the font's second palette.
58
+
// Palette indexes are zero-based; null keeps the font's default.
59
+
FontPalette=newFontPalette(1)
60
+
};
61
+
```
62
+
63
+
A palette selection can also override individual entries. Each [`FontPaletteOverride`](xref:SixLabors.Fonts.FontPaletteOverride) replaces the palette color at one index:
64
+
65
+
```csharp
66
+
// Start from the default palette, then replace entry 2 with opaque red.
[`TextRun.FontPalette`](xref:SixLabors.Fonts.TextRun.FontPalette) replaces the selection over a range of text. [`GlyphOptions.FontPalette`](xref:SixLabors.Fonts.GlyphOptions.FontPalette) applies the same selection when rendering or measuring by glyph ID.
74
+
47
75
## What happens in custom renderers
48
76
49
77
When a resolved glyph is a painted color glyph, Fonts streams it through [`IGlyphRenderer`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer) as one or more layers.
@@ -52,9 +80,10 @@ That means custom renderers should pay attention to:
-[`BeginGroup(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGroup*) and [`EndGroup()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndGroup*)
COLR v1 paint graphs can also form composite groups. Fonts wraps such content in [`BeginGroup(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGroup*) and [`EndGroup()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndGroup*) calls. Layers inside a group compose as one isolated unit. The finished group then blends onto the content below it with the [`CompositeMode`](xref:SixLabors.Fonts.Rendering.CompositeMode) given to `BeginGroup(...)`. A clip for the glyph arrives through [`GlyphRendererParameters.ClipBounds`](xref:SixLabors.Fonts.Rendering.GlyphRendererParameters.ClipBounds).
96
+
66
97
If your renderer ignores paint information, the glyph can still be drawn, but it will no longer preserve the font's intended color presentation.
Copy file name to clipboardExpand all lines: articles/fonts/customrendering.md
+13-5Lines changed: 13 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@
5
5
6
6
Most developers meet Fonts through [ImageSharp.Drawing](../imagesharp.drawing/index.md), where the rendering surface is already handled for you. This page is for the next step down: when you want Fonts to do the shaping and glyph decomposition, but you want to decide how those glyphs are painted or exported.
7
7
8
-
Custom rendering in Fonts is built around [`IGlyphRenderer`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer). [`TextRenderer.RenderTextTo(...)`](xref:SixLabors.Fonts.Rendering.TextRenderer.RenderTextTo*) performs layout and shaping, then sends the result to your renderer as glyphs, layers, figures, and path commands.
8
+
Custom rendering in Fonts is built around [`IGlyphRenderer`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer). [`TextRenderer.RenderTo(...)`](xref:SixLabors.Fonts.Rendering.TextRenderer.RenderTo*) performs layout and shaping, then sends the result to your renderer as glyphs, layers, figures, and path commands.
9
9
10
10
## When to use it
11
11
@@ -27,9 +27,9 @@ For monochrome outline glyphs, the path callbacks are delivered inside [`BeginGl
27
27
5.`SetDecoration(...)` for any decorations requested by `EnabledDecorations()`
28
28
6.`EndText()`
29
29
30
-
Painted color glyphs add [`BeginLayer(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginLayer*) / [`EndLayer()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndLayer*) around each painted layer between [`BeginGlyph(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGlyph*) and [`EndGlyph()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndGlyph*).
30
+
Painted color glyphs add [`BeginLayer(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginLayer*) / [`EndLayer()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndLayer*) around each painted layer between [`BeginGlyph(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGlyph*) and [`EndGlyph()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndGlyph*). COLR v1 composite content adds [`BeginGroup(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGroup*) / [`EndGroup()`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.EndGroup*) around layers that must compose as one isolated unit before they blend onto the content below.
31
31
32
-
[`BeginGlyph(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGlyph*) receives [`GlyphRendererParameters`](xref:SixLabors.Fonts.Rendering.GlyphRendererParameters), which identify the glyph instance being rendered, including the glyph ID, the glyph's [`CodePoint`](xref:SixLabors.Fonts.Unicode.CodePoint) value, font style, point size, DPI, layout mode, and active [`TextRun`](xref:SixLabors.Fonts.TextRun). Return `false` from `BeginGlyph(...)` if you want to skip rendering that glyph.
32
+
[`BeginGlyph(...)`](xref:SixLabors.Fonts.Rendering.IGlyphRenderer.BeginGlyph*) receives [`GlyphRendererParameters`](xref:SixLabors.Fonts.Rendering.GlyphRendererParameters), which identify the glyph instance being rendered, including the glyph ID, the glyph's [`CodePoint`](xref:SixLabors.Fonts.Unicode.CodePoint) value, font style, point size, DPI, layout mode, hinting mode, and active [`TextRun`](xref:SixLabors.Fonts.TextRun). Return `false` from `BeginGlyph(...)` if you want to skip rendering that glyph. The parameters include everything that changes glyph geometry, so a renderer can use them as a cache key.
33
33
34
34
## A minimal renderer
35
35
@@ -57,14 +57,22 @@ public sealed class RecordingGlyphRenderer : IGlyphRenderer
Copy file name to clipboardExpand all lines: articles/fonts/fallbackfonts.md
+22Lines changed: 22 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,28 @@ Fallback families are searched in the order you provide them.
34
34
- Put emoji fonts after your normal text families unless you explicitly want them to win earlier.
35
35
- Keep the fallback list as small and intentional as possible so the selection stays predictable.
36
36
37
+
## Resolver-based fallback
38
+
39
+
[`FallbackFontFamilies`](xref:SixLabors.Fonts.TextOptions.FallbackFontFamilies) is a fixed list. [`TextOptions.FontFallbackResolver`](xref:SixLabors.Fonts.TextOptions.FontFallbackResolver) adds a dynamic last step behind it. Shaping consults the resolver only for code points that neither the primary font nor any fallback family can shape. It asks at most once per distinct unresolved code point per shaping operation. Leave the value `null` to render such code points as the missing-glyph outline.
40
+
41
+
[`SystemFonts.FallbackResolver`](xref:SixLabors.Fonts.SystemFonts.FallbackResolver) is a built-in resolver that selects from the fonts installed on the current machine:
42
+
43
+
```csharp
44
+
usingSixLabors.Fonts;
45
+
46
+
Fontfont=SystemFonts.CreateFont("Segoe UI", 18);
47
+
TextOptionsoptions=new(font)
48
+
{
49
+
// Ask the operating system for a family when no configured font
50
+
// can shape a code point.
51
+
FontFallbackResolver=SystemFonts.FallbackResolver
52
+
};
53
+
```
54
+
55
+
Installed fonts differ between machines, so output rendered with the system resolver can differ too. Pin `FallbackFontFamilies` for output that must stay identical everywhere, and use the resolver as a safety net behind them.
56
+
57
+
Implement [`IFontFallbackResolver`](xref:SixLabors.Fonts.IFontFallbackResolver) for a custom policy. The resolver receives the code point, the requested family, the style, and the culture. It returns the family that contains a glyph for the code point.
58
+
37
59
## Mixed-script example
38
60
39
61
This pattern works well for text that mixes Latin, Arabic, and emoji:
Copy file name to clipboardExpand all lines: articles/fonts/fontmetrics.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,6 +41,7 @@ The core identity and scaling properties are:
41
41
-[`Description`](xref:SixLabors.Fonts.FontMetrics.Description) for the face metadata
42
42
-[`UnitsPerEm`](xref:SixLabors.Fonts.FontMetrics.UnitsPerEm) for the design-space resolution of the font
43
43
-[`ScaleFactor`](xref:SixLabors.Fonts.FontMetrics.ScaleFactor) for the face-level unit-to-point scaling used by glyph metrics
44
+
-[`XHeight`](xref:SixLabors.Fonts.FontMetrics.XHeight) and [`CapHeight`](xref:SixLabors.Fonts.FontMetrics.CapHeight) for the lowercase and capital letter heights in design units, or `0` when the font does not provide them
44
45
45
46
`UnitsPerEm` is the important anchor for understanding almost every other metric on the typeface. Values like ascenders, underline positions, or glyph advances are stored in font units and should be interpreted relative to that em square.
Copy file name to clipboardExpand all lines: articles/fonts/hinting.md
+45-20Lines changed: 45 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
-
# TrueType Hinting
1
+
# Font Hinting
2
2
3
-
Font hinting is the use of instructions in a font to adjust outline glyphs for a raster grid. In TrueType fonts, those instructions are bytecode programs stored in the font. The rasterizer executes them at a given size and DPI to move outline points before the glyph is drawn.
3
+
Font hinting adjusts outline glyphs for a raster grid. TrueType fonts carry bytecode programs that move outline points at a given size and DPI. CFF fonts declare stem hints and alignment zones that a rasterizer fits to the grid. Fonts supports both models.
4
4
5
5
## Why Hinting Exists
6
6
@@ -17,12 +17,13 @@ Hinting changes the scaled outline before rasterization. It can improve:
17
17
18
18
The effect is most visible for small UI text at ordinary screen DPI. At larger sizes or high-resolution outputs, the outline has more pixels available and hinting usually has less visible effect.
-[`HintingMode.Standard`](xref:SixLabors.Fonts.HintingMode.Standard) applies the library's FreeType v40-compatible TrueType hinting behavior.
25
+
-[`HintingMode.Standard`](xref:SixLabors.Fonts.HintingMode.Standard) fits outlines to the pixel grid on the vertical axis only. Horizontal placement stays smooth.
26
+
-[`HintingMode.Full`](xref:SixLabors.Fonts.HintingMode.Full) fits outlines and glyph origins to the pixel grid on both axes. This reproduces the classic bi-level grid fitting that font hints were originally authored for.
The active font size and [`Dpi`](xref:SixLabors.Fonts.TextOptions.Dpi) matter because hinting targets a specific pixels-per-em scale.
39
40
40
-
## Fonts' Hinting Approach
41
+
## Standard Hinting
41
42
42
-
Fonts uses a TrueType bytecode interpreter modeled on FreeType's v40 subpixel hinting behavior. In practical terms, that means Fonts preserves full vertical TrueType instruction processing while intentionally disabling horizontal hinting.
43
+
Standard hinting models FreeType's v40 subpixel hinting behavior. For TrueType fonts, it preserves full vertical instruction processing while intentionally disabling horizontal hinting. For CFF fonts, it fits the vertical axis only from the declared hints.
43
44
44
-
This approach is designed for modern antialiased text rendering, where horizontal subpixel placement should remain smooth and glyph advances should not be forced into old bi-level grid-fitting behavior. It gives small text the vertical alignment benefits of TrueType hinting while avoiding legacy horizontal snapping that can make spacing and shapes less consistent in modern raster output.
45
+
This mode is designed for modern antialiased text rendering, where horizontal subpixel placement remains smooth and glyph advances keep their fractional shaped values. It gives small text the vertical alignment benefits of hinting while avoiding legacy horizontal snapping that can make spacing less consistent.
45
46
46
-
When hinting is active, Fonts:
47
+
## Full Hinting
48
+
49
+
Full hinting reproduces the classic rasterizer pipeline. It produces the sharpest results at small sizes, at the cost of shape fidelity and spacing regularity.
50
+
51
+
Under full hinting, Fonts:
52
+
53
+
- rounds the em size to a whole number of pixels, with a minimum of one pixel
54
+
- executes the complete horizontal and vertical TrueType instruction set, or fits CFF outlines on both axes
55
+
- aligns glyph origins and text decorations to the pixel grid on both axes
56
+
- replaces fractional advances on the flow axis with whole-pixel advances
57
+
58
+
For TrueType fonts, the whole-pixel advance comes from the font's `hdmx` device record when the font carries one. Otherwise Fonts uses the hinted advance that instruction execution produced, or the design advance rounded to whole pixels for glyphs the interpreter could not hint. CFF fonts carry no device advance records, so the design advance rounds to whole pixels.
59
+
60
+
Whole-pixel advances change spacing. Fractional positioning adjustments on the flow axis, such as pair kerning, are dropped because the classic pipeline never applied them. Inter-glyph spacing can vary by up to half a pixel from the unhinted design. Measurement uses the same advances as rendering, so measured layout and rendered output stay in agreement.
61
+
62
+
Two cases keep their shaped fractional advances: subscript and superscript runs, and upright glyphs in vertical layout.
63
+
64
+
## The TrueType Pipeline
65
+
66
+
Fonts uses a TrueType bytecode interpreter. When hinting is active, Fonts:
47
67
48
68
- executes the font program from `fpgm` to initialize TrueType function definitions
49
69
- scales the Control Value Table from `cvt ` for the current size and DPI
@@ -54,27 +74,32 @@ When hinting is active, Fonts:
54
74
- executes each glyph's TrueType instructions against the resolved outline
55
75
- leaves the outline unhinted if a glyph has no instructions, hinting is inhibited by the font program, or instruction execution fails
56
76
57
-
## TrueType Scope
77
+
Some fonts are known to require hinting for correct rendering, and some are known to render badly with it. Fonts maintains compatibility lists that force such TrueType fonts to full hinting or to no hinting, regardless of the requested mode.
78
+
79
+
## The CFF Pipeline
58
80
59
-
Fonts applies this hinting path to TrueType outlines. It does not turn CFF or CFF2 outlines into hinted TrueType outlines, and it does not change which glyphs are selected for the text.
81
+
CFF outlines carry no instructions. Instead, the font declares the regularities in its design:
60
82
61
-
Within the TrueType path, Fonts supports:
83
+
- horizontal and vertical stem hints in each glyph's charstring
84
+
- hint masks and counter masks that control which stems apply in each region of the glyph
85
+
- alignment zones, standard stem widths, and related values in the Private DICT
62
86
63
-
- TrueType glyph instruction execution.
64
-
- Standard TrueType hinting tables such as `fpgm`, `prep`, and `cvt `.
65
-
- Per-glyph hinting at the active size and DPI.
66
-
-`cvar`-driven control-value adjustments for variable TrueType fonts before hinting runs.
67
-
- Hinted contour-point resolution for GPOS anchor data when a font uses contour-point anchors.
68
-
- Font-specific compatibility behavior for fonts known to require hinting.
87
+
When hinting is active, Fonts collects these declared hints while it evaluates the charstring, then fits the outline through a hint map. Standard hinting fits the vertical axis only, from the declared horizontal stem zones and alignment-zone flats. Full hinting fits both axes.
69
88
70
-
## When to Enable It
89
+
## Choosing a Mode
71
90
72
-
Use [`HintingMode.Standard`](xref:SixLabors.Fonts.HintingMode.Standard) when rendering small TrueType UI text to a raster target and you want grid-fitted outlines.
91
+
Use [`HintingMode.Standard`](xref:SixLabors.Fonts.HintingMode.Standard) when rendering small UI text to a raster target and you want grid-fitted outlines with smooth, fractional spacing.
92
+
93
+
Use [`HintingMode.Full`](xref:SixLabors.Fonts.HintingMode.Full) when you want the sharpest possible small text and accept the classic-rasterizer tradeoffs: whole-pixel spacing, dropped fractional kerning, and altered glyph shapes. It is also the mode to compare output against classic bi-level rasterizers.
73
94
74
95
Use [`HintingMode.None`](xref:SixLabors.Fonts.HintingMode.None) when you want raw outline behavior, when you are rendering large display text, or when the text is being treated as artwork rather than screen UI.
75
96
76
97
There is no universal best setting. Hinting is a raster-quality tradeoff: it can make small text clearer, but it can also move outlines away from their pure scaled design.
77
98
99
+
## Custom Renderers
100
+
101
+
The requested hinting mode is part of [`GlyphRendererParameters`](xref:SixLabors.Fonts.Rendering.GlyphRendererParameters). A renderer that caches glyph geometry can include the parameters in its cache key, so outlines fitted under one mode are never reused under another.
0 commit comments