How To Get English Name For East Asian Font Names

The fonts for many East Asian languages have two typeface names: an English name and a localized name.

比如:

宋体 vs SimSun

幼圆 vs SimYou


有时候我们需要得到English name,比如PDF中存储的字体名一般都是英文名,经常会用到English name和localized name之间来回转换,本文只说如何从localized name转换为English name,反之其实同理。

具体做法就是用EnumFonts函数枚举所有字体,在它的callback function处理每个字体的的信息,得到它的English name,并把English name和localized name map起来,每次用的时候都可以查询。

代码如下:

class CFontInfo{
	...
	CMapStringToString m_mapLocToEngFontName;
	int createFontNameMaps();
	...
}


struct NAMERECORD {
	USHORT platformID;
	USHORT encodingID;
	USHORT languageID;
	USHORT nameID;
	USHORT length;
	USHORT offset;
};

#define SWAPBYTES(w)  ( ((USHORT)((w)[0]) << 8) | (w)[1])

//callback function
int CALLBACK MyEnumFontsProc(CONST LOGFONT *lplf,CONST TEXTMETRIC *lptm,DWORD dwType,LPARAM lpData)
{
	for(int j=0;j<LF_FACESIZE;j++)
	{
		if(lplf->lfFaceName[j]==0)
			return 1;
		else if(lplf->lfFaceName[j]<0 || lplf->lfFaceName[j]>128)
			break;
	}

	HDC hdc=GetDC(NULL);
	HFONT hfont = CreateFontIndirect(lplf); 
	if(hfont) {
		HFONT hfontOld = (HFONT)::SelectObject(hdc, hfont);
		if(hfontOld) {
			DWORD dw = ::GetFontData(hdc, 'eman', 0, NULL, 0);
			if(dw != GDI_ERROR) {
				LPBYTE lpv = (BYTE *)malloc(dw);
				if(lpv) {
					dw = ::GetFontData(hdc, 'eman', 0, lpv, dw);
					if(dw != GDI_ERROR) {
						UINT offset = 0;
						USHORT format, count, stringOffset;
						NAMERECORD * rgNR;

						format = SWAPBYTES(&lpv[offset]);
						offset += sizeof(USHORT);
						count = SWAPBYTES(&lpv[offset]);
						offset += sizeof(USHORT);
						stringOffset = SWAPBYTES(&lpv[offset]);
						offset += sizeof(USHORT);

						rgNR = (struct NAMERECORD *)calloc(count, sizeof(NAMERECORD));

						for(int i = 0; i < count; i++) {
							rgNR[i].platformID = SWAPBYTES(&lpv[offset]);
							offset += sizeof(USHORT);
							rgNR[i].encodingID = SWAPBYTES(&lpv[offset]);
							offset += sizeof(USHORT);
							rgNR[i].languageID = SWAPBYTES(&lpv[offset]);
							offset += sizeof(USHORT);
							rgNR[i].nameID   = SWAPBYTES(&lpv[offset]);
							offset += sizeof(USHORT);
							rgNR[i].length   = SWAPBYTES(&lpv[offset]);
							offset += sizeof(USHORT);
							rgNR[i].offset   = SWAPBYTES(&lpv[offset]);
							offset += sizeof(USHORT);

							// The name string is at
							// lpv + stringOffset + rgNR[i].offset
							// The name string length is rgNR[i].length

							// The bytes in both cases must each be run
							// through something like the SWAPBYTES macro
							// because all font information is big endian
							// regardless of endian-ness of the platform).

							//http://www.microsoft.com/typography/otspec/name.htm
							if(rgNR[i].languageID==0 && rgNR[i].nameID==4)//Full font name
							{
								CString strEngName((LPCSTR)(lpv+stringOffset+rgNR[i].offset),rgNR[i].length);
								CString strLogName(lplf->lfFaceName);
								CFontInfo *pFontInfo=(CFontInfo*)lpData;
								CString strOut;
								if(pFontInfo->m_mapLocToEngFontName.Lookup(strLogName, strOut)==0)
								{
									pFontInfo->m_mapLocToEngFontName[strLogName] = strEngName;
								}
								break;
							}
						}
						free(rgNR);
					}
					free(lpv);
				}
			}
			::SelectObject(hdc, hfontOld);
		}
		::DeleteObject(hfont);
	}
	ReleaseDC(NULL, hdc);
	return 1;
}

int CFontInfo::createFontNameMaps()
{
	HDC dc=::GetDC(NULL);
	if(!dc)
		return 0;
	EnumFonts(dc,NULL,MyEnumFontsProc,(LPARAM)this);

	::ReleaseDC(NULL, dc);
	return m_mapLocToEngFontName.GetCount();
}


//conver logic name to english name
CString strEngName;
if(m_mapLocToEngFontName.Lookup(pCurFontInfo->m_strName, strEngName))
{
	//do something
}

ps: 实际测试,“微软雅黑”并没有找到对应的英文名,我记得“微软雅黑”的英文名是Microsoft Yahei,它对应的languageID=0x0409,如果去掉languageID==0的条件,“微软雅黑”得到的英文名就是空,查看点击打开链接 ,也没有必须用languageID==0的理由,但是不用它就不对,不晓得为什么,这个后续再研究吧.


ps2:google了一下,发现找到了这段代码的出处,应该是作者受不了windows居然不提供这样的API,然后自己去看了OpenType Specification,研究出来的方法,这是那篇文章的地址:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值