PDFsharp & MigraDoc Foundation

PDFsharp - A .NET library for processing PDF & MigraDoc Foundation - Creating documents on the fly
It is currently Sun Jun 30, 2024 4:26 pm

All times are UTC


Forum rules


Please read this before posting on this forum: Forum Rules



Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Thu Jan 05, 2012 3:52 am 
Offline

Joined: Thu Jan 05, 2012 3:14 am
Posts: 8
HI, I really tried hard to figure this out on my own, and I also searched the forum, I found two sort of relevant questions:
viewtopic.php?f=2&t=1400&start=0
viewtopic.php?f=2&t=1527

But I'm still not getting it. Is there any way someone could provide a working sample of private fonts with asp.net? Don't get me wrong, the wiki sample is great and I have that working as a console app, but I just can't seem to get it to work as asp.net code (everything else I've tried with PDFSharp is working GREAT and I love this library!).

The part I can't get working is just the Uri and the fontcollection.add:

For reference only, the console app uses syntax like this:
Uri uri = new Uri("pack://application:,,,/");
globalFontCollection.Add(uri, "./Fonts/#OfficinaSanITCBoo");

Which works fine. But in asp the Uri is totally different compared to the console app which may be what is throwing me off. To use some code found in the question linked above:

Uri fontUri = new Uri(baseUrl + "/public/fonts/FreightDispBlackItalicSC.ttf");
privateFontCollection.Add(fontUri, "./#FreightDispBlackItalicSC");

It seems no matter what I try, I always get the error "Font with the specified family name does not exist" on the .Add line. So obviously the PDFSharp functions are not finding the font but for the life of me I can't figure out how to resolve this issue.

I have verified that the full string in the new Uri is correct. I am setting a reference to the WPF PDFSharp dll file. Now I know in the console version you have to change the properties on your font files and specify "resource" but in asp.net I don't see any sort of equivalent to that - perhaps I am missing something?

I think it would be extremely valuable to add a complete asp.net sample of using private fonts to the wiki.

Thanks so much for any help!!


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 05, 2012 3:30 pm 
Offline

Joined: Mon Mar 21, 2011 7:17 pm
Posts: 3
Hi TraderGordo,

I got your message in my email this morning and decided to try to help since I remember this being a big trial and error pain!! I do not remember exactly how I got it working, but I will try my best.

Here are some code snippits, but the important thing to remember is the name of the font.. The file name and the font name can be different. Mostly I remember playing around a lot with the names and all that. You can find the name of a font by opening the ttf file or via the properties->details of the file.. I believe.

This is a code example where I'm setting the fonts in the document renderer. You can ignore that UriSupport.SiteUrl (framework specific) stuff and just insert whatever your own base url is for your website.

Code:
// Load in a private font to use.
XPrivateFontCollection privateFontCollection = new XPrivateFontCollection();
Uri fontUri = new Uri(UriSupport.SiteUrl.ToString() + "/public/fonts/FreightDispBlackItalicSC.ttf");
privateFontCollection.Add(fontUri, "./#FreightDispBlackItalicSC");

fontUri = new Uri(UriSupport.SiteUrl.ToString() + "/public/fonts/Bodoni Svntytwo ITC Std.ttf");
privateFontCollection.Add(fontUri, "./#Bodoni Svntytwo ITC Std");

// Render the document
DocumentRenderer documentRenderer = new DocumentRenderer(doc);
documentRenderer.PrivateFonts = privateFontCollection;
documentRenderer.PrepareDocument();


When I'm using the font to write some text.. (simple example)

Code:
Paragraph paragraph = textFrame.AddParagraph();

paragraph.Format.Alignment = ParagraphAlignment.Left;
paragraph.Format.Font.Name = "Bodoni Svntytwo ITC Std";
paragraph.Format.Font.Size = 36;
paragraph.Format.Font.Color = new Color(0.0, 0.0, 0.0, 0.0);

paragraph.AddText("Hello World");


I hope this helps!!


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 05, 2012 4:06 pm 
Offline

Joined: Thu Jan 05, 2012 3:14 am
Posts: 8
I greatly appreciate your help - I think I'm missing something as far as app setup or some prerequisite. Are you calling the code you posted above directly from an asp page (for example default.aspx) or is it in some .dll or some other indirect method?

Also do you call "new System.Windows.Application();"? I was a little confused about this, I got the same missing font error with or without that line, but when I keep that line in, I can only run it once in the debugger otherwise I get error "Cannot create more than one System.Windows.Application instance in the same AppDomain".

I actually downloaded the exact font you were using in your sample code just for sanity purposes, I also opened the font file and verifed the font family name which matches exactly what you have in your code.

I'm doing my testing in debug mode directly from visual studio. Do I need to actually deploy it and configure as web app in IIS before it would work? (I haven't tried that yet)

Maybe there is something wrong with baseURL? You are apparently using some 3rd party class for that? Can I just use:
string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority + Request.ApplicationPath.TrimEnd('/') + '/';

?

EDIT: I think I'm narrowing down the problem, if I use a Uri like:
Uri fontUri = new Uri("C:\\Users\\Gordo\\Documents\\WebSites\\WebSite1\\public\\fonts\\FreightDispBlackItalicSC.ttf");

IT WORKS! So there is obviously something wrong with my Uri string. Any help with that would be greatly appreciated, I think I'm close to solving this...

Thanks again!


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 05, 2012 5:35 pm 
Offline

Joined: Mon Mar 21, 2011 7:17 pm
Posts: 3
Personally I called my code from a .cs file (dll, class library) but I imagine it can go anywhere you can put C# code. Nowhere in my code did I call new System.Windows.Application() to get this thing to work.

As for the 'base url' you could make a web.config value that holds that information and set it for each deployment location.

I'm glad you got it working. Good luck!


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 05, 2012 6:27 pm 
Offline
PDFsharp Expert
User avatar

Joined: Wed Dec 09, 2009 8:59 am
Posts: 343
Hi!
TraderGordo wrote:
Uri uri = new Uri("pack://application:,,,/");
This searches the font in the application. With ASP.NET, the application is the W3 work process or whatever, but not your assembly.

If you want to load the font from your assembly, add the name of the assembly (without .DLL) to the Uri and add "/component" after the assembly name.
See also:
http://stackoverflow.com/questions/3500 ... ce-in-code
The "pack:" protocol is not simple to figure out, but it can be done.

A different approach is loading the font files directly from the hard disk. You may prefer to stick to that approach.

_________________
Öhmesh Volta ("() => true")
PDFsharp Team Holiday Substitute


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 05, 2012 6:51 pm 
Offline

Joined: Thu Jan 05, 2012 3:14 am
Posts: 8
Thanks guys for your help. I think the confusion was the subtle differences between loading from an assembly vs directly from asp. I have this all worked out now. In my app I was not doing this from a .dll, so that is the major difference between my code (pure asp.net) and other things that have been posted.

For the benefit of others looking at this in the future. If you are doing private fonts from asp.net directly, you need to form your uri like this:

Uri fontUri = new Uri(MappedApplicationPath + "Fonts\\");

In this example you should have a subfolder for your website called "Fonts" that contain all of your font files. Note that I never reference a specific file in my code, you can let PDFsharp do this work for you.

Then add all of your font families (note that you might have 4 files for one family, this doesn't matter, you only call it once per font family):

privateFontCollection.Add(fontUri, "./#FreightDispBlackItalicSC");
privateFontCollection.Add(fontUri, "./#OfficinaSanITCBoo");

Everything else is the same as the demo console project in the pdfsharp wiki.

The key thing about the Uri is that it has to be an absolute path, you cannot use URL format or relative paths. Here is the code for MappedApplicationPath:
public static string MappedApplicationPath
{
get
{
string APP_PATH = System.Web.HttpContext.Current.Request.ApplicationPath.ToLower();
if (APP_PATH == "/") //a site
APP_PATH = "/";
else if (!APP_PATH.EndsWith(@"/")) //a virtual
APP_PATH += @"/";

string it = System.Web.HttpContext.Current.Server.MapPath(APP_PATH);
if (!it.EndsWith(@"\"))
it += @"\";
return it;
}
}

As was mentioned before, you do NOT need to call System.Windows.Application(); Nor do you need to do anything with packing or resource file properties, etc. like you see in the console app demo from the wiki.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 05, 2012 10:06 pm 
Offline

Joined: Thu Jan 05, 2012 3:14 am
Posts: 8
Now I got it working on my workstation, but when deployed to the server I get error:
Cannot get a matching glyph typeface for font 'OfficinaSanITCBoo'.

What does it mean if it works on your workstation but not on the server?
I don't think I should have to, but I went ahead and installed the font files for 'OfficinaSanITCBoo' on the server, but that did not help, same error message. Don't know if it matters but my development box is Win Server 2008, and the deployment server is win server 2003.

Any ideas?


Top
 Profile  
Reply with quote  
PostPosted: Fri Jan 06, 2012 8:42 pm 
Offline

Joined: Thu Jan 05, 2012 3:14 am
Posts: 8
OK - just wanted to post my final solution - everything is working beautifully now - I've deployed it to 3 different servers for testing purposes, and it is working on all of them (win 2003, win 2008, win 2008R2). I did NOT need to install fonts on any servers. What I found, for asp.net, and PDFSharp (I'm not using migradoc), you need to add your private fonts to the global collection apparently only one time. I could NOT get it to work consistently any other way. Since it will error out if you try to add it again, I just created a function, catch any errors, and ignore. I'm SURE there is a better/proper way to do it, but this was the only thing I could come up with that worked. This will eliminate those errors like "Cannot get a matching glyph typeface for font".

Code:
        //To use a private font, first get the font file (.ttf or .otf) and add it to your project (if it is an asp project, you can add the font files to a subfolder called "Fonts".  If it is a .dll or console/forms project, add the file as a resource (click the file and change "build action" to "Resource")).
        //NOTE: You do NOT need to install (windows) the font on the server or your workstation in order to use it.
        //You can get many font files from: http://www.azfonts.net/
        //To get the font family name, double click on the font file in windows and look for the line near the top of the sample that says "Font Name:" use that name below after the '#'.
        //Note: You might have several font files for ONE font "family" - this is normal, you only need to add the family once (for example you might have separate files for bold and italic) but all files should be added to your project (and marked for build action: resource unless it is an asp project).
        //Note: If for some reason bold or italic aren't working and you are sure you did everything above, you may need to find a different font file, often a given font family exists in different formats (tt vs. otf) and is built differently from alternate sources so you may have better luck with a different download.


        // First of all initialize the global XPrivateFontCollection.
        XPrivateFontCollection privateFontCollection = XPrivateFontCollection.Global;
        Uri fontUri = new Uri(MappedApplicationPath + "Fonts\\");
        LoadPrivateFont(privateFontCollection, fontUri, "./#FreightDispBlackItalicSC"); //Example of adding a private font family - the font file should be located in the Uri path above, it will get embedded in the PDF.

        LoadPrivateFont(privateFontCollection, fontUri, "./#OfficinaSanITCBoo");        //Example of adding a private font family - the font file should be located in the Uri path above, it will get embedded in the PDF.

protected void LoadPrivateFont(XPrivateFontCollection privateFontCollection, Uri fontUri, string sFontFamilyname)
    {
        //Every font must be added to the global font collection.  There is probably some better way to do this but this was the only method that seemed to work when deploying to any server.
        //If the font has previously been added it will just error out and continue, this does not matter.
        try
        {
            privateFontCollection.Add(fontUri, sFontFamilyname);
        }
        catch
        {
        }
    }
    public static string MappedApplicationPath
    {
        get
        {
            //Returns the absolute path to files from your website - this is needed for font embedding
            string APP_PATH = System.Web.HttpContext.Current.Request.ApplicationPath.ToLower();
            if (APP_PATH == "/")      //a site
                APP_PATH = "/";
            else if (!APP_PATH.EndsWith(@"/")) //a virtual
                APP_PATH += @"/";

            string it = System.Web.HttpContext.Current.Server.MapPath(APP_PATH);
            if (!it.EndsWith(@"\"))
                it += @"\";
            return it;
        }
    }


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 08, 2012 3:44 pm 
Offline

Joined: Thu Jan 05, 2012 3:14 am
Posts: 8
jerrzey wrote:
Any new idea


Not sure what you mean, the issue was resolved and the code posted in this thread. If you meant, any better way of doing this - I haven't been looking and no one else posted anything, so I'm just using what worked and I've moved on.


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

All times are UTC


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 61 guests


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