Freetype获得truetype字体宽度

通过Freetype库获得truetype字体宽度,如果有需要改进之处,请不吝赐教。
很抱歉,这是用古老的MFC写的,但是你应该很容易的替换成标准库的字符串和容器。

#include <iostream>
#include <afx.h>
#include <afxtempl.h>
#include <shlobj_core.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

class FreeType
{
	static inline void DoneFace(FT_Face face)
	{
		FT_Done_Face(face);
	}
public:
	FreeType()
		: m_library(nullptr)
		, m_timer(0)
	{
		FT_Error error = FT_Init_FreeType(&m_library);
		if (error) {

		}
	}
	FT_Face NewFace(const CString& fontFile);
	void DoneFaces()
	{
		POSITION pos = m_faces.GetStartPosition();
		CString key;
		FT_Face face;
		while (pos != NULL)
		{
			m_faces.GetNextAssoc(pos, key, face);
			FreeType::DoneFace(face);
		}
		m_faces.RemoveAll();
		KillTimer(NULL, m_timer);
		m_timer = 0;
	}
	static inline void SetCharSize(FT_Face     face,
		FT_F26Dot6  char_width,
		FT_F26Dot6  char_height,
		FT_UInt     horz_resolution,
		FT_UInt     vert_resolution)
	{
		FT_Set_Char_Size(face, char_width, char_height, horz_resolution, vert_resolution);
	}
	static inline void SetPixelSizes(FT_Face     face,
		FT_UInt  pixel_width,
		FT_UInt  pixel_height)
	{
		FT_Set_Pixel_Sizes(face, pixel_width, pixel_height);
	}
	
	static inline void LoadChar(FT_Face   face,
		FT_ULong  char_code,
		FT_Int32  load_flags) // FT_LOAD_DEFAULT, FT_LOAD_COMPUTE_METRICS
	{
		FT_Load_Char(face, char_code, load_flags);
	}
	static inline FT_Glyph GetGlyph(FT_GlyphSlot glyph)
	{
		FT_Glyph res;
		FT_Get_Glyph(glyph, &res);
		return res;
	}
	static inline void DoneGlyph(FT_Glyph glyph)
	{
		FT_Done_Glyph(glyph);
	}
	~FreeType()
	{
		DoneFaces();
		FT_Done_FreeType(m_library);
	}

	FT_Library    m_library;
	CMap<CString, LPCTSTR, FT_Face, FT_Face> m_faces;
	UINT_PTR m_timer;
};

FreeType g_freetype;
void __stdcall DoneFacesTimerproc(
	HWND Arg1,
	UINT Arg2,
	UINT_PTR Arg3,
	DWORD Arg4
)
{
	g_freetype.DoneFaces();
}
FT_Face FreeType::NewFace(const CString& fontFile)
{
	FT_Face face;
	BOOL found = m_faces.Lookup(fontFile, face);
	if (found)
		return face;
	LPITEMIDLIST ppidl;
	TCHAR lpsbuf[255];
	SHGetSpecialFolderLocation(NULL, CSIDL_FONTS, &ppidl);
	SHGetPathFromIDList(ppidl, lpsbuf);
	CoTaskMemFree(ppidl);
	const size_t len = _tcslen(lpsbuf);
	if (len >= sizeof(lpsbuf) - 1)
		// can't go on
		return nullptr;
	lpsbuf[len] = '\\';
	lpsbuf[len + 1] = '\0';
	FT_Error error = FT_New_Face(m_library,
		CT2A(CString(lpsbuf) + fontFile),
		0,
		&face);
	if (error == FT_Err_Cannot_Open_Resource)
	{
		// 试一试.ttc文件
		if (fontFile.Right(4).MakeLower() == _T(".ttf"))
		{
			CString fontFile2 = fontFile.Left(fontFile.GetLength() - 4) + _T(".ttc");
			error = FT_New_Face(m_library,
				CT2A(CString(lpsbuf) + fontFile2),
				0,
				&face);
		}
	}
	if (error)
	{
		return nullptr;
	}
	m_faces[fontFile] = face;
	// 只要NewFace在超时时间内调用,计时器会被重置。
	SetTimer(NULL, m_timer, 5000, DoneFacesTimerproc);
	return face;
}

std::tuple<double, double, double> GetTextWidth(const CString& fontFile, double textHeight, const CString& text2)
{
	double Ascent = textHeight;
	double Descent = 0, width = 0;
	FT_Face face = g_freetype.NewFace(fontFile);
	if (face == nullptr)
		return { 0.0, 0.0, 0.0 };
	// 放大倍数
	double ratio = 640.0 / textHeight;
	auto fontHeight = FT_UInt(640);
	//const double* LookForWidthTableTtfFile(const CString& ttfFace);
	//const auto widthTable = LookForWidthTableTtfFile(pTSD->FontFile);
	double whratio;
	//if (widthTable)
	//	whratio = widthTable[96] / 100.0;
	//else
		whratio = 1.4382;
	auto fontWidth = FT_UInt(fontHeight * whratio); // 经验系数
	FreeType::SetPixelSizes(face, fontWidth, fontHeight);
	CStringW text(CT2W(text2).operator LPWSTR());
	size_t len = text.GetLength();
	int xmin = 0, ymin = 0, xmax = 0;
	for (size_t i = 0; i < len; ++i)
	{
		FreeType::LoadChar(face, text[i], FT_LOAD_COMPUTE_METRICS);
		FT_Glyph_Metrics metrics = face->glyph->metrics;
		if (i == 0)
		{
			xmin = 0; // metrics.horiBearingX;
			ymin = metrics.horiBearingY - metrics.height;
		}
		else
		{
			ymin = min(ymin, metrics.horiBearingY - metrics.height);
		}
		if (i == len - 1)
		{
			xmax += metrics.horiAdvance; // metrics.horiBearingX + metrics.width;
		}
		else
		{
			xmax += metrics.horiAdvance;
		}
	}
	// 为了提高程序性能,face被缓存。在空闲时用一个计时器来释放faces。
	//FreeType::DoneFace(face);
	// 缩小ratio倍
	// 再除以64,因为FT_Pos是26.6定点小数
	width = (xmax - xmin) / ratio / 64.0 * widthFactor;
	Descent = -ymin / ratio / 64.0;
	return { width, Ascent, Descent };
}


int main()
{
	auto tuple = GetTextWidth("simsun.ttc", 10, "中国前进");
    std::cout << tuple.get<0> << std::endl;
    std::cout << tuple.get<2> << std::endl;
}

输出

57.5
0.984375
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值