Example T1252015
Visible to All Users

Reporting for WinForms - Obtain Missing Fonts from a Font Hosting Service (Google Fonts)

Your report design and layout may rely on a font type that is not available in the application's hosting environment. The font may not be installed on the client machine, in a Docker image, in an Azure Virtual Desktop, or in another host/container. In such instances, your report will substitute unavailable fonts with default options. Once a font is substituted, a report may not appear as expected/designed.

DevExpress Reports suite helps you ensure that a report uses correct fonts regardless of the hosting environment. A report notifies you about missing typefaces so you can obtain required font data. Once you obtain the fonts, add them to your report's DXFontRepository and thus make the fonts available to individual report elements/controls.

You can obtain required font data from any font hosting service. This example illustrates a service that downloads missing fonts from Google Fonts.

[!Note]
Review license agreements associated with fonts that you use. Use and redistribution permissions may vary. The service used in this example (Google Fonts) hosts fonts that are open source and without cost. Review Google Fonts FAQ to learn more.

Example Details

The report in this example contains a few fonts that may be missing in many hosting environments: Ga Maamli, Roboto, and Nerko One. The example obtains these fonts if missing and make them available to report controls. When exported to PDF, the report uses the original fonts (result.pdf):

Report PDF file uses typefaces obtained from Google Fonts

Implementation

The DXFontRepository.QueryNotFoundFont event fires for every unavailable font type. The event handler does the following:

  • Identifies the missing typeface and its suggested alternative (e.RequestedFont and e.ActualFont)
  • Obtains the required font file from Google Fonts
  • Prepares a byte array and passes it to e.FontFileData

This implementation ensures that DXFontRepository contains all required font types before document generation begins.

[!Important]
Use your personal Google API Key to run this example. For instructions on how to obtain your key, see Google Fonts Developer API.

Assign your API Key to the apiKey variable in the FontCollectorService.cs file before you launch the example.

Files to Review

Documentation

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

LoadMissingFonts/FontCollectorService.cs
C#
using System.IO; using System.Net.Http; using System.Text.Json; namespace LoadMissingFonts { public class FontCollectorService { class MyFont { public string? Family { get; set; } public string? Menu { get; set; } public Files? Files { get; set; } } class MyFontList { public List<MyFont>? Items { get; set; } } class Files { public string? regular { get; set; } } string apiKey = "YOUR_API_KEY"; string fontApiUrl = "https://www.googleapis.com/webfonts/v1/webfonts/?family="; async Task<byte[]?> LoadFontFromGoogle(string fontName) { string fontUrl = $"{fontApiUrl}{fontName}&key={apiKey}"; using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync(fontUrl).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); return null; } string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); MyFontList? webfontList = JsonSerializer.Deserialize<MyFontList>(content,new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); return await LoadFontFile(webfontList.Items[0].Files.regular).ConfigureAwait(false); } } async Task<byte[]?> LoadFontFile(string fontUrl) { using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync(fontUrl).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); return null; } using (MemoryStream fileStream = new MemoryStream()) { await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); return fileStream.ToArray(); } } } public Task<byte[]?> ProcessFont(string fontName) { return LoadFontFromGoogle(fontName); } } }
LoadMissingFonts/Form1.cs
C#
using DevExpress.Drawing; using DevExpress.XtraReports.UI; using FontDemoReport; namespace LoadMissingFonts { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { using (var report = new DemoReport()) { DXFontRepository.QueryNotFoundFont += Report_QueryNotFoundFont; using (var tool = new ReportPrintTool(report)) { tool.ShowRibbonPreviewDialog(); } } Close(); } private static void Report_QueryNotFoundFont(object sender, NotFoundFontEventArgs e) { var service = new FontCollectorService(); var fontData = service.ProcessFont(e.RequestedFont).Result; e.FontFileData = fontData; } } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.