【问题标题】:Retrieve Physical Font Data from Logical Font Handle从逻辑字体句柄中检索物理字体数据
【发布时间】:2021-03-10 16:14:15
【问题描述】:

我基于 freetype 库中的某些功能编写了一个字体解析器和渲染器,但它目前仅适用于我指定的字体文件。我希望能够从 Windows 字体映射器中检索字体,然后解析和渲染它们,但我不知道如何从逻辑字体中获取实际的字体数据。

我认为完成此操作的简单方法是从逻辑字体中获取字体文件名,但基于其他堆栈溢出帖子,没有任何好的解决方案,因为没有 1 1 物理字体到你指定的逻辑字体的映射。

这段代码显示了我当前如何检索逻辑字体的句柄:

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

基于这个针对 Java 的堆栈溢出帖子,我认为我想做的事情可能是不可能的。似乎唯一的解决方案可能是查看所有系统字体文件并尝试找出它们是什么。

How to get ttf font data from system fonts in java

这让我很吃惊,因为对于一个程序来说,想要自己渲染字体而不依赖于 Windows 渲染器似乎是相对常见的。有谁知道获取字体数据的方法,或者其他人如何解决这个问题?

【问题讨论】:

  • “程序想要自己渲染字体是相对常见的” - 考虑到字体渲染的复杂程度,应用程序不想这样做似乎相当普遍完全没有。
  • @IInspectable 是的,common 不是正确的词。我想我的意思是,对于已经拥有复杂渲染管道的应用程序来说,想要自己渲染字体是很常见的。想到游戏和网络浏览器。不过,游戏可能不需要这个,因为它们很可能附带为游戏设计的自己的字体,并且不需要使用系统字体。
  • 你见过GetFontData吗?您似乎正在寻找系统字体的 ttf 文件。不知道我的猜测是否正确,this thread你可以参考。
  • 是的,我实际上尝试使用 GetFontData,但无法使其工作。不,我实际上是在确保我使用的字体是 .ttf 而不是 .fon。不过那个帖子很有趣,因为看起来他们正在以我想要的方式使用 GetFontData,所以我会检查一下,看看我是否可以让它工作。
  • 我刚刚用更多代码更新了我的问题。我对 GetFontData 有点困惑。我认为这是我需要的,因为它获得了正确数量的字节,但数据与 .ttf 文件不同。有谁知道这个功能是如何工作的?我不明白为什么它得到的字节数与文件完全相同,但数据却不一样。

标签: winapi


【解决方案1】:

我不明白为什么它得到的字节数与 文件,但数据不一样。

official sample,我找到了GetFontData的正确使用方法。

这是修改后的代码,返回的数据和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

【讨论】:

  • 哇,谢谢。老实说,我真的很惊讶,因为唯一真正的区别是它们使用 windows 函数而不是 malloc 分配内存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-03
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
相关资源
最近更新 更多