locked
How do I load a custom font from an embedded file into DirectWrite in a Metro app?

    Question

  • I have been fighting a losing battle against loading fonts from an embedded file for use with DirectWrite.  I am writing a simple puzzle game that has a C#/XAML interface but also uses SurfaceImageSource to add some DirectX content.  I have written a WinRT component that handles all of the DirectX code, and it works quite nicely.  Some of my DirectX content is text drawn using the DirectWrite API.  I can draw all the text I like so long as I'm loading an installed font from the system using IDWriteFactory::GetSystemFontCollection(), etc.  But, I cannot seem to find a way to load a custom font from an embedded file.

    From what I can tell Metro apps are not allowed to load files from the filesystem in the same way as a traditional app.  So, the IDWriteFactory::CreateFontFileReference() method that takes a normal file path is worthless to me, right?  I need to load my file from an ms-appx URL.

    So, I wrote a custom font loader in my WinRT component that implements the IDWriteFontCollectionLoader interface (which is a ton of work if you've never done it before btw).  Now, I can load my IDWriteFontFile and I can get a IDWriteFontFace, but if I try to call any of the truly useful methods on the font face it returns E_UNEXPECTED.  I can get the number of glyphs and the glyph indices, but if I try to call something like GetGlyphRunOutline() or GetDesignGlyphMetrics(), it fails with E_UNEXPECTED.  Using the same drawing code that generates an ID2D1PathGeometry using GetGlyphRunOutline works great as long as I install the font file and get the IDWriteFontFace through the series of calls starting with IDWriteFactory::GetSystemFontCollection().  This is just a normal true type font.

    So, how do I load a custom font from an embedded file into DirectWrite in a Metro app?  I'm probably just missing something easy, because I am certain that other people will want to be able to load custom fonts in this way.

    I have a sample project (or could prepare one easily) for anyone who can help me identify my problem.

    I have loaded the two IDWriteFontFace objects side by side, and I tried to figure out what is different between the one that works and the one that breaks.  What I need to see in order to find out why it is failing is opaque to me hidden behind inside the IDWriteFontFace interface.  HELP PLEASE!

    Sunday, July 22, 2012 6:39 AM

Answers

  • Normal file path is NOT worthless . You can get the DOS-path from IStorageItem.Path of Package.InstalledLocation

    C++ DX11

    Wednesday, July 25, 2012 2:52 AM
  • Hi Daniel,

    So, the IDWriteFactory::CreateFontFileReference() method that takes a normal file path is worthless to me, right? I need to load my file from an ms-appx URL

    As RaptorCK16 pointed out, this is incorrect. Your app has access to its install directory so you can call CreateFontFileReference with a path retrieved via Package.InstalledLocation. If you look at the documentation for CreateFontFileReference you can see that it "Applies to: desktop apps | Metro style apps" so you can call it from your app.

    That would be by far the easiest way to get this to work. Please give it a try and let us know how it works.

    You shouldn't need to implement IDWriteFontCollectionLoader, &c. yourself.

    --Rob

    Thursday, August 09, 2012 9:47 PM
    Owner

All replies

  • Normal file path is NOT worthless . You can get the DOS-path from IStorageItem.Path of Package.InstalledLocation

    C++ DX11

    Wednesday, July 25, 2012 2:52 AM
  • Hi Daniel,

    You can contact me here and we can arrange it so you can get me a copy of your problem repro:  http://blogs.msdn.com/jpsanders/contact.aspx

    -Jeff


    Jeff Sanders (MSFT)

    Wednesday, July 25, 2012 3:24 PM
    Moderator
  • Hey Jeff,

    Any luck with that test project that I sent?  I'm still unable to make any progress with this on my end.

    Thanks,

    Dan

    Wednesday, August 01, 2012 3:54 PM
  • Hi Daniel,

    So, the IDWriteFactory::CreateFontFileReference() method that takes a normal file path is worthless to me, right? I need to load my file from an ms-appx URL

    As RaptorCK16 pointed out, this is incorrect. Your app has access to its install directory so you can call CreateFontFileReference with a path retrieved via Package.InstalledLocation. If you look at the documentation for CreateFontFileReference you can see that it "Applies to: desktop apps | Metro style apps" so you can call it from your app.

    That would be by far the easiest way to get this to work. Please give it a try and let us know how it works.

    You shouldn't need to implement IDWriteFontCollectionLoader, &c. yourself.

    --Rob

    Thursday, August 09, 2012 9:47 PM
    Owner
  • Hey Daniel

    In my app i'm using fonts that are not installed and they could be not only in the installed folder

    I'm also using driectwrite and had problem loading those fonts

    What i found out is that you need to create a custom font collection load the font files to it and then use it.

    there is a sample: http://code.msdn.microsoft.com/Magazine-Sample-2a657289 that show you how to do it.

    I used it and i got it to work (also from c#/xaml)

    Assaf Dar

    Sunday, October 07, 2012 7:26 AM