使用Windows API加载ttf字体

时间:2011-04-22 15:52:06

标签: windows winapi

使用CreateFont可以指定字体名称和一堆其他属性。但是,如果我有一个font.ttf文件,我想要通过Windows加载该特定字体怎么办?如何指定要使用的特定文件?

4 个答案:

答案 0 :(得分:3)

我很确定你做不到。所有字体请求都通过字体映射器,它会选择最接近您提供的规范的字体文件。虽然我不确定它在现实中是否存在,但它至少在理论上可以使用(例如)来自两个完全独立的字体文件的数据来创建一个逻辑字体。

答案 1 :(得分:3)

这无疑是间接的,但是你可以在Windows 7 +上运行时使用带有DWrite的GDI互操作。

#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;
}

其中IFR只是在FAILED HRESULT上返回的失败宏,而ComPtr是辅助智能指针类(替换为您自己的,或ATL CComPtr,WinRT ComPtr,VS2013 _com_ptr_t ......)。

答案 2 :(得分:2)

一种可能性是EnumFonts(),保存结果。然后再次添加AddFontResourceEx()EnumFonts()的私有字体,区别在于您添加的内容。请注意,TTF和位图字体的枚举方式不同,但对于此测试,这应该无关紧要。

如果您使用的是位图字体,则可以轻松解析它们(.FNT和.FON)。 TTF您可能需要构建(或借用另一个评论者建议的FreeType)解析器来从TTF文件中提取“名称”表。

对于您正在控制或提供应用的字体,这似乎很多工作。

我们使用AddFontResourceEx()添加私有字体,但由于我们控制了我们添加的字体,我们只需将传递给CreateFontIndirect()的字体名称硬编码即可。

答案 3 :(得分:1)

如果您不关心安装字体,可以使用AddFontResource进行安装,那么您可以通过查看HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts中的映射来获取物理.TTF与其逻辑/系列名称之间的关系。

我在评论中提到了PrivateFontCollection 因为我以为你想暂时这样做;您可以使用PrivateFontCollection::AddFontFile将TTF加载到PFC中,从集合中获取新的FontFamily对象。考试GetFamilyName。 (我已经完成了类似的.net实现,但不是原始API)