PDFsharp & MigraDoc Foundation

PDFsharp - A .NET library for processing PDF & MigraDoc Foundation - Creating documents on the fly
It is currently Tue Mar 19, 2024 9:39 am

All times are UTC




Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Sun Mar 15, 2015 9:28 am 
Offline
PDFsharp Expert
User avatar

Joined: Sat Mar 14, 2015 10:15 am
Posts: 905
Location: CCAA
PDFsharp 1.50 implements a new mechanism for private fonts (fonts that are not installed on the system). You simply implement IFontResolver and assign this to a global property:

Code:
// That's all it takes to register your own fontresolver
GlobalFontSettings.FontResolver = new DemoFontResolver();


The interesting part is IFontResolver and how you implement it.

The IFontResolver interface requires two methods: ResolveTypeface and GetFont.

I derived my class DemoFontResolver from PDFsharp’s class FontResolverBase. For this demo I downloaded two free font: Janitor (regular only) and Ubuntu (using regular, italic, bold, bold italic).

Here is the ResolveTypeface code:

Code:
public override FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
{
    // Ignore case of font names.
    var name = familyName.ToLower();

    // Deal with the fonts we know.
    switch (name)
    {
        case "ubuntu":
            if (isBold)
            {
                if (isItalic)
                    return new FontResolverInfo("Ubuntu#bi");
                return new FontResolverInfo("Ubuntu#b");
            }
            if (isItalic)
                return new FontResolverInfo("Ubuntu#i");
            return new FontResolverInfo("Ubuntu#");

        case "janitor":
            return new FontResolverInfo("Janitor#");
    }

    // 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 base.ResolveTypeface(familyName, isBold, isItalic);
}


The other method, GetFont, must return the TTF file in a byte array.

My implementation of GetFont looks like this:

Code:
/// <summary>
/// Return the font data for the fonts.
/// </summary>
public override byte[] GetFont(string faceName)
{
    switch (faceName)
    {
        case "Janitor#":
            return FontHelper.Janitor;

        case "Ubuntu#":
            return FontHelper.Ubuntu;

        case "Ubuntu#b":
            return FontHelper.UbuntuBold;

        case "Ubuntu#i":
            return FontHelper.UbuntuItalic;

        case "Ubuntu#bi":
            return FontHelper.UbuntuBoldItalic;
    }

    return base.GetFont(faceName);
}


The code that does the work of retrieving the fonts is hidden in a helper class. I added the fonts to the project using the "Embedded Resource" compile type. I then used the free dotPeek tool from JetBrains to find the names of the embedded resources.

Code:
/// <summary>
/// Helper class that reads font data from embedded resources.
/// </summary>
public static class FontHelper
{
    public static byte[] Janitor
    {
        get { return LoadFontData("MyFontResolver.fonts.janitor.Janitor.ttf"); }
    }

    // Tip: I used JetBrains dotPeek to find the names of the resources (just look how dots in folder names are encoded).
    // Make sure the fonts have compile type "Embedded Resource". Names are case-sensitive.
    public static byte[] Ubuntu
    {
        get { return LoadFontData("MyFontResolver.fonts.ubuntufontfamily0._80.Ubuntu-R.ttf"); }
    }

    public static byte[] UbuntuBold
    {
        get { return LoadFontData("MyFontResolver.fonts.ubuntufontfamily0._80.Ubuntu-B.ttf"); }
    }

    public static byte[] UbuntuItalic
    {
        get { return LoadFontData("MyFontResolver.fonts.ubuntufontfamily0._80.Ubuntu-RI.ttf"); }
    }

    public static byte[] UbuntuBoldItalic
    {
        get { return LoadFontData("MyFontResolver.fonts.ubuntufontfamily0._80.Ubuntu-BI.ttf"); }
    }

    /// <summary>
    /// Returns the specified font from an embedded resource.
    /// </summary>
    static byte[] LoadFontData(string name)
    {
        var assembly = Assembly.GetExecutingAssembly();

        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;
        }
    }
}


You can download the complete demo application as a ZIP file (about 2 MiB in size due to the embedded fonts).
http://pdfsharp.th-soft.com/pdfsharp/do ... erDemo.zip

The font resolver applies to PDFsharp and it will also be used when you create PDF files from MigraDoc.

The ZIP file contains two console applications, one demo for PDFsharp and one demo for MigraDoc.
The solution uses PDFsharp 1.50 beta from NuGet. In Visual Studio (I used the free Community Edition Visual Studio 2013) in the <strong>Solution Explorer</strong>, select <strong>Manage NuGet Packages for Solution</strong> from the context menu of the solution.

Sample also discussed in my blog:
http://developer.th-soft.com/developer/?p=11


A generic font resolver that implements IFontResolver and simplifies usage for inexperienced users can be found here:
viewtopic.php?p=9576#p9576

_________________
Best regards
Thomas
(Freelance Software Developer with several years of MigraDoc/PDFsharp experience)


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 01, 2016 2:08 pm 
Offline

Joined: Fri Jul 29, 2016 8:11 pm
Posts: 2
Hi, I have tried your solution to embedding private fonts. This solution works when I open my pdf files in Adobe Acrobat. However, if I try to directly print the pdf files from my application, or save them to .png, my embedded fonts are not used. It uses a default font instead. Do you know how to make this work?


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 01, 2016 3:03 pm 
Offline
PDFsharp Guru
User avatar

Joined: Mon Oct 16, 2006 8:16 am
Posts: 3092
Location: Cologne, Germany
IFontResolver is a PDFsharp feature. Those fonts are not used when printing with GDI+.

Theoretically you can use the GDI+ build of PDFsharp and add the fonts to the XPrivateFontCollection - then they should also be used when printing to a physical printer or a file (PNG or TIFF).

_________________
Regards
Thomas Hoevel
PDFsharp Team


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 01, 2016 3:41 pm 
Offline

Joined: Fri Jul 29, 2016 8:11 pm
Posts: 2
Could you explain how to load the fonts using XPrivateFontCollection? I have been searching for examples of how to do that for quite a while and have found nothing on the GDI+ side, only WPF.

I am using MigraDoc 1.5 beta3b because I need to use images from streams as well.

Thank you!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Privacy Policy, Data Protection Declaration, Impressum
Powered by phpBB® Forum Software © phpBB Group