wxleasyland@139.com
2021.12
unicode型字体文件中,有字符unicode与字形编码索引值index的关系。
一、得到字体中字符unicode与字形编码索引值index的关系
参考别人的《GetFontUnicodeRanges获取指定字体文件中的字符》、《字样索引(Glyph Index)与字符之间的转换》。
这个程序中有CreateFont()时要指定字体准确名称的问题,可双击字体查看这个名称,比较麻烦,暂无解决。
在VS的MFC的对话框的按钮的程序中(设置中字符集采用多字节):
CString cstr, cstrin, cstrout;
GetDlgItem(IDC_EDIT1)->GetWindowText(cstrin);
HDC hdc = ::GetDC(0);
DWORD size = 0;
//wchar_t myChar[200000]; //unicode char
wchar_t *myChar=(wchar_t*) new BYTE[2000000];
int error2 = AddFontResourceEx(cstrin, FR_PRIVATE, 0);
if (!error2)
{
MessageBox("字体加载失败AddFontResourceEx!");
return;
}
HFONT hfont = NULL;
hfont = CreateFont(20, 0, 0, 0, FW_HEAVY, 0, 0, 0, DEFAULT_CHARSET, \
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, _T("Symath"));
//注:CreateFont中要把字体名称改成你的字体的准确名称,如果名称乱输或不对,则函数也会成功,会得到一个很大的字体,未研究是什么字体
if(hfont==NULL)
{
MessageBox("字体加载失败 CreateFont!");
return;
}
HFONT oldFont = (HFONT)SelectObject(hdc, hfont);
//第一次调用,获得所需空间大小
size = GetFontUnicodeRanges(hdc, NULL);
// 分配空间
GLYPHSET *pGlyphSet = (GLYPHSET*) new BYTE[size];
pGlyphSet->cbThis = size;
//第二次调用,获得字库相关信息
size = GetFontUnicodeRanges(hdc, pGlyphSet);
int i; int j;
int q = 0;
for (i = 0; i < pGlyphSet->cRanges; i++)
{
for (j = 0; j < pGlyphSet->ranges[i].cGlyphs; j++)
{
myChar[q] = j + pGlyphSet->ranges[i].wcLow;//这就是包含的字符
q++;
}
}
//最终得到q是字符总数
cstr.Format("q=%d", q);
MessageBox(cstr);
WORD gp[100];
cstr.Format("unicode\tindex\r\n", q);
cstrout += cstr;
for (i = 0; i < q; i++)
{
GetGlyphIndicesW(hdc, &myChar[i], 1, gp, GGI_MARK_NONEXISTING_GLYPHS);
cstr.Format("%04X\t%04X\r\n", (WORD)myChar[i], gp[0] );
cstrout += cstr;
}
SetDlgItemText(IDC_EDIT9, cstrout);
二、显示字体中的所有字符
根据别人的《C++解析IconFont矢量字体文件ttf,以及无锯齿显示矢量字体》。
程序是采用gdi接口来编的,在vs2017下有一些错误,修改了一下。
这个程序解决了CreateFont()时要指定字体名称的问题,可以根据这个程序,再用GetGlyphIndicesW()来得到index关系。
另外,有一个情况:字体中有字符存在,但没有字形,即字符显示出来是空的。这种情况很常见。
在VS的MFC对话框程序中成功。
(设置中字符集采用UNICODE)
程序前面加上:
#include <vector>
#include "gdiplus.h"
#pragma comment(lib,"gdiplus.lib")
using namespace Gdiplus;
加上全局变量:
// 初始化gdiplus
ULONG_PTR m_gdiplusToken;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
OnInitDialog()中加上:
// 初始化gdiplus
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
加上2个子函数程序:
//1、获取字体名称(gdiplus初始化的代码最好放在程序的初始化中,且全局只能初始化一次)
BOOL GetFontName(LPCTSTR pFilePath, LPTSTR pFontName)
{
// 添加字体
Gdiplus::PrivateFontCollection pCollection;
if (Gdiplus::Status::Ok != pCollection.AddFontFile(pFilePath)) return FALSE;
int count = pCollection.GetFamilyCount();
if (count == 0) return FALSE;
int found = 0;
Gdiplus::FontFamily* pFontFamily = (Gdiplus::FontFamily*)malloc(count * sizeof(Gdiplus::FontFamily));
pCollection.GetFamilies(count, pFontFamily, &found); //这里好像需要字符串是WCHAR才行!!!!!所以工程要设置 成 unicode环境
if (found == 0) {
free(pFontFamily);
return FALSE;
}
// 获取字体名称
pFontFamily->GetFamilyName(pFontName);
free(pFontFamily);
return TRUE;
}
//2、获取字体所包含的所有图标的unicode代码
std::vector<WCHAR> GetIconNames(LPCTSTR pFilePath, LPCTSTR pFontName)
{
// 加载字体文件
::AddFontResourceEx(pFilePath, FR_PRIVATE, 0);
std::vector<WCHAR> vcNames;
// 临时获取一个HDC
HDC hDc = ::GetDC(NULL);
// 创建所加载的文件的字体
HFONT hfont = ::CreateFont(20, 0, 0, 0, FW_HEAVY, 0, 0, 0, DEFAULT_CHARSET, \
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, pFontName);
// 载入到当前的HDC中
HFONT oldFont = (HFONT)::SelectObject(hDc, (HGDIOBJ)hfont);
// 获取该ttf字体文件所有的全部unicode字符
DWORD size = ::GetFontUnicodeRanges(hDc, NULL);
GLYPHSET * pGlyphSet = (GLYPHSET*) new BYTE[size];
pGlyphSet->cbThis = size;
size = GetFontUnicodeRanges(hDc, pGlyphSet);
for (int i = 0; i < pGlyphSet->cRanges; i++)
for (int j = 0; j < pGlyphSet->ranges[i].cGlyphs; j++)
vcNames.emplace_back(j + pGlyphSet->ranges[i].wcLow);
::SelectObject(hDc, (HGDIOBJ)oldFont);
::ReleaseDC(NULL, hDc);
::RemoveFontResourceEx(pFilePath, FR_PRIVATE, 0);
delete pGlyphSet;
return vcNames;
}
在按钮程序中,加上:
CString pFontPath;
GetDlgItemText(IDC_EDIT1, pFontPath);
//TCHAR * pFontPath = _T("F:\\MyCode\\CPP\\DuiLib\\Fonts\\fontawesome-webfont.ttf");
TCHAR fontName[MAX_PATH] = { 0 };
if (!GetFontName(pFontPath, fontName)) return;
auto iconNames = GetIconNames(pFontPath, fontName);
HDC hDC = ::GetDC(m_hWnd);
// 添加字体
Gdiplus::PrivateFontCollection pCollection;
if (Gdiplus::Status::Ok != pCollection.AddFontFile(pFontPath)) return;
Gdiplus::Font font(fontName, 16, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel, &pCollection);
int i = 0, j = 0;
for (auto iconName : iconNames)
{
wchar_t wc_iconFont[2] = { 0 };
wc_iconFont[0] = iconName;
Gdiplus::Graphics graphics(hDC);
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
Gdiplus::SolidBrush solidBrush(Gdiplus::Color(255, 0, 0, 0));
graphics.DrawString( wc_iconFont, 1, &font, Gdiplus::PointF(i, j), &solidBrush); //画出wc_iconFont这个字符(实际是个字串)
i += 50;
if (i % 500 == 0)
{
i = 0;
j += 50;
}
}
在程序退出的OnClose()代码中,加上:
// 卸载gdiplus
Gdiplus::GdiplusShutdown(m_gdiplusToken);