0

I wrote a font parser and renderer based on some functionality in the freetype library, but it currently only works for font files that I specify. I'd like to be able to retrieve fonts from the Windows Font Mapper and then parse and render them, but I can't figure out how to get the actual font data from a logical font.

I thought that the easy way to accomplish this would be to get the font file name from the logical font, but based on other stack overflow posts, there isn't any good solution to this because there isn't a 1 to 1 mapping of physical fonts to the logical font you specify.

This code shows how I'm currently retrieving a handle to a logical font:

HFONT windowsFont = CreateFontA(72, 0, 0, 0, 0,
                        0, 0, 0, ANSI_CHARSET,
                        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                        DEFAULT_QUALITY, DEFAULT_PITCH, "Arial");

HDC deviceContext = GetDC(windowHandle);
SelectObject(deviceContext, windowsFont);

DWORD fontSize = GetFontData(deviceContext, 0, 0, NULL, 0);
void *fontData = malloc(fontSize);
fontSize = GetFontData(deviceContext, 0, 0, fontData, 0);

char *fontFileData;
size_t fontFileSize;

// This is a function that I wrote that does what you'd expect. It opens
// a file, reads all the bytes to a buffer and closes the file
readFileToBuff(&fontFileData, &fontFileSize, "c:/windows/fonts/arial.ttf");

assert(fontFileSize == fontSize); // This passes
assert(((char)fontFileData) == ((char)fontData)); // This fails

Based on this stack overflow post which is for Java, I'm thinking that what I want to do may not be possible. It seems that the only solution may be to look at all the system font files and try to figure out what they are.

How to get ttf font data from system fonts in java

This surprises me though, because it seems that it would be relatively common for a program to want to render fonts themselves, without relying on the Windows renderer. Does anyone know of a way to get the font data, or how other people have solved this problem?

  • *"it would be relatively common for a program to want to render fonts themselves"* - Given how complex font rendering is it would seem rather common for applications to not want to do that at all. – IInspectable Mar 09 '21 at 03:18
  • @IInspectable Ya, common wasn't the right word. I guess I mean that it's common for applications that already have complex rendering pipelines to want to render fonts themselves. Games and web browsers come to mind. Games probably wouldn't require this though, because they most likely ship with their own fonts that are designed for the game and don't need to use the system fonts. – labmonkey398 Mar 09 '21 at 03:34
  • Have you seen [GetFontData](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getfontdata)? You seem to be looking for the ttf files of the system fonts. Not sure if my guess is correct, [this thread](https://social.msdn.microsoft.com/Forums/vstudio/en-US/ccdf449f-f82b-4277-a9ea-309f573b1cc6/how-to-get-physical-font-data?forum=vclanguage) you can refer. – Strive Sun Mar 09 '21 at 09:55
  • Yes, I actually tried to use GetFontData, but couldn't get it to work. And no, I'm actually making sure that the font's that I'm using are .ttf and not .fon. That thread is interesting though, because it looks like they're using GetFontData in the way that I would like to, so I'll check that out and see if I can get it to work. – labmonkey398 Mar 09 '21 at 20:50
  • I just updated my question with some more code. I'm a little confused by GetFontData. I think it's what I need because it gets the right amount of bytes, but the data isn't the same as the .ttf file. Does anyone know how this function works? I don't understand why it's getting the exact same amount of bytes as the file, but the data isn't the same. – labmonkey398 Mar 09 '21 at 21:51

1 Answers1

0

I don't understand why it's getting the exact same amount of bytes as the file, but the data isn't the same.

From the official sample, I found the correct way to use GetFontData.

This is the modified code, and the returned data is the same as fontFileData.

HRESULT hr = S_OK;
LPVOID ptr = NULL;
HGLOBAL hGlobal = NULL;
...

HFONT windowsFont = CreateFontA(72, 0, 0, 0, 0,
                0, 0, 0, ANSI_CHARSET,
                OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                DEFAULT_QUALITY, DEFAULT_PITCH, "Arial");

HDC deviceContext = GetDC(hWnd);
SelectObject(deviceContext, windowsFont);

DWORD fontSize = GetFontData(deviceContext, 0, 0, NULL, 0);
hGlobal = GlobalAlloc(GMEM_MOVEABLE, fontSize);
ptr = GlobalLock(hGlobal);
if (!ptr)
{
    hr = HRESULT_FROM_WIN32(GetLastError());
    fwprintf(stderr, L"ERROR: Could not lock global memory object: %08X\n", hr);
}
else
{
    if (GetFontData(deviceContext, 0, 0, ptr, fontSize) == GDI_ERROR)
    {
        fwprintf(stderr, L"ERROR: Could not get font data\n");
        hr = E_UNEXPECTED;
    }

    GlobalUnlock(hGlobal);
}

char *fontFileData;
size_t fontFileSize;

// This is a function that I wrote that does what you'd expect. It opens
// a file, reads all the bytes to a buffer and closes the file
readFileToBuff(&fontFileData, &fontFileSize, "c:/windows/fonts/arial.ttf");

assert(fontFileSize == fontSize); // This passes
assert(((char)fontFileData) == ((char)fontData)); // This fails
Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • 1
    Wow, thanks for that. I'm honestly really surprised that worked because the only real difference is that they allocate memory with the windows function and not malloc. – labmonkey398 Mar 11 '21 at 04:03