Dailycode.info

Short solution for short problems

Azure web apps and PDF sharp to generate pdf. (1.3 -> 1.5)

I was using PDF sharp 1.3 to generate PDF via my web api. I had some challenges but generally speaking it went fine. After some good tests I decided to publish it to Azure. Then things got strange. I got a 500 internal server error. After some investigation, this was the error:

font data could not retrieved

Well, this was a pain. Locally this worked fine, but not in azure. I found a nice explanation here, but no solution.

This is what is says:

Azure App Service (aka Azure Websites) enforces a number of more restrictive security constraints than a cloud service or IaaS (VMs). One of the things that is blocked is access to much of the GDI API surface area, which includes some font manipulation. As other folks have noted, if the same code works on a plain IaaS VM, a cloud service, or even a local desktop/laptop, then the problem you are running into is a hard block on the underlying GDI calls.

So the problem is that in web apps you cannot acces the fonts. the solution is to add font as a resource to your application and use the IFormatter interface of PDF sharp 1.5. 

Oh no, this means migrating the code and rewriting. Forntunately this was NOT the case. I looked for the nuget package (it's a beta vesion, so you need to include pre releases) 


I only had to remove the old reference to the charting dll and that was it. 

Now I could start to make a class that implements the IFormatter interface:

using PdfSharp.Fonts;
using System;
using System.IO;
using System.Reflection;
 
namespace spib.print
{
    public class SPIBFontresolver : IFontResolver

In my case I'm using the Verdana font. So where to find the fonts. Thats easy. Go to C:\Windows\Fonts\ and look for the fonts you want to use. copy them and paste them in a folder in your project.


I placed the fonts in a sub folder called font directly in my project. then I added them as embedded resource:


Here you see the project structure with the files:


Next we can complete the implementation of the interface. 

Implement the interface and complete. Here how I completed it in my case for the Verdana font:

public class SPIBFontresolver : IFontResolver
{
    public byte[] GetFont(string faceName)
    {
        switch (faceName)
        {
            case "Verdana#":
                return LoadFontData("spib.print.font.verdana.ttf"); ;
 
            case "Verdana#b":
                return LoadFontData("spib.print.font.verdanab.ttf"); ;
 
            case "Verdana#i":
                return LoadFontData("spib.print.font.verdanai.ttf");
 
            case "Verdana#bi":
                return LoadFontData("spib.print.font.verdanaz.ttf");
        }
 
        return null;
    }
 
    /// <summary>
    /// Returns the specified font from an embedded resource.
    /// </summary>
    private byte[] LoadFontData(string name)
    {
        var assembly = Assembly.GetExecutingAssembly();
 
        // Test code to find the names of embedded fonts - put a watch on "ourResources"
        //var ourResources = assembly.GetManifestResourceNames();
 
        using (Stream stream = assembly.GetManifestResourceStream(name))
        {
            if (stream == null)
                throw new ArgumentException("No resource with name " + name);
 
            int count = (int)stream.Length;
            byte[] data = new byte[count];
            stream.Read(data, 0, count);
            return data;
        }
    }
 
    public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
    {
        // Ignore case of font names.
        var name = familyName.ToLower().TrimEnd('#');
 
        // Deal with the fonts we know.
        switch (name)
        {
            case "verdana":
                if (isBold)
                {
                    if (isItalic)
                        return new FontResolverInfo("Verdana#bi");
                    return new FontResolverInfo("Verdana#b");
                }
                if (isItalic)
                    return new FontResolverInfo("Verdana#i");
                return new FontResolverInfo("Verdana#");
        }
 
        // We pass all other font requests to the default handler.
        // When running on a web server without sufficient permission, you can return a default font at this stage.
        return PlatformFontResolver.ResolveTypeface(familyName, isBold, isItalic);
    }
}

Last, you will need to add the formatter to your applcation where you are using it.

public PrintOffer()
{
    GlobalFontSettings.FontResolver = new SPIBFontresolver();

And now it works. So with some minimum easy code, you can add private fonts to Azure web apps. I tested it and got a desired result!

I got a good help here: https://stackoverflow.com/questions/27606877/pdfsharp-private-fonts-for-azure-1-50