3

With CreateFont one can specify font name and a bunch of other properties. However, what if I have a font.ttf file, and I want that particular font to be loaded by windows? How do I specify that specific file to be used?

Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • Wouldn't CreateFontIndirectEx be an option then? There you can pick and choose. – 0xC0000022L Apr 22 '11 at 16:00
  • @STATUS_ACCESS_DENIED: i don't see anywhere to specify a filename, just a 'face name', which i suspect is looked up in the system font table somewhere. maybe i could `AddFontResourceEx`, then use it, then `RemoveFontResourceEx`, but then how do i figure out under what name windows put it so i can load it with `CreateFont`? – Claudiu Apr 22 '11 at 16:04
  • Alternative; GDI+ PrivateFontCollection you can then possibly enumerate the collection & fetch the family name – Alex K. Apr 22 '11 at 16:15
  • @Claudiu: so you know the file name but not the font name? Or rather you have to expect that the font name and properties will not be sufficient to distinguish your (installed) font from others? I haven't found any solution to loading a font (except the old style fonts from PE resource) without installing when I looked for this a few years again. I'd put in quite some time back then. – 0xC0000022L Apr 22 '11 at 16:21
  • @STATUS_ACCESS_DENIED: it's more like i have a user-supplied font file i want to use, that isn't necessarily installed. my program can install it - that's fine. but how do i get that particular installed font? the filename can be `foo.ttf` - it doesn't say anything about its logical nam – Claudiu Apr 22 '11 at 16:25
  • @Claudiu: I see. Well, that's a tricky one. +1 – 0xC0000022L Apr 22 '11 at 16:29
  • @Alex K.: can you go a bit more into that? – Claudiu Apr 22 '11 at 17:20

4 Answers4

3

It's admittedly rather indirect, but you could utilize GDI interop with DWrite when running on Windows 7+.

#include <Windows.h>
#include <WindowsX.h>
#include <DWrite.h>

...

// Make the font file visible to GDI.
AddFontResourceEx(fontFileName, FR_PRIVATE, 0);
if (SUCCEEDED(GetLogFontFromFileName(fontFileName, &logFont)))
{
    logFont.lfHeight = -long(desiredPpem);
    HFONT hf = CreateFontIndirect(&logFont);
    HFONT oldFont = SelectFont(hdc, hf);
    ...
    // Do stuff...
    ...
    SelectFont(hdc, oldFont);
}
RemoveFontResource(fontFileName);

....

HRESULT GetLogFontFromFileName(_In_z_ wchar const* fontFileName, _Out_ LOGFONT* logFont)
{
    // DWrite objects
    ComPtr<IDWriteFactory> dwriteFactory;
    ComPtr<IDWriteFontFace> fontFace;
    ComPtr<IDWriteFontFile> fontFile;
    ComPtr<IDWriteGdiInterop> gdiInterop;

    // Set up our DWrite factory and interop interface.
    IFR(DWriteCreateFactory(
        DWRITE_FACTORY_TYPE_SHARED,
        __uuidof(IDWriteFactory),
        reinterpret_cast<IUnknown**>(&dwriteFactory)
        );
    IFR(g_dwriteFactory->GetGdiInterop(&gdiInterop));

    // Open the file and determine the font type.
    IFR(g_dwriteFactory->CreateFontFileReference(fontFileName, nullptr, &fontFile));
    BOOL isSupportedFontType = false;
    DWRITE_FONT_FILE_TYPE fontFileType;
    DWRITE_FONT_FACE_TYPE fontFaceType;
    UINT32 numberOfFaces = 0;
    IFR(fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces));

    if (!isSupportedFontType)
        return DWRITE_E_FILEFORMAT;

    // Set up a font face from the array of font files (just one)
    ComPtr<IDWriteFontFile> fontFileArray[] = {fontFile};
    IFR(g_dwriteFactory->CreateFontFace(
        fontFaceType,
        ARRAYSIZE(fontFileArray), // file count
        &fontFileArray[0], // or GetAddressOf if WRL ComPtr
        0, // faceIndex
        DWRITE_FONT_SIMULATIONS_NONE,
        &fontFace
        );

    // Get the necessary logical font information.
    IFR(gdiInterop->ConvertFontFaceToLOGFONT(fontFace, OUT logFont));

    return S_OK;
}

Where IFR is just a failure macro that returns on a FAILED HRESULT, and ComPtr is a helper smart pointer class (substitute with your own, or ATL CComPtr, WinRT ComPtr, VS2013 _com_ptr_t...).

Dwayne Robinson
  • 2,034
  • 1
  • 24
  • 39
3

I'm pretty sure you can't. All requests for fonts go through the font mapper, and it picks out the font file that comes the closest to meeting the specifications you've given. Though I'm not sure it even does in reality, it could at least theoretically use (for example) data from two entirely separate font files to create one logical font.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • would there be a way to parse the `ttf` file to get all of its properties such that i could install it, then pass those properties to windows so as to get that particular font? – Claudiu Apr 22 '11 at 16:32
  • @Claudiu: yes, but it's definitely not trivial to do it on your own. I'd probably use something like Freetype (Freetype 2, really) to access the data from the font files. – Jerry Coffin Apr 22 '11 at 17:01
  • yep i ended up just enumerating the existing windows fonts to solve my problem. – Claudiu Aug 25 '11 at 14:36
  • `AddFontResourceEx("data/fonts/quantico.ttf", FR_PRIVATE)` seems to make embedded Webkit to recognize the font-family:Quantico without the font being actually available on my system in my game engine. – Петър Петров Oct 10 '14 at 09:13
2

One possibility is to EnumFonts(), save the results. Then add your private font with AddFontResourceEx(), and EnumFonts() again, the difference is what you added. Note that TTF and bitmap fonts enumerate differently, but for this test, that shouldn't matter.

If you were using bitmap fonts, they could be easily parsed (.FNT and .FON). TTF you'd likely have to build (or borrow, as another commenter suggested FreeType) a parser to pull the "name" table out of the TTF file.

That seems like a lot of work for a font you're controlling or supplying with your app.

We use AddFontResourceEx() to add a private font, but since we control the font we're adding, we just hardcode the fontname passed to CreateFontIndirect() to match.

CoreyStup
  • 1,488
  • 13
  • 14
1

If you dont care about installing the font you can do so with AddFontResource then you can fetch the relationship between the physical .TTF and it logical/family name by looking at the mappings in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts.

I mentioned PrivateFontCollection in my comment because I thought you wanted to do this temporarily; you can load a TTF into a PFC with PrivateFontCollection::AddFontFile, fetch back the new FontFamily object from the collection & examime GetFamilyName. (I've done similar with the .net implementation of this but not the raw API)

Alex K.
  • 171,639
  • 30
  • 264
  • 288
  • AddFontResource does not actually persist the addition to the registry for reboots, just temporarily to GDI's system table. When you install a font via the shell (by right-clicking on the file), it calls AddFontResource, updates the registry key too, and broadcasts WM_FONTCHANGE. http://msdn.microsoft.com/en-us/library/windows/desktop/dd144833(v=vs.85).aspx – Dwayne Robinson Aug 28 '14 at 21:06
  • That is why a ttf file not marked as FR_PRIVATE is taken by PID 4 :P – Петър Петров Oct 10 '14 at 09:26