Subsetting

edit

A document that embeds a font, such as a PDF file, only needs the glyphs it draws. FontSubsetter makes a font program with these glyphs only:

static byte[] Subset(FontFace face, string text)
{
    // The glyphs the document uses; the closure adds the glyph 0 and the components of composite glyphs
    var glyphs = new HashSet<int>();
    foreach (var rune in text.EnumerateRunes())
    {
        glyphs.Add(face.MapCodePoint(rune.Value));
    }

    // A font program to embed in a document that refers to the glyphs by their identifiers, such as a PDF file:
    // the identifiers are kept, the other glyphs are empty, and there is no character map
    return face.Outlines is FontOutlineKind.TrueType
        ? FontSubsetter.SubsetTrueType(face, glyphs, keepHinting: false)
        : throw new NotSupportedException("SubsetCff gives the CFF table of a font with CFF outlines");
}
  • The glyph identifiers are kept: the glyphs that are not kept are empty, so that what refers to a glyph by its identifier, such as a PDF content stream or a shaped text, is unchanged.
  • GetClosure gives the glyphs a subset keeps: the requested glyphs, the glyph 0 (.notdef) and the components of the composite glyphs. Identifiers that are not glyphs of the face are ignored.
MethodOutlinesResult
SubsetTrueTypeTrueType (FontOutlineKind.TrueType)A font file with the glyf and loca tables rebuilt, the metrics tables (head, hhea, hmtx, maxp), OS/2 and name, a post table without glyph names, and the instructions when keepHinting is set
SubsetCffCFF (FontOutlineKind.Cff)A CID-keyed CFF table whose CIDs are the glyph identifiers: the charstrings of the glyphs that are not kept end at once, and the subroutines are kept whole

The result is a font program to embed, not a font to install: it has no character map and no layout tables. A method called with a face whose outlines are of the other kind throws an ArgumentException.