文字的显示依赖于字体字库,大致的字体字库分为点阵字库、笔画字库和轮廓字库。
点阵字库:缺点比较明显,缩放存在锯齿,渲染旋转等操作相对复杂,且效果不理想,先大多用在嵌入式行业(基本抛弃),常见格式有bdf,pcf,fnt,hbf,hzf等。
笔画字体:不讨论。
轮廓字体:即矢量字体,利用字体轮廓及填充实现字体显示,优势明显,渲染缩放较容易,但效率相对低些(相对于嵌入式)
简单来说,freetype为字体字库提供了一套解决方案,支持文字字体渲染等操作,主要还是其为C语言编写,跨平台,为很多不支持矢量字体格式的嵌入式系统提供使用嵌入式字体的可能,且效率不低。
基本流程为:
加载字体字库文件-> 查找待显示的文字索引-> 渲染操作(若反走样处理)->处理为位图数据->显示
freetype官网http://freetype.sourceforge.net/index2.html
下面为在XP下显示中文字体的实例,在官方下载源码,在..\freetype-2.4.2\builds\win32\vc2008\下打开工程,编译为链接库,新建VS2008的MFC程序,加载freetype242.lib库。
简单考虑,直接在MFC中的draw函数中画出一个中文汉字。便于显示,使用GDI+画出汉字,因此首先对GDI+进行初始化等操作(GDI+的相关知识不讨论,不清楚可以留言或索取GDI+文档,网上也可以搜搜)
在view.h中添加头文件声明
#include <ft2build.h> #include FT_FREETYPE_H
在view.h中添加成员变量
public: FT_Library library; FT_Face face;
在view.cpp的构造函数中添加
// 初始化库 bool bError = FT_Init_FreeType(&library); if (!bError) { // 是否初始化成功 } // 加载一个字库文件,这里为黑体中文字库 bError = FT_New_Face(library, "C:\\WINDOWS\\Fonts\\simhei.ttf", 0, &face); if (bError == FT_Err_Unknown_File_Format) { // 表示可以打开和读此文件,但不支持此字体格式 } else if (bError) { // 其他错误 } // 设定为UNICODE,默认也是 FT_Select_Charmap(face,FT_ENCODING_UNICODE); // 设定字体字符宽高和分辨率 bError = FT_Set_Char_Size(face, 0, 16*64, 300, 300);
在::OnDraw(CDC* pDC)中添加代码
bool bError; wchar_t wChar= _T('博'); // 查找‘好’的字符索引 FT_UInt glyph_index = FT_Get_Char_Index(face, wChar); // 装载字型图像到字形槽 bError = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); // 转换为位图数据 if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) { // 第二个参数为渲染模式,这里渲染为1位位图(黑白位图),若为FT_RENDER_MODE_NORMAL则渲染为256级灰度图 bError = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); }
这里便可以通过face->glyph->bitmap获得字体“博”的位图数据了,bitmap中存放了如位图的宽高、色深,调色板等信息,便可以通过GDI+绘制该图像了
//创建位位图 BITMAPINFO bmpinfo = {0}; // 初始化位图结构体 bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.bmiHeader.biWidth = face->glyph->bitmap.width; bmpinfo.bmiHeader.biHeight = face->glyph->bitmap.rows; bmpinfo.bmiHeader.biBitCount = 1;// 与渲染模式有关,详见FreeType API手册的FT_Bitmap部分说明 bmpinfo.bmiHeader.biClrImportant = 0; bmpinfo.bmiHeader.biClrUsed = 0; bmpinfo.bmiHeader.biCompression = BI_RGB; bmpinfo.bmiHeader.biPlanes = 1; bmpinfo.bmiHeader.biSizeImage = 0; // 创建内存位图 unsigned char *pvBits = new unsigned char[10000]; HBITMAP hBitmap =CreateDIBSection(NULL, &bmpinfo, DIB_RGB_COLORS, (void ** )&pvBits, NULL, 0 ); int iLineBytes = (bmpinfo.bmiHeader.biWidth + 7) / 8; for (int i = 0; i != bmpinfo.bmiHeader.biHeight; ++i) { memcpy(pvBits + i * iLineBytes, face->glyph->bitmap.buffer + i * iLineBytes, iLineBytes); } Bitmap *pBitmap = Bitmap::FromHBITMAP(hBitmap, NULL); Graphics graphic(pDC->m_hDC); graphic.DrawImage(pBitmap, Point(20, 150));
这部分代码不多解释,只是显示位图数据,这里face->glyph->bitmap是没有调色板的1位位图,源于使用FT_RENDER_MODE_MONO渲染模式
显示预览
这里字体倒置与位图坐标系有关,只要简单处理即可,不讨论。
简单的描述一下freetype的使用流程,更详细的函数说明及流程请参阅“freetype2开发入门”, 网上有此文档,感兴趣可以看看。