通过字体名获取字体文件

由于在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;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值