整天都让我感到疯狂。
我需要根据字体名称(例如Arial)以及其是否为粗体,斜体或两者皆有来获取字体文件名(例如Arial.ttf)。使用这些信息,我需要找到字体文件,以便用于渲染。
一些其他例子:
- Calibri,Bold会解析为calibrib.ttf。
- Calibri,Italic会解析为calibrii.ttf。
您有任何关于如何在C++(Win32)中实现此功能的想法吗?
整天都让我感到疯狂。
我需要根据字体名称(例如Arial)以及其是否为粗体,斜体或两者皆有来获取字体文件名(例如Arial.ttf)。使用这些信息,我需要找到字体文件,以便用于渲染。
一些其他例子:
您有任何关于如何在C++(Win32)中实现此功能的想法吗?
据我所知,目前没有可靠的方法来实现这个目标。
Windows API 处理字体族和映射,而不是处理字体文件的更低层级。此外,请注意即使您成功获取了字体的文件名,(就我所知)也没有任何渲染函数能够接受它,那么您该怎么办呢?
尽管如此,您可以查看注册表键 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts
来从逻辑名称中获取字体的文件名。可以在此处找到该解决方案的实现:here。
与早期帖子相关的是,这似乎是一种可靠的方法:
1) 读取注册的Windows字体列表,从以下路径获取: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts\ 在这里你可以获得文件名和备用文件路径。 字体名称并不实用,因为它们可能会因用户所在地区而改变。
2) 加载TrueType文件 (.ttf, .ttc, .otf): 使用FreeType https://www.freetype.org/)。只需初始化FreeType库并使用FT_New_Face(library, path, 0, &face)加载面。
3) 使用FreeType获取字体族名称。 使用FT_Get_Sfnt_Name_Count() 和 FT_Get_Sfnt_Name() 获取字符串表。 您需要检查编码是否为Ansi、UTF16或其他,因为某些字符串将以多种不同的语言和编码出现。
4) 获取OS2 TrueType属性。 使用(TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2) 获取OS2结构。 使用类似于https://www.microsoft.com/typography/otspec/os2.htm#fc的文档解释该结构。
5) 现在你有字体文件路径、字体族名称、样式属性和其他信息。建立这些的列表和基于字体族名称和样式搜索文件的函数。
自Windows Vista SP2以来,可以通过字体家族名称查询字体。 有多种方法可以从family_name、weight和italic中检索字体文件名。 这个答案提供了两种可能的方法,但还有很多其他方法。
请注意,DirectWrite可能会为一个字体返回多个字体文件名,但我不知道什么情况下会发生。根据我进行的少量测试,它总是返回一个字体。
请注意,我不熟悉C++,所以你可能需要修改一些部分,但这会给你一个解决问题的好思路。
适用于Windows Vista SP2及更高版本
#include <iostream>
#include <dwrite.h>
#include <list>
#pragma comment(lib, "dwrite.lib")
using namespace std;
list<WCHAR*> get_fonts_path(WCHAR* family_name, BOOL is_bold, BOOL is_italic)
{
list<WCHAR*> fonts_filename_list;
HRESULT hr;
IDWriteFactory* dwrite_factory;
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&dwrite_factory));
if (FAILED(hr))
{
return fonts_filename_list;
}
IDWriteFontCollection* sys_collection;
hr = dwrite_factory->GetSystemFontCollection(&sys_collection, false);
if (FAILED(hr))
{
dwrite_factory->Release();
return fonts_filename_list;
}
UINT32 index;
BOOL exists;
sys_collection->FindFamilyName(family_name, &index, &exists);
if (FAILED(hr))
{
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
if (!exists) {
wcout << L"The font '" << family_name << L"' does not exist" << endl;
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
IDWriteFontFamily* font_family;
hr = sys_collection->GetFontFamily(index, &font_family);
if (FAILED(hr))
{
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
IDWriteFont* matching_font;
DWRITE_FONT_WEIGHT weight = is_bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR;
DWRITE_FONT_STYLE style = is_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
hr = font_family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &matching_font);
if (FAILED(hr))
{
font_family->Release();
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
IDWriteFontFace* font_face;
hr = matching_font->CreateFontFace(&font_face);
if (FAILED(hr))
{
matching_font->Release();
font_family->Release();
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
UINT file_count;
hr = font_face->GetFiles(&file_count, NULL);
if (FAILED(hr))
{
font_face->Release();
matching_font->Release();
font_family->Release();
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
IDWriteFontFile** font_files = new IDWriteFontFile * [file_count];
hr = font_face->GetFiles(&file_count, font_files);
if (FAILED(hr))
{
font_face->Release();
matching_font->Release();
font_family->Release();
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
for (int i = 0; i < file_count; i++)
{
LPCVOID font_file_reference_key;
UINT font_file_reference_key_size;
hr = font_files[i]->GetReferenceKey(&font_file_reference_key, &font_file_reference_key_size);
if (FAILED(hr))
{
font_files[i]->Release();
continue;
}
IDWriteFontFileLoader* loader;
hr = font_files[i]->GetLoader(&loader);
if (FAILED(hr))
{
font_files[i]->Release();
continue;
}
IDWriteLocalFontFileLoader* local_loader;
hr = loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), (void**)&local_loader);
if (FAILED(hr))
{
loader->Release();
font_files[i]->Release();
continue;
}
UINT32 path_length;
hr = local_loader->GetFilePathLengthFromKey(font_file_reference_key, font_file_reference_key_size, &path_length);
if (FAILED(hr))
{
local_loader->Release();
loader->Release();
font_files[i]->Release();
continue;
}
WCHAR* path = new WCHAR[path_length + 1];
hr = local_loader->GetFilePathFromKey(font_file_reference_key, font_file_reference_key_size, path, path_length + 1);
if (FAILED(hr))
{
local_loader->Release();
loader->Release();
font_files[i]->Release();
continue;
}
fonts_filename_list.push_back(path);
local_loader->Release();
loader->Release();
font_files[i]->Release();
}
font_face->Release();
matching_font->Release();
font_family->Release();
sys_collection->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
int main() {
list<WCHAR*> fonts_filename_list = get_fonts_path(const_cast<WCHAR*>(L"Arial"), false, true);
for (WCHAR* font_filename : fonts_filename_list)
{
wcout << L"Font filename: " << font_filename << endl;
}
return 0;
}
#include <iostream>
#include <dwrite.h>
#include <list>
#pragma comment(lib, "dwrite.lib")
using namespace std;
list<WCHAR*> get_fonts_path(WCHAR* family_name, BOOL is_bold, BOOL is_italic)
{
list<WCHAR*> fonts_filename_list;
HRESULT hr;
IDWriteFactory* dwrite_factory;
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&dwrite_factory));
if (FAILED(hr))
{
return fonts_filename_list;
}
IDWriteGdiInterop* gdi_interop;
hr = dwrite_factory->GetGdiInterop(&gdi_interop);
if (FAILED(hr))
{
dwrite_factory->Release();
return fonts_filename_list;
}
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
wcscpy_s(lf.lfFaceName, LF_FACESIZE, family_name);
lf.lfWeight = is_bold ? FW_BOLD : FW_REGULAR;
lf.lfItalic = is_italic;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_TT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = ANTIALIASED_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
IDWriteFont* matching_font;
hr = gdi_interop->CreateFontFromLOGFONT(&lf, &matching_font);
if (FAILED(hr))
{
gdi_interop->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
IDWriteFontFace* font_face;
hr = matching_font->CreateFontFace(&font_face);
if (FAILED(hr))
{
matching_font->Release();
gdi_interop->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
UINT file_count;
hr = font_face->GetFiles(&file_count, NULL);
if (FAILED(hr))
{
font_face->Release();
matching_font->Release();
gdi_interop->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
IDWriteFontFile** font_files = new IDWriteFontFile * [file_count];
hr = font_face->GetFiles(&file_count, font_files);
if (FAILED(hr))
{
font_face->Release();
matching_font->Release();
gdi_interop->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
for (int i = 0; i < file_count; i++)
{
LPCVOID font_file_reference_key;
UINT font_file_reference_key_size;
hr = font_files[i]->GetReferenceKey(&font_file_reference_key, &font_file_reference_key_size);
if (FAILED(hr))
{
font_files[i]->Release();
continue;
}
IDWriteFontFileLoader* loader;
hr = font_files[i]->GetLoader(&loader);
if (FAILED(hr))
{
font_files[i]->Release();
continue;
}
IDWriteLocalFontFileLoader* local_loader;
hr = loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), (void**)&local_loader);
if (FAILED(hr))
{
loader->Release();
font_files[i]->Release();
continue;
}
UINT32 path_length;
hr = local_loader->GetFilePathLengthFromKey(font_file_reference_key, font_file_reference_key_size, &path_length);
if (FAILED(hr))
{
local_loader->Release();
loader->Release();
font_files[i]->Release();
continue;
}
WCHAR* path = new WCHAR[path_length + 1];
hr = local_loader->GetFilePathFromKey(font_file_reference_key, font_file_reference_key_size, path, path_length + 1);
if (FAILED(hr))
{
local_loader->Release();
loader->Release();
font_files[i]->Release();
continue;
}
fonts_filename_list.push_back(path);
local_loader->Release();
loader->Release();
font_files[i]->Release();
}
font_face->Release();
matching_font->Release();
gdi_interop->Release();
dwrite_factory->Release();
return fonts_filename_list;
}
int main() {
list<WCHAR*> fonts_filename_list = get_fonts_path(const_cast<WCHAR*>(L"Arial"), false, true);
for (WCHAR* font_filename : fonts_filename_list)
{
wcout << L"Font filename: " << font_filename << endl;
}
return 0;
}
一个解决方案是访问字体文件并从名称表中提取名称以创建自己的查找(STL映射是一种简单的方法)。可以在这里找到TTF文件格式的详细信息。