Font Embedding and Substitution
A PDF looks the way it does because of its fonts, and a font that isn't available where the PDF is created is replaced by another. Replaced fonts change the width of text, and with it line and page breaks. For documents that must look the same wherever your Windows Forms application runs, and for PDF/A, which embeds every font, you decide which fonts a document may use and which font replaces a missing one.
Listing the fonts the editor supports is shown in Check the Fonts of a Document, and font problems as users see them are covered in Fonts and Document Layout in Troubleshooting.
Where the Fonts Come From
TX Text Control .NET for Windows Forms formats text with the fonts installed on Windows. Which of them it supports depends on the formatting device, the printer that FormattingPrinter names, and GetSupportedFonts returns their names.
A font is adapted, replaced by a supported one, in three situations:
- A document is loaded that uses a font that isn't supported.
- Another printer is set with
FormattingPrinter, which supports other fonts. - The fonts are restricted with
EmbeddableFontsOnlyorTrueTypeFontsOnlyofFontSettings, as the next section describes.
Restrict the Fonts of a Document
FontSettings decides which fonts a document may use. Its properties are false by default:
| Property | When true, a document may use |
|---|---|
| EmbeddableFontsOnly | Fonts that can be embedded without violating their licenses. TX Text Control treats only OpenType and TrueType fonts as embeddable. Required for PDF/A. |
| TrueTypeFontsOnly | TrueType and OpenType fonts |
| ScalableFontsOnly | Freely scalable fonts |
The TextControl.FontSettings property returns the settings of the editor, and ServerTextControl.FontSettings those of a ServerTextControl. Each instance has its own settings.
Choose the Replacement Fonts
By default, TX Text Control chooses the replacement itself. To use fonts of your choice, handle the AdaptFont event and set the replacement. The following code in Form1.cs allows TrueType and OpenType fonts only, replaces other fonts with the first available font of a list and shows which fonts were replaced after a DOCX template has been exported as PDF. It needs using System.Collections.Generic; at the top of the file:
private readonly string[] preferredFonts = { "Arial", "Segoe UI", "Times New Roman" };
private readonly List<string> replacedFonts = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
textControl1.FontSettings.TrueTypeFontsOnly = true;
textControl1.FontSettings.AdaptFontEvent = true;
textControl1.AdaptFont += TextControl1_AdaptFont;
}
private void TextControl1_AdaptFont(object sender, AdaptFontEventArgs e)
{
// Use the first preferred font that is available
foreach (string font in preferredFonts)
{
if (Array.IndexOf(e.SupportedFonts, font) >= 0)
{
e.AdaptedFontName = font;
break;
}
}
replacedFonts.Add(e.FontName + " -> " + e.AdaptedFontName);
}
private void loadAndExportButton_Click(object sender, EventArgs e)
{
replacedFonts.Clear();
textControl1.Load("template.docx", StreamType.WordprocessingML);
textControl1.Save("template.pdf", StreamType.AdobePDF);
if (replacedFonts.Count > 0)
{
MessageBox.Show("Replaced fonts:\n" + string.Join("\n", replacedFonts));
}
}
Connect Form1_Load to the Load event of the form in the Properties window, or double-click the form in the designer. The code works as follows:
- AdaptFontEvent must be
true, or the event doesn't occur. - FontName is the original font. AdaptedFontName holds the replacement that TX Text Control chose, and setting it chooses another one.
- The new font must be one of the SupportedFonts. The loop checks this, and when no font of the list is available, TX Text Control's choice stays.
Fonts in a ServerTextControl
A ServerTextControl has its own FontSettings and its own AdaptFont event, and the settings of the editor don't apply to it. Make the settings after Create and before Load, so that they apply to the fonts of the loaded document:
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.FontSettings.TrueTypeFontsOnly = true;
tx.FontSettings.AdaptFontEvent = true;
tx.AdaptFont += TextControl1_AdaptFont;
tx.Load("template.docx", StreamType.WordprocessingML);
tx.Save("template.pdf", StreamType.AdobePDF);
}
The handler of the previous section works for both, because AdaptFontEventArgs is the same class. Its SupportedFonts are those of the ServerTextControl, which has its own FormattingPrinter.
Embed Fonts in PDF/A
A PDF/A document must contain its fonts, so EmbeddableFontsOnly must be true before the document is saved with StreamType.AdobePDFA. A font can't be embedded when its license forbids it or when it depends on a device. With the setting, such fonts are replaced, and AdaptFont occurs for each of them. A document that still contains a font that can't be embedded throws a FilterException with the reason NonEmbeddableFont when it is saved.
PDF/A shows the complete save, and A Document Can't Be Saved as PDF/A lists the error messages.
Get the Same Result on Every Machine
The fonts installed on Windows differ between machines, and so do the default printers. To make the PDF of a document the same wherever your application runs:
- Use fonts that every target machine has, or install the fonts your templates use with your application, if their licenses allow it.
- Set the formatting printer. The Layout Depends on the Printer explains how
FormattingPrinteraffects the supported fonts and the layout. - Check templates before you deploy them. The blog article Check TX Text Control Template Dependencies Before Deployment lists the fonts a template needs.
Next Steps
- PDF/A: save documents with embedded fonts for archiving.
- PDF Creation and Conversion: the other options of a PDF.
- Fonts and Document Layout: fix fonts that look different than expected.