通过字体名获取字体文件
由于在GLFT/FreeType中需要传入字体文件作为参数,所以需要通过字体名来寻找字体文件。现已完成,特此总结分享。
参考链接:
https://www.codeproject.com/Articles/1235/Finding-a-Font-file-from-a-Font-name
https://github.com/chaoticbob/Cinder-SdfText 具体看acquireFontNamesAndPaths,有读mac,windows,Linux的
https://github.com/pezy/QtLab/blob/fb226b6d3af5f8efcd449b1b9025c05b901b828f/QtLab/Playground/main.cpp
//.h
//通过字体名获取字体文件
BOOL GetFontFile(LPCTSTR lpszFontName, CString &strFontFile, BOOL bBold = FALSE, BOOL bItalic = FALSE);
//通过字体文件获取字体名
BOOL GetFontName(LPCTSTR lpszFontFile, CString& strFontName);
//字体中英文对照
std::map<std::string, std::string> FontFaceMap();
//.cpp
LONG GetNextNameValue(HKEY key, LPCTSTR subkey, LPTSTR szName, LPTSTR szData)
{
static HKEY hkey = NULL;
static DWORD dwIndex = 0;
LONG retval;
if (subkey == NULL && szName == NULL && szData == NULL)
{
//TRACE(_T("closing key\n"));
if (hkey)
RegCloseKey(hkey);
hkey = NULL;
return ERROR_SUCCESS;
}
if (subkey && subkey[0] != 0)
{
retval = RegOpenKeyEx(key, subkey, 0, KEY_READ, &hkey);
// if (retval != ERROR_SUCCESS)
// {
// //TRACE(_T("RegOpenKeyEx failed\n"));
// return retval;
// }
// else
// {
// //TRACE(_T("RegOpenKeyEx ok\n"));
// }
dwIndex = 0;
}
else
{
dwIndex++;
}
ASSERT(szName != NULL && szData != NULL);
*szName = 0;
*szData = 0;
char szValueName[MAX_PATH];
DWORD dwValueNameSize = sizeof(szValueName) - 1;
BYTE szValueData[MAX_PATH];
DWORD dwValueDataSize = sizeof(szValueData) - 1;
DWORD dwType = 0;
retval = RegEnumValue(hkey, dwIndex, szValueName, &dwValueNameSize, NULL,
&dwType, szValueData, &dwValueDataSize);
if (retval == ERROR_SUCCESS)
{
//TRACE(_T("szValueName=<%s> szValueData=<%s>\n"), szValueName, szValueData);
lstrcpy(szName, (char *)szValueName);
lstrcpy(szData, (char *)szValueData);
}
else
{
//TRACE(_T("RegEnumKey failed\n"));
}
return retval;
}
BOOL GetFontFile(LPCTSTR lpszFontName, CString& strDisplayName, CString& strFontFile,
BOOL bBold /*= FALSE*/, BOOL bItalic /*= FALSE*/)
{
if (lpszFontName && lpszFontName[0] == 0)
{
strFontFile = "";
return FALSE;
}
CString strFontName = lpszFontName;
if (bBold)
{
strFontName += " Bold";
}
if (bItalic)
{
strFontName += " Italic";
}
_TCHAR szName[2 * MAX_PATH];
_TCHAR szData[2 * MAX_PATH];
// int nVersion;
// CString strVersion;
// GetWinVer(strVersion, &nVersion);
// //TRACE(_T("strVersion=%s\n"), strVersion);
CString strFont = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
strFontFile.Empty();
BOOL bResult = FALSE;
while (GetNextNameValue(HKEY_LOCAL_MACHINE, strFont, szName, szData) == ERROR_SUCCESS)
{
CString strName = szName;
int nFind = strName.ReverseFind('(');
if (nFind != -1)
{
strName = strName.Left(nFind-1);
}
CStringArray strArr;
SplitCString(strName, "&", strArr);
nFind = 0;
for (int i = 1; i < strArr.GetSize(); i++)
{
CString strTmp = strArr[i].Trim();
if (strTmp == strFontName)
{
nFind = 1;
break;
}
}
if (_strnicmp(strFontName.GetBuffer(), szName, strlen(strFontName.GetBuffer())) == 0
|| nFind)
{
//TRACE(_T("found font\n"));
strDisplayName = szName;
strFontFile = szData;
bResult = TRUE;
break;
}
strFont.Empty(); // this will get next value, same key
}
GetNextNameValue(HKEY_LOCAL_MACHINE, NULL, NULL, NULL); // close the registry key
if (strFontFile.IsEmpty() && (strFontName.Find("Bold") != -1
|| strFontName.Find("Italic") != -1))
{
strFontName.Replace(" Bold", "");
strFontName.Replace(" Italic", "");
//GetFontFile(strFontName, strDisplayName, strFontFile, bBold, bItalic);
strFontFile.Empty();
bResult = FALSE;
strFont = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
while (GetNextNameValue(HKEY_LOCAL_MACHINE, strFont, szName, szData) == ERROR_SUCCESS)
{
CString strName = szName;
int nFind = strName.ReverseFind('(');
if (nFind != -1)
{
strName = strName.Left(nFind - 1);
}
CStringArray strArr;
SplitCString(strName, "&", strArr);
nFind = 0;
for (int i = 1; i < strArr.GetSize(); i++)
{
CString strTmp = strArr[i].Trim();
if (strTmp == strFontName)
{
nFind = 1;
break;
}
}
if (_strnicmp(strFontName.GetBuffer(), szName, strlen(strFontName.GetBuffer())) == 0
|| nFind)
{
//TRACE(_T("found font\n"));
strDisplayName = szName;
strFontFile = szData;
bResult = TRUE;
break;
}
strFont.Empty(); // this will get next value, same key
}
GetNextNameValue(HKEY_LOCAL_MACHINE, NULL, NULL, NULL); // close the registry key
}
return bResult;
}
BOOL GetFontFile(LPCTSTR lpszFontName, CString &strFontFile, BOOL bBold /*= FALSE*/, BOOL bItalic /*= FALSE*/)
{
CString strFontName = lpszFontName;
CString strDispName;
BOOL bRes = GetFontFile(strFontName, strDispName, strFontFile, bBold, bItalic);
if (bRes)
{
return bRes;
}
//中英文字体名称映射
auto mapChnEng = FontFaceMap();
auto itFind = mapChnEng.find(strFontName.GetBuffer());
int nFind = -1;
if (itFind == mapChnEng.end())
{
nFind = strFontName.Find("Light");
if (nFind != -1)
{
strFontName.Replace(" Light", "");
}
itFind = mapChnEng.find(strFontName.GetBuffer());
}
if (!bRes && itFind != mapChnEng.end())
{
strFontName = itFind->second.c_str(); /*G_UserData.GetAt("Fonts", strFontName)*/;
nFind != -1 ? strFontName += " Light" : NULL;
bRes = GetFontFile(strFontName, strDispName, strFontFile, bBold, bItalic);
}
if (strFontFile.IsEmpty())
{
strFontFile = "msyh.ttc";
}
return bRes;
}
BOOL GetFontName(LPCTSTR lpszFontFile, CString& strFontName)
{
if (lpszFontFile == 0)
{
strFontName = "";
return FALSE;
}
CString strFontFile = lpszFontFile;
_TCHAR szName[2 * MAX_PATH];
_TCHAR szData[2 * MAX_PATH];
// int nVersion;
// CString strVersion;
// GetWinVer(strVersion, &nVersion);
// //TRACE(_T("strVersion=%s\n"), strVersion);
CString strFont = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
strFontName.Empty();
BOOL bResult = FALSE;
while (GetNextNameValue(HKEY_LOCAL_MACHINE, strFont, szName, szData) == ERROR_SUCCESS)
{
if (_strnicmp(strFontFile.GetBuffer(), szData, strlen(strFontFile.GetBuffer())) == 0)
{
//TRACE(_T("found font\n"));
strFontName = szName;
bResult = TRUE;
break;
}
strFont.Empty(); // this will get next value, same key
}
GetNextNameValue(HKEY_LOCAL_MACHINE, NULL, NULL, NULL); // close the registry key
int nFind = strFontName.ReverseFind('(');
if (nFind != -1)
{
strFontName = strFontName.Left(nFind - 1);
}
CStringArray strArr;
SplitCString(strFontName, "&", strArr);
strFontName = strArr[0].Trim();
nFind = strFontName.Find(" Light");
if (nFind != -1)
{
strFontName.Replace(" Light", "");
}
strFontName.Replace(" Bold", "");
strFontName.Replace(" Italic", "");
auto mapChnEng = FontFaceMap();
auto itFind = find_if(mapChnEng.begin(), mapChnEng.end(),
[&](pair<const string, string> &a) {return a.second == strFontName.GetBuffer(); });
if (itFind != mapChnEng.end())
{
strFontName = itFind->first.c_str();
}
if (nFind != -1)
{
strFontName += " Light";
}
return bResult;
}
// SafeRelease inline function.
template <class T> inline void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
std::wstring GetFontFaceNamePair(IDWriteLocalizedStrings* pFamilyNames, UINT32 index)
{
std::wstring result;
UINT32 length = 0;
HRESULT hr = pFamilyNames->GetStringLength(index, &length);
// Allocate a string big enough to hold the name.
wchar_t* name = new (std::nothrow) wchar_t[length+1];
if (name == NULL)
{
hr = E_OUTOFMEMORY;
}
// Get the family name.
if (SUCCEEDED(hr))
{
hr = pFamilyNames->GetString(index, name, length+1);
}
if (SUCCEEDED(hr))
{
result = name;
}
delete [] name;
return result;
}
//将wstring转换成string
string ws2s(wstring wstr)
{
string result;
//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.size(), NULL, 0, NULL, NULL);
char* buffer = new char[len + 1];
//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.size(), buffer, len, NULL, NULL);
buffer[len] = '\0';
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
std::map<std::string, std::string> FontFaceMap()
{
std::map<std::string, std::string> map;
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
// Get the default locale for this user.
int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
if (!defaultLocaleSuccess || wcscmp(localeName, L"en-us") == 0)
return map;
IDWriteFactory* pDWriteFactory = NULL;
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
IDWriteFontCollection* pFontCollection = NULL;
// Get the system font collection.
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->GetSystemFontCollection(&pFontCollection);
UINT32 familyCount = 0;
// Get the number of font families in the collection.
if (SUCCEEDED(hr))
{
familyCount = pFontCollection->GetFontFamilyCount();
for (UINT32 i = 0; i < familyCount; ++i)
{
IDWriteFontFamily* pFontFamily = NULL;
// Get the font family.
if (SUCCEEDED(hr))
{
hr = pFontCollection->GetFontFamily(i, &pFontFamily);
}
IDWriteLocalizedStrings* pFamilyNames = NULL;
// Get a list of localized strings for the family name.
if (SUCCEEDED(hr))
{
hr = pFontFamily->GetFamilyNames(&pFamilyNames);
UINT32 defaultLocaleIndex = 0;
UINT32 EnglishIndex = 0;
BOOL exists1 = false, exists2 = false;
if (SUCCEEDED(hr))
{
HRESULT hr1, hr2;
hr1 = pFamilyNames->FindLocaleName(localeName, &defaultLocaleIndex, &exists1);
hr2 = pFamilyNames->FindLocaleName(L"en-us", &EnglishIndex, &exists2);
if (SUCCEEDED(hr1) && exists1 && SUCCEEDED(hr2) && exists2 && defaultLocaleIndex != EnglishIndex)
{
auto defaultLocaleName = GetFontFaceNamePair(pFamilyNames, defaultLocaleIndex);
auto EnglishName = GetFontFaceNamePair(pFamilyNames, EnglishIndex);
map[ws2s(defaultLocaleName)] = ws2s(EnglishName);
//std::wcout << defaultLocaleName.c_str() << "=>" << EnglishName.c_str() << std::endl;
}
SafeRelease(&pFamilyNames);
}
SafeRelease(&pFontFamily);
}
}
SafeRelease(&pFontCollection);
}
SafeRelease(&pDWriteFactory);
}
return map;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律