DEV Community

IronSoftware
IronSoftware

Posted on

PDFsharp and .NET Core: Font Resolution and Cross-Platform Deployment (Fixed)

Migrating a PDFsharp project from .NET Framework to .NET Core, .NET 6, or .NET 8 often results in runtime exceptions related to fonts, System.Drawing, or missing platform dependencies. The original PDFsharp library was built around Windows-specific APIs, and while recent versions have added cross-platform support, developers continue to encounter obstacles when deploying to Linux servers, Docker containers, or macOS environments.

The Problem

PDFsharp's architecture historically relied on System.Drawing.Common and GDI+ for two critical operations: font resolution and image handling. When Microsoft deprecated System.Drawing.Common for non-Windows platforms in .NET 6+, PDFsharp users faced a choice between staying on Windows-only builds or navigating a complex migration path.

The official PDFsharp 6.x release introduced a "Core" build that removes the GDI+ dependency, but this creates a new problem: the Core build has no built-in font resolution strategy for non-Windows platforms. Developers must implement a custom IFontResolver interface before any text can be rendered to a PDF.

This manifests in several ways depending on the deployment environment:

  • Attempting to create an XFont object throws an exception stating no fonts are available
  • Applications that worked in development on Windows fail when deployed to Linux containers
  • PDF generation succeeds but uses incorrect or fallback fonts, producing unexpected output
  • Docker deployments require additional configuration that documentation does not clearly explain

Error Messages and Symptoms

The most common error when running PDFsharp Core on Linux or macOS:

System.InvalidOperationException: No appropriate font found.
at PdfSharp.Fonts.PlatformFontResolver.ResolveTypeface(String familyName, Boolean isBold, Boolean isItalic)
Enter fullscreen mode Exit fullscreen mode

When using the older PDFsharp 1.5x with .NET Core:

System.TypeLoadException: Could not resolve type with token 01000060 from typeref
(expected class 'System.Drawing.Graphics' in assembly 'System.Drawing.Common, Version=4.0.0.0')
Enter fullscreen mode Exit fullscreen mode

Docker containers running Alpine Linux may show:

System.DllNotFoundException: Unable to load shared library 'user32.dll' or one of its dependencies
Enter fullscreen mode Exit fullscreen mode

And when the PlatformFontResolver fails to locate system fonts:

InvalidOperationException: No Fonts installed on this device
Enter fullscreen mode Exit fullscreen mode

Who Is Affected

This issue impacts developers in several scenarios.

Cloud and Container Deployments: Applications running on AWS Lambda, Azure Functions, Google Cloud Run, or Kubernetes clusters with Linux-based containers cannot use PDFsharp without significant configuration work. The typical development workflow of building on Windows and deploying to Linux breaks down.

Cross-Platform Applications: .NET MAUI, Blazor WebAssembly, and other cross-platform frameworks cannot rely on PDFsharp's default font resolution. Each target platform requires explicit font handling code.

CI/CD Pipelines: Build servers running Linux agents may fail tests or produce different PDF output than developer machines running Windows, creating inconsistent behavior between environments.

Framework Versions: The compatibility matrix is complex:

  • PDFsharp 1.5x works with .NET Framework 4.x but has limited .NET Core support
  • PDFsharp 6.x targets .NET 6, .NET 8, .NET 9, and .NET 10
  • The -GDI and -WPF variants only work on Windows
  • The Core variant works cross-platform but requires custom font resolver implementation

Evidence from the Developer Community

The challenges with PDFsharp on .NET Core have been documented across multiple platforms since 2020.

Timeline

Date Event Source
2020-02-05 Stack Overflow question confirms PDFsharp does not work with .NET Core Stack Overflow
2021-08-20 PdfSharpCore users report font resolution failures in Linux containers GitHub
2022-03-15 GitHub issue documents .NET 6 incompatibility with PDFsharp 1.50 GitHub
2022-06-10 Forum thread describes System.Drawing.Common errors PDFsharp Forum
2023-01-15 Docker/Alpine Linux font issues documented PDFsharp Forum
2024-01-01 PDFsharp 6.x documentation acknowledges custom font resolver requirement Official Docs
2024-11-12 .NET 6 end of support, PDFsharp 6.2.3 drops .NET 6 compilation target GitHub

Community Reports

"No, PDFsharp does not work with .NET Core yet. Yes, you can get third-party libraries that support the PDFsharp APIs with .NET Core."
— Stack Overflow answer, February 2020

The official documentation itself states the limitation clearly:

"In the Core build, PlatformFontResolver throws an exception by default. The reason is that the .NET version of the Core build runs on all platforms/operating systems .NET runs on and there is no general font resolving strategy on all these platforms."
— PDFsharp Documentation, Font Resolving

Multiple GitHub issues in the PdfSharpCore repository document developers struggling with font resolution after deploying to production Linux environments, only to discover their Windows development setup masked the underlying platform dependency.

Root Cause Analysis

The fundamental issue stems from PDFsharp's original design targeting Windows desktop applications where System.Drawing and GDI+ provide font enumeration and rendering services. When .NET went cross-platform, these dependencies became problematic.

System.Drawing.Common Deprecation: Microsoft explicitly warns against using System.Drawing.Common on non-Windows platforms. The library relies on libgdiplus on Linux, which is not maintained to the same standard as the Windows GDI+ implementation and can introduce memory leaks and rendering inconsistencies.

No Universal Font Resolution: Unlike Windows, which has a centralized font registration system accessible via GDI+, Linux distributions store fonts in various locations with different naming conventions. macOS uses yet another approach with its Core Text framework. PDFsharp's team chose not to implement platform-specific font resolution for the Core build, instead requiring developers to provide their own implementation.

PdfSharpCore Fork Limitations: The community-maintained PdfSharpCore fork attempted to solve this by using SixLabors.Fonts and SixLabors.ImageSharp. However, this introduces its own constraints:

  • Only TTF font format is supported; OTF fonts cannot be used
  • The fork is based on an older PDFsharp version
  • SixLabors libraries have their own licensing considerations
  • Documentation is sparse

API Surface Changes: Migrating from PDFsharp 1.5x to 6.x involves namespace changes and some breaking API modifications. PdfSharpCore uses different namespaces entirely (PdfSharpCore instead of PdfSharp), requiring search-and-replace operations across codebases.

Attempted Workarounds

Workaround 1: Implement Custom IFontResolver

The official recommendation is to implement the IFontResolver interface and set it via GlobalFontSettings.FontResolver at application startup.

using PdfSharp.Fonts;

public class CustomFontResolver : IFontResolver
{
    public byte[] GetFont(string faceName)
    {
        // Load font bytes from embedded resource or file system
        var assembly = typeof(CustomFontResolver).Assembly;
        using var stream = assembly.GetManifestResourceStream($"MyApp.Fonts.{faceName}.ttf");
        if (stream == null)
            throw new InvalidOperationException($"Font {faceName} not found");

        using var ms = new MemoryStream();
        stream.CopyTo(ms);
        return ms.ToArray();
    }

    public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
    {
        // Map requested font families to embedded font face names
        var faceName = familyName.ToLower() switch
        {
            "arial" when isBold && isItalic => "arialbi",
            "arial" when isBold => "arialbd",
            "arial" when isItalic => "ariali",
            "arial" => "arial",
            _ => "arial" // Fallback
        };

        return new FontResolverInfo(faceName);
    }
}

// At application startup
GlobalFontSettings.FontResolver = new CustomFontResolver();
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Every font family and style combination must be explicitly mapped
  • Fonts must be embedded as resources, increasing assembly size
  • The resolver cannot be changed after any XFont has been created
  • No fallback to system fonts for missing entries
  • Requires acquiring and distributing font files (licensing considerations)

Workaround 2: Use PdfSharpCore Instead

Some developers switch to the PdfSharpCore NuGet package, which uses SixLabors libraries for cross-platform font and image handling.

// Change namespace from PdfSharp to PdfSharpCore
using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf;

// Then use similar API
var document = new PdfDocument();
var page = document.AddPage();
var gfx = XGraphics.FromPdfPage(page);
var font = new XFont("Arial", 12);
gfx.DrawString("Hello", font, XBrushes.Black, new XPoint(50, 50));
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Based on older PDFsharp codebase
  • Only TTF fonts are supported
  • Different namespace requires code changes
  • SixLabors.Fonts has its own quirks with font discovery
  • Less active maintenance than official PDFsharp

Workaround 3: Install libgdiplus in Docker

For the GDI build variant, some developers install libgdiplus in their Docker containers.

FROM mcr.microsoft.com/dotnet/aspnet:8.0

RUN apt-get update && apt-get install -y --no-install-recommends \
    libgdiplus \
    libc6-dev \
    && rm -rf /var/lib/apt/lists/*

# Symbolic link sometimes required
RUN ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Only works with PDFsharp-GDI variant, not the Core build
  • Increases container image size significantly
  • libgdiplus has known memory leak issues
  • Microsoft explicitly recommends against System.Drawing.Common for server workloads
  • Does not solve font resolution; fonts must still be installed in the container

Workaround 4: Use Windows-Only Packages

Developers who only target Windows can use the PDFsharp-gdi or PDFsharp-wpf NuGet packages, which continue to use the platform's native font resolution.

<PackageReference Include="PDFsharp-gdi" Version="6.2.3" />
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Locks the application to Windows deployment only
  • Cannot use in Linux containers, cloud functions, or cross-platform scenarios
  • Target framework must include -windows suffix: net8.0-windows

A Different Approach: IronPDF

For developers who need to generate PDFs on .NET 6, .NET 8, or later across multiple platforms without implementing custom font resolvers or managing platform-specific dependencies, IronPDF offers an alternative architecture.

IronPDF embeds a Chromium rendering engine that handles font resolution, CSS styling, and HTML rendering internally. The library does not depend on System.Drawing.Common or require custom font resolver implementations. The same code runs on Windows, Linux, macOS, and Docker without configuration changes.

Why IronPDF Avoids These Issues

IronPDF's architecture differs fundamentally from PDFsharp's drawing-based approach:

  1. Self-contained rendering: The embedded Chromium engine includes font handling, eliminating the need for external font resolution APIs or custom resolvers.

  2. HTML/CSS input: Instead of programmatic drawing calls with explicit font objects, IronPDF accepts HTML and CSS, using web-standard font specifications that Chromium interprets.

  3. Cross-platform binaries: IronPDF ships platform-specific native binaries that are automatically selected at runtime based on the deployment environment.

  4. Docker-ready: No additional packages like libgdiplus are required. The library works with standard .NET runtime containers.

Code Example

using IronPdf;

public class CrossPlatformPdfGenerator
{
    public void GeneratePdf()
    {
        // Works identically on Windows, Linux, macOS, and Docker
        var renderer = new ChromePdfRenderer();

        // Configure rendering options if needed
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;

        // Render HTML content to PDF
        // Fonts are handled by the embedded Chromium engine
        string htmlContent = @"
            <html>
            <head>
                <style>
                    body { font-family: Arial, sans-serif; }
                    h1 { color: #333; }
                    p { font-size: 14px; line-height: 1.6; }
                </style>
            </head>
            <body>
                <h1>Cross-Platform PDF Generation</h1>
                <p>This document renders consistently across all platforms
                   without custom font resolver configuration.</p>
            </body>
            </html>";

        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("output.pdf");
    }

    public void RenderFromUrl()
    {
        var renderer = new ChromePdfRenderer();

        // Render any web page, including pages with web fonts
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
Enter fullscreen mode Exit fullscreen mode

Key points about this approach:

  • No IFontResolver implementation required
  • HTML/CSS syntax is familiar to most developers
  • Web fonts (Google Fonts, custom fonts via @font-face) work automatically
  • Same code deploys to any .NET-supported platform

API Reference

For details on the methods and configuration options used above:

Migration Considerations

Licensing

PDFsharp is open source under the MIT license, making it free for any use. IronPDF is commercial software with a licensing fee. A free trial is available for evaluation before purchase. Organizations should factor licensing costs into the total cost of ownership, balanced against development time spent implementing and maintaining custom font resolvers.

API Differences

PDFsharp uses a programmatic drawing model with explicit coordinate placement:

// PDFsharp approach
gfx.DrawString("Hello", font, brush, x, y);
gfx.DrawRectangle(pen, x, y, width, height);
Enter fullscreen mode Exit fullscreen mode

IronPDF uses an HTML/CSS model:

// IronPDF approach
renderer.RenderHtmlAsPdf("<p style='margin-left: 50px'>Hello</p>");
Enter fullscreen mode Exit fullscreen mode

For applications with heavy use of PDFsharp's drawing APIs, migration requires restructuring PDF generation logic around HTML templates. For applications that already generate HTML reports or use template engines, IronPDF may integrate more naturally.

What You Gain

  • Cross-platform deployment without custom font resolver code
  • No libgdiplus or System.Drawing.Common dependencies
  • Consistent rendering across Windows, Linux, macOS, and Docker
  • Full CSS support including Flexbox, Grid, and web fonts
  • JavaScript execution for dynamic content

What to Consider

  • Commercial license required for production use
  • Larger package size due to embedded Chromium
  • Different mental model (HTML templates vs programmatic drawing)
  • Potential refactoring effort for existing PDFsharp codebases

Conclusion

PDFsharp's .NET Core compatibility has improved with version 6.x, but cross-platform font resolution remains a challenge that requires custom implementation. Developers deploying to Linux, Docker, or macOS must either implement IFontResolver, use the community-maintained PdfSharpCore fork with its limitations, or accept Windows-only deployment.

For projects where cross-platform consistency and minimal configuration are priorities, evaluating IronPDF's Chromium-based approach may reduce development complexity and deployment issues.


Jacob Mellor built IronPDF and has spent 25+ years developing commercial software tools for .NET developers.


References

  1. PDFsharp Font Resolving Documentation{:rel="nofollow"} - Official documentation on font resolver requirements
  2. Is it possible to use PDFsharp with .NET Core? - Stack Overflow{:rel="nofollow"} - Community discussion on .NET Core compatibility
  3. PdfSharpCore GitHub Repository{:rel="nofollow"} - Community fork for .NET Core
  4. PDFsharp GitHub - .NET 6 Compatibility Issue{:rel="nofollow"} - Discussion of .NET 6 incompatibility
  5. PDFsharp Forum - Fonts not resolved on Docker{:rel="nofollow"} - Forum thread on Docker deployment issues
  6. Choose the best PDFsharp build{:rel="nofollow"} - Official guidance on build variants
  7. PdfSharpCore Font Limitations{:rel="nofollow"} - Discussion of TTF-only font support

For the latest IronPDF documentation and tutorials, visit ironpdf.com.

Top comments (0)