Class Typeface
One font face: its names, style, metrics, character map, glyph outlines and kerning, read from a TrueType or OpenType font, a collection, or a bare CFF stream. Immutable and safe to share across threads, canvases and backends.
public sealed class Typeface
- Inheritance
-
Typeface
- Inherited Members
Examples
// One face from a file; a collection takes an index. The bytes are read once and every table is parsed when first needed.
Typeface face = Typeface.FromFile(FontFile);
Console.WriteLine($"{face.FamilyName} {face.SubfamilyName}, {face.GlyphCount} glyphs, {face.UnitsPerEm} units per em");
// What a file holds, from its header alone.
FontProbe probe = FontLoader.Probe(File.ReadAllBytes(FontFile));
Console.WriteLine($"{probe.Kind}, {probe.FaceCount} face(s), {probe.Outlines} outlines");
// Damaged fonts load leniently with diagnostics; Strict throws instead.
var seen = new List<EgamiDiagnostic>();
var options = new FontLoadOptions { Context = EgamiContext.Default with { Diagnostics = seen.Add } };
Typeface lenient = Typeface.FromMemory(File.ReadAllBytes(FontFile), 0, options);
Remarks
Loading reads the table directory, head and maxp, and checks that glyph data is there; every other table is parsed the first time it is needed and kept. The font's bytes are held once, as the ReadOnlyMemory<T> given or read, and every table is a slice of them. Memory given to FromMemory(ReadOnlyMemory<byte>, int, FontLoadOptions?) must not change afterwards.
Loading is lenient by default: see FontLoadOptions for the defaults damaged or missing tables get and the diagnostics they raise. All glyph metrics and outlines are in font units with y up; Font scales them to a size.
Properties
BuiltInEncoding
Gets a name-keyed CFF font's own encoding (bare, or the CFF table of an OpenType font) as FreeType presents it: a CharacterMap with platform 7 and encoding 0 (the Standard Encoding), 1 (the Expert Encoding) or 2 (a custom encoding) that maps character codes 0 to 255 to glyphs. Null for CID-keyed, CFF2 and TrueType fonts.
public CharacterMap? BuiltInEncoding { get; }
Property Value
Remarks
PDF uses it for a Type1C font whose font dictionary gives no /Encoding.
CharacterMaps
Gets every cmap subtable of the face as stored, in table order, but the format 14 variation sequences (which GetGlyph(int, int) uses); empty for a bare CFF font or a face without a cmap table.
public IReadOnlyList<CharacterMap> CharacterMaps { get; }
Property Value
Examples
// A symbolic TrueType font in PDF looks a code up in (3,0) first, then (1,0); a non-symbolic one uses (3,1).
CharacterMap? map = trueType.FindCharacterMap(3, 0) ?? trueType.FindCharacterMap(1, 0) ?? trueType.FindCharacterMap(3, 1);
ushort forA = map?.GetGlyph('A') ?? 0;
// A Type1C font without /Encoding uses the CFF program's own encoding.
CharacterMap? own = face.BuiltInEncoding; // platform 7, encoding 0: the Standard Encoding
ushort forB = own?.GetGlyph('B') ?? 0;
// Every code the map gives a glyph, in code order, for a PDF writer's /Widths or a ToUnicode table.
int mapped = map?.GetMappings().Count() ?? 0;
Remarks
GetGlyph(int) keeps choosing its one Unicode subtable as before; these maps are for callers that need a particular one, such as PDF's (3,0) or (1,0) for a symbolic TrueType font and (3,1) otherwise.
CidSystemInfo
Gets the character collection of a CID-keyed CFF font (bare, or the CFF table of an OpenType font), such as Adobe-Identity-0; null for every other font.
public CidSystemInfo? CidSystemInfo { get; }
Property Value
ColorFormats
Gets the kinds of color glyph data the face holds; None for a plain outline font.
public ColorGlyphFormats ColorFormats { get; }
Property Value
Container
Gets the container the face was read from: Sfnt, Collection, Cff, or Woff and Woff2 for a web font, whose tables TryGetTable(FontTag, out ReadOnlyMemory<byte>) returns decoded.
public FontFileKind Container { get; }
Property Value
Embedding
Gets the embedding permissions the face declares (OS/2 fsType). Egami never enforces them.
public FontEmbedding Embedding { get; }
Property Value
Extents
Gets the face's vertical metrics and decoration positions in font units; see FontExtents for the rule.
public FontExtents Extents { get; }
Property Value
FaceIndex
Gets the face's index in its collection, 0 for a single font.
public int FaceIndex { get; }
Property Value
FamilyName
Gets the typographic family name in English (name ID 16, else 1), such as "Noto Sans"; "Unknown" when the font has none.
public string FamilyName { get; }
Property Value
FullName
Gets the full name in English (name ID 4), such as "Noto Sans Bold Italic".
public string FullName { get; }
Property Value
GlyphCount
Gets the number of glyphs.
public int GlyphCount { get; }
Property Value
HasCharacterMap
Gets whether the face maps characters to glyphs; false for a bare CFF font or a font without a usable cmap.
public bool HasCharacterMap { get; }
Property Value
HasKerning
Gets whether the face has pair kerning, from GPOS or the kern table.
public bool HasKerning { get; }
Property Value
HheaMetrics
Gets the hhea table's ascender, descender and line gap; zeros when the font has no hhea.
public VerticalMetrics HheaMetrics { get; }
Property Value
IsFixedPitch
Gets whether every glyph has the same advance (post isFixedPitch, or the CFF isFixedPitch entry).
public bool IsFixedPitch { get; }
Property Value
IsVariable
Gets whether the face is a variable font (it has an fvar table with at least one axis).
public bool IsVariable { get; }
Property Value
Layout
Gets what the face's OpenType layout tables offer: scripts, language systems and features.
public OpenTypeLayout Layout { get; }
Property Value
NamedInstances
Gets the named instances of a variable font, such as "Bold"; empty for a static font.
public IReadOnlyList<NamedInstance> NamedInstances { get; }
Property Value
Outlines
Gets how the face stores its outlines.
public FontOutlines Outlines { get; }
Property Value
Palettes
Gets the face's CPAL palettes; empty when it has none.
public IReadOnlyList<FontPaletteInfo> Palettes { get; }
Property Value
PostScriptName
Gets the PostScript name (name ID 6, or the CFF font name), such as "NotoSans-BoldItalic", which PDF uses as BaseFont.
public string PostScriptName { get; }
Property Value
Style
Gets the weight, width and slant the face declares in OS/2 (or head and post when OS/2 is missing).
public FontStyle Style { get; }
Property Value
SubfamilyName
Gets the typographic subfamily name in English (name ID 17, else 2), such as "Bold Italic"; "Regular" when the font has none.
public string SubfamilyName { get; }
Property Value
TypoMetrics
Gets the OS/2 typo ascender, descender and line gap; zeros when the font has no OS/2.
public VerticalMetrics TypoMetrics { get; }
Property Value
UnitsPerEm
Gets the font units per em, 16 to 16384.
public int UnitsPerEm { get; }
Property Value
VariationAxes
Gets the axes of a variable font, in fvar order; empty for a static font.
public IReadOnlyList<VariationAxis> VariationAxes { get; }
Property Value
Variations
Gets this face's position: one value per axis that is not at its default, in fvar order; empty for the default position and for a static font.
public IReadOnlyList<FontVariation> Variations { get; }
Property Value
WinMetrics
Gets the OS/2 Windows ascent and descent (the descent made negative), with a zero line gap.
public VerticalMetrics WinMetrics { get; }
Property Value
Methods
FindCharacterMap(int, int)
Finds the first character map with a platform and encoding, as stored (without translating codes).
public CharacterMap? FindCharacterMap(int platformId, int encodingId)
Parameters
platformIdintThe platform: 0 Unicode, 1 Macintosh, 3 Windows; 7 gives BuiltInEncoding.
encodingIdintThe encoding within the platform, such as 1 for (3,1) or 0 for (1,0).
Returns
- CharacterMap
The map, or null when the face has none for that pair.
FromCff(ReadOnlyMemory<byte>, CffOptions?)
Loads a bare CFF stream as PDF embeds it (FontFile3 with subtype Type1C or CIDFontType0C). The face has no character map: glyphs are reached by id, or by CID through the charset for a CID-keyed font.
public static Typeface FromCff(ReadOnlyMemory<byte> data, CffOptions? options = null)
Parameters
dataReadOnlyMemory<byte>The CFF data, kept and not copied.
optionsCffOptions
Returns
- Typeface
The face.
Examples
// A CFF stream as a PDF embeds it (FontFile3): no character map, glyphs by id; widths from the PDF when it gives them.
Typeface embedded = Typeface.FromCff(fontFile3, new CffOptions { UnitsPerEm = 1000 });
float width = embedded.GetAdvance(1);
Exceptions
- UnsupportedFormatException
The data is CFF2 or uses Type 1 charstrings.
- CorruptDataException
The CFF structures cannot be read.
- LimitExceededException
The data is larger than the context's MaxTotalBytes.
FromFile(string, int, FontLoadOptions?)
Loads one face from a font file, reading the whole file into memory and closing it.
public static Typeface FromFile(string path, int index = 0, FontLoadOptions? options = null)
Parameters
pathstringThe file: .ttf, .otf, .ttc, .otc, .woff, .woff2 or a bare CFF stream.
indexintThe face to load from a collection; 0 for a single font.
optionsFontLoadOptions
Returns
- Typeface
The face.
Examples
// One face from a file; a collection takes an index. The bytes are read once and every table is parsed when first needed.
Typeface face = Typeface.FromFile(FontFile);
Console.WriteLine($"{face.FamilyName} {face.SubfamilyName}, {face.GlyphCount} glyphs, {face.UnitsPerEm} units per em");
// What a file holds, from its header alone.
FontProbe probe = FontLoader.Probe(File.ReadAllBytes(FontFile));
Console.WriteLine($"{probe.Kind}, {probe.FaceCount} face(s), {probe.Outlines} outlines");
// Damaged fonts load leniently with diagnostics; Strict throws instead.
var seen = new List<EgamiDiagnostic>();
var options = new FontLoadOptions { Context = EgamiContext.Default with { Diagnostics = seen.Add } };
Typeface lenient = Typeface.FromMemory(File.ReadAllBytes(FontFile), 0, options);
Exceptions
- ArgumentOutOfRangeException
indexis not a face of the file.- UnsupportedFormatException
The file is not a font Egami reads.
- CorruptDataException
The font has no readable glyph data, or is damaged and Strict is set.
- LimitExceededException
The file is larger than the context's MaxTotalBytes.
FromMemory(ReadOnlyMemory<byte>, int, FontLoadOptions?)
Loads one face from memory, which is kept, not copied, and must not change afterwards. A WOFF or WOFF2 file is unwrapped into an sfnt in new memory once, and the compressed input is not kept.
public static Typeface FromMemory(ReadOnlyMemory<byte> data, int index = 0, FontLoadOptions? options = null)
Parameters
dataReadOnlyMemory<byte>The font data: an sfnt, a collection, a WOFF or WOFF2 file, or a bare CFF stream.
indexintThe face to load from a collection; 0 for a single font.
optionsFontLoadOptions
Returns
- Typeface
The face.
Examples
// One face from a file; a collection takes an index. The bytes are read once and every table is parsed when first needed.
Typeface face = Typeface.FromFile(FontFile);
Console.WriteLine($"{face.FamilyName} {face.SubfamilyName}, {face.GlyphCount} glyphs, {face.UnitsPerEm} units per em");
// What a file holds, from its header alone.
FontProbe probe = FontLoader.Probe(File.ReadAllBytes(FontFile));
Console.WriteLine($"{probe.Kind}, {probe.FaceCount} face(s), {probe.Outlines} outlines");
// Damaged fonts load leniently with diagnostics; Strict throws instead.
var seen = new List<EgamiDiagnostic>();
var options = new FontLoadOptions { Context = EgamiContext.Default with { Diagnostics = seen.Add } };
Typeface lenient = Typeface.FromMemory(File.ReadAllBytes(FontFile), 0, options);
Exceptions
- ArgumentOutOfRangeException
indexis not a face of the data.- UnsupportedFormatException
The data is not a font Egami reads.
- CorruptDataException
The font has no readable glyph data, or is damaged and Strict is set.
- LimitExceededException
The data is larger than the context's MaxTotalBytes.
FromStream(Stream, int, FontLoadOptions?)
Loads one face from a stream, reading it to the end.
public static Typeface FromStream(Stream stream, int index = 0, FontLoadOptions? options = null)
Parameters
streamStreamThe stream; it is read but not closed.
indexintThe face to load from a collection; 0 for a single font.
optionsFontLoadOptions
Returns
- Typeface
The face.
Examples
// One face from a file; a collection takes an index. The bytes are read once and every table is parsed when first needed.
Typeface face = Typeface.FromFile(FontFile);
Console.WriteLine($"{face.FamilyName} {face.SubfamilyName}, {face.GlyphCount} glyphs, {face.UnitsPerEm} units per em");
// What a file holds, from its header alone.
FontProbe probe = FontLoader.Probe(File.ReadAllBytes(FontFile));
Console.WriteLine($"{probe.Kind}, {probe.FaceCount} face(s), {probe.Outlines} outlines");
// Damaged fonts load leniently with diagnostics; Strict throws instead.
var seen = new List<EgamiDiagnostic>();
var options = new FontLoadOptions { Context = EgamiContext.Default with { Diagnostics = seen.Add } };
Typeface lenient = Typeface.FromMemory(File.ReadAllBytes(FontFile), 0, options);
Exceptions
- ArgumentOutOfRangeException
indexis not a face of the data.- UnsupportedFormatException
The data is not a font Egami reads.
- CorruptDataException
The font has no readable glyph data, or is damaged and Strict is set.
- LimitExceededException
The data is larger than the context's MaxTotalBytes.
GetAdvance(ushort)
Gets a glyph's advance width in font units: hmtx, or for a bare CFF font the given or charstring width.
public float GetAdvance(ushort glyph)
Parameters
glyphushortThe glyph id.
Returns
- float
The advance; 0 for a glyph id past GlyphCount.
GetCid(ushort)
Gets the CID of a glyph of a CID-keyed CFF font (its charset entry), as FreeType's FT_Get_CID_From_Glyph_Index does.
public int GetCid(ushort glyph)
Parameters
glyphushortThe glyph id.
Returns
- int
The CID; -1 for a font that is not CID-keyed or a glyph past GlyphCount.
Examples
// A CIDFontType0 font with /CIDToGIDMap absent reaches glyphs by CID through the CFF charset.
CidSystemInfo? collection = cjk.CidSystemInfo; // Adobe-Identity-0 for this font
ushort glyph = cjk.TryGetGlyphByCid(1, out ushort byCid) ? byCid : (ushort)0;
int cid = cjk.GetCid(glyph);
GetGlyph(int)
Maps a Unicode code point to a glyph id through the character map.
public ushort GetGlyph(int codePoint)
Parameters
codePointintThe code point, 0 to 0x10FFFF.
Returns
- ushort
The glyph, or 0 (.notdef) when the face has none for the code point.
GetGlyph(int, int)
Maps a code point followed by a variation selector, such as U+FE0E, through the format 14 subtable.
public ushort GetGlyph(int codePoint, int variationSelector)
Parameters
codePointintThe base code point.
variationSelectorintThe selector, U+FE00 to U+FE0F or U+E0100 to U+E01EF.
Returns
- ushort
The glyph for the sequence, else the base glyph, else 0.
GetGlyphExtents(ushort)
Gets the box around a glyph's ink in font units: from the glyph header for TrueType, from the curves' extremes for CFF.
public GlyphExtents GetGlyphExtents(ushort glyph)
Parameters
glyphushortThe glyph id.
Returns
- GlyphExtents
The box; empty for a glyph without ink, past GlyphCount or damaged.
GetGlyphName(ushort)
Gets a glyph's name: from the charset of a name-keyed CFF font (bare, or the CFF table of an OpenType font), else from the post table (versions 1, 2 and 2.5), as FreeType's FT_Get_Glyph_Name gives it.
public string? GetGlyphName(ushort glyph)
Parameters
glyphushortThe glyph id.
Returns
- string
The name, such as "Aacute"; null for a glyph past GlyphCount, for a font without names (a CID-keyed CFF font, post versions 3 and 4) or for a damaged entry, which also reports a warning.
Examples
// A PDF simple font's /Differences array names glyphs: find each by name, and get names back for a ToUnicode guess.
ushort aacute = face.TryGetGlyphByName("aacute", out ushort g) ? g : (ushort)0;
string? name = face.GetGlyphName(aacute);
GetGlyphOutline(ushort, IGlyphOutlineSink)
Sends a glyph's outline to sink in font units with y up.
public bool GetGlyphOutline(ushort glyph, IGlyphOutlineSink sink)
Parameters
glyphushortThe glyph id.
sinkIGlyphOutlineSinkThe receiver.
Returns
- bool
true if the outline was sent (a glyph without ink sends nothing); false if the glyph id is past GlyphCount or its data is damaged, which raises
Font.BadGlyph(or throws in strict mode).
GetKerning(ushort, ushort)
Gets the pair kerning between two glyphs in font units: GPOS pair positioning, else the kern table.
public float GetKerning(ushort left, ushort right)
Parameters
Returns
- float
The adjustment to the first glyph's advance, usually negative; 0 when the pair is not kerned.
GetLeftSideBearing(ushort)
Gets a glyph's left side bearing in font units: hmtx, or the left edge of its outline when there is no hmtx.
public float GetLeftSideBearing(ushort glyph)
Parameters
glyphushortThe glyph id.
Returns
- float
The bearing; 0 for a glyph id past GlyphCount.
GetNames()
Gets every decoded string of the naming table, in every language present.
public IReadOnlyList<FontNameRecord> GetNames()
Returns
- IReadOnlyList<FontNameRecord>
The records, in table order; empty when the font has no name table.
GetWoffMetadata()
Gets the extended metadata block of a WOFF or WOFF2 file, decompressed: XML in UTF-8, as the W3C WOFF specifications define it.
public string? GetWoffMetadata()
Returns
GetWoffPrivateData()
Gets the private data block of a WOFF or WOFF2 file, whose meaning only its vendor knows.
public ReadOnlyMemory<byte> GetWoffPrivateData()
Returns
- ReadOnlyMemory<byte>
The bytes; empty when the face is not from a web font or the file has none.
HasColorGlyph(ushort)
Gets whether a glyph has color data in any format this face draws (not counting SVG), without reading it.
public bool HasColorGlyph(ushort glyph)
Parameters
glyphushortThe glyph.
Returns
MapCodePoints(ReadOnlySpan<char>, Span<ushort>)
Maps text to glyphs, one per code point: surrogate pairs become one glyph, and a variation selector changes the glyph before it instead of adding one.
public int MapCodePoints(ReadOnlySpan<char> text, Span<ushort> glyphs)
Parameters
textReadOnlySpan<char>The UTF-16 text.
glyphsSpan<ushort>The glyphs, at least as long as
text.
Returns
- int
The number of glyphs written.
Exceptions
- ArgumentException
glyphsis shorter thantext.
ToString()
Returns the full name, such as "Noto Sans Bold".
public override string ToString()
Returns
- string
The text.
TryGetColorGlyph(ushort, FontPalette?, out ColorGlyph?, float)
Gets a glyph's color description in the first format that has it: COLR version 1, then version 0, then sbix, then CBDT
(OpenType SVG glyphs are not drawn; see TryGetSvgDocument(ushort, out ReadOnlyMemory<byte>, out ushort, out ushort)). COLR graphs are read at this face's variation
position with the palette's colors; bitmaps come from the strike for pixelsPerEm.
public bool TryGetColorGlyph(ushort glyph, FontPalette? palette, out ColorGlyph? colorGlyph, float pixelsPerEm = 0)
Parameters
glyphushortThe glyph.
paletteFontPalettecolorGlyphColorGlyphThe color glyph, or null.
pixelsPerEmfloatThe size the glyph is drawn at, for choosing a bitmap strike: the smallest at or above it, else the largest; 0 for the largest.
Returns
Examples
// Color glyphs draw in color by themselves: COLR (layers and gradients), sbix and CBDT (images), per glyph.
using (RasterCanvas<Rgba8> canvas = image.CreateCanvas())
{
canvas.DrawText("Ship it", new Vector2(8, 40), new Font(text, 24), Rgba8.Black);
canvas.DrawText("\U0001F680\U0001F389", new Vector2(100, 42), new Font(emoji, 32), Rgba8.Black);
}
// The palette is a font setting; the paint's color fills a glyph's foreground parts and its alpha the whole glyph.
var darkMode = new Font(emoji, 32) { Palette = FontPalette.Dark };
ColorGlyphFormats formats = emoji.ColorFormats;
// The paint graph is there to walk, for writers that draw color glyphs their own way.
emoji.TryGetColorGlyph(emoji.GetGlyph(0x1F680), darkMode.Palette, out ColorGlyph? rocket);
TryGetGlyph(int, out ushort)
Maps a code point to a glyph, saying whether the face has one.
public bool TryGetGlyph(int codePoint, out ushort glyph)
Parameters
Returns
TryGetGlyphByCid(int, out ushort)
Finds the glyph with a CID in a CID-keyed CFF font; when several share it, the lowest glyph id.
public bool TryGetGlyphByCid(int cid, out ushort glyph)
Parameters
Returns
TryGetGlyphByName(string, out ushort)
Finds the glyph with a name; when several share it, the lowest glyph id, as FreeType's FT_Get_Name_Index does.
public bool TryGetGlyphByName(string name, out ushort glyph)
Parameters
namestringThe glyph name, compared ordinally.
glyphushortThe glyph id, or 0 when no glyph has the name.
Returns
Exceptions
- ArgumentNullException
nameis null.
TryGetSvgDocument(ushort, out ReadOnlyMemory<byte>, out ushort, out ushort)
Gets the OpenType SVG document holding a glyph, decompressed when it is gzipped, for callers that draw SVG themselves; Egami
draws such glyphs from their COLR, bitmap or outline data instead (SVG drawing arrives with Egami.Svg). The glyph's
element in it has the id glyph followed by the glyph id.
public bool TryGetSvgDocument(ushort glyph, out ReadOnlyMemory<byte> document, out ushort firstGlyph, out ushort lastGlyph)
Parameters
glyphushortThe glyph.
documentReadOnlyMemory<byte>The document's UTF-8 bytes.
firstGlyphushortThe first glyph the document covers.
lastGlyphushortThe last glyph the document covers.
Returns
Examples
// Color glyphs draw in color by themselves: COLR (layers and gradients), sbix and CBDT (images), per glyph.
using (RasterCanvas<Rgba8> canvas = image.CreateCanvas())
{
canvas.DrawText("Ship it", new Vector2(8, 40), new Font(text, 24), Rgba8.Black);
canvas.DrawText("\U0001F680\U0001F389", new Vector2(100, 42), new Font(emoji, 32), Rgba8.Black);
}
// The palette is a font setting; the paint's color fills a glyph's foreground parts and its alpha the whole glyph.
var darkMode = new Font(emoji, 32) { Palette = FontPalette.Dark };
ColorGlyphFormats formats = emoji.ColorFormats;
// The paint graph is there to walk, for writers that draw color glyphs their own way.
emoji.TryGetColorGlyph(emoji.GetGlyph(0x1F680), darkMode.Palette, out ColorGlyph? rocket);
Exceptions
- CorruptDataException
The document is damaged and strict loading is set.
TryGetTable(FontTag, out ReadOnlyMemory<byte>)
Gets a table's bytes as stored in the font, without parsing them.
public bool TryGetTable(FontTag tag, out ReadOnlyMemory<byte> data)
Parameters
tagFontTagThe table tag, such as
new FontTag("GSUB").dataReadOnlyMemory<byte>The table's bytes, a slice of the font's memory.
Returns
WithNamedInstance(int)
Returns the face at one of its named instances.
public Typeface WithNamedInstance(int index)
Parameters
indexintThe instance's index in NamedInstances.
Returns
- Typeface
The face at the instance's position.
Exceptions
- ArgumentOutOfRangeException
indexis not an instance of the face.
WithVariations(params ReadOnlySpan<FontVariation>)
Returns this face at another position on its axes, sharing the file's memory and parsed tables: outlines, advances, extents, kerning, names and subsets all answer for that position. Axes not named keep this face's values; values clamp to each axis's range; a tag the font repeats sets every axis with it; axes the font does not have are ignored.
public Typeface WithVariations(params ReadOnlySpan<FontVariation> variations)
Parameters
variationsReadOnlySpan<FontVariation>The axis values, such as
FontVariation.Weight(650).
Returns
- Typeface
The face at that position: the default face when every axis is at its default, this face for a static font.
Examples
// A variable font's axes and named instances, and the face at any position on them.
Typeface flex = Typeface.FromFile(VariableFile);
foreach (VariationAxis axis in flex.VariationAxes)
{
Console.WriteLine($"{axis.Tag} {axis.Name}: {axis.Min} to {axis.Max}, default {axis.Default}");
}
Typeface semiBold = flex.WithVariations(FontVariation.Weight(600), FontVariation.Width(90));
Typeface black = flex.WithNamedInstance(flex.NamedInstances.Count - 1);
// The optical size follows the font size unless the face sets it (OpticalSizing.None turns that off).
var caption = new Font(semiBold, 11);
Typeface drawn = caption.EffectiveTypeface;
// For a PDF, the subset is a static font at the face's position, which every viewer draws as it is.
FontSubset subset = FontSubsetter.Subset(semiBold, caption.Shape("Static at 600").Glyphs.ToArray());