FreeType是一款字體服務庫,它支持多種字體,並且提供高效,高質量的文字。
freetype相關介紹見:http://blog.csdn.net/ganxingming/archive/2006/06/05/774796.aspx
1, 編譯FreeType 解壓后進入./include/freetype,復制config到當前文件夾,隨便去個什么名,這里我用custom_config
然后進入 ./builds/win32/visualc 這里是vs工程,因為FreeType的支持相當廣泛,有很多我們不需要東西,因此需要重新編譯FreeType。 而剛才我們復制的文件夾中,就是FreeType的可定制文件
打開工程后,將你剛才復制的文件夾加入到工程中,即custom_config 然后打開ft2build.h 可以看到這里包含了一個文件, #include <freetype/config/ftheader.h> 這個文件就是用於定制FreeType的主要文件,我們要做的就是創建自己的定制文件,將其替代這個文件,將其改成 #include <freetype/custom_config/ftheader.h> custom_config是你自己的文件夾哈
然后進入custom_config/ftheader.h 修改這幾行 #define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h> #define FT_CONFIG_STANDARD_LIBRARY_H <freetype/config/ftstdlib.h> #define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h> #define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h> 改成 #define FT_CONFIG_CONFIG_H <freetype/custom_config/ftconfig.h> #define FT_CONFIG_STANDARD_LIBRARY_H <freetype/custom_config/ftstdlib.h> #define FT_CONFIG_OPTIONS_H <freetype/custom_config/ftoption.h> #define FT_CONFIG_MODULES_H <freetype/custom_config/ftmodule.h>
接着進入custom_config/ftmodule.h 這個文件是FreeType的模塊注冊,我把它改成了 /*FT_USE_MODULE(autofit_module_class)*/ FT_USE_MODULE(tt_driver_class) /*FT_USE_MODULE(t1_driver_class)*/ /*FT_USE_MODULE(cff_driver_class)*/ /*FT_USE_MODULE(t1cid_driver_class)*/ /*FT_USE_MODULE(pfr_driver_class)*/ /*FT_USE_MODULE(t42_driver_class)*/ /*FT_USE_MODULE(winfnt_driver_class)*/ /*FT_USE_MODULE(pcf_driver_class)*/ /*FT_USE_MODULE(psaux_module_class)*/ /*FT_USE_MODULE(psnames_module_class)*/ /*FT_USE_MODULE(pshinter_module_class)*/ /*FT_USE_MODULE(ft_raster1_renderer_class)*/ FT_USE_MODULE(sfnt_module_class) FT_USE_MODULE(ft_smooth_renderer_class) /*FT_USE_MODULE(ft_smooth_lcd_renderer_class)*/ /*FT_USE_MODULE(ft_smooth_lcdv_renderer_class)*/ /*FT_USE_MODULE(bdf_driver_class)*/ 只留下了3個模塊
好,現在FreeType定制完畢了,但是還有個問題,FreeType是編譯的靜態鏈接庫,我們一般是使用動態鏈接庫的, 因此需要將其修改成動態鏈接庫。
進入custom_config/ftconfig.h,將 #ifndef FT_EXPORT
#ifdef __cplusplus #define FT_EXPORT( x ) extern "C" x #else #define FT_EXPORT( x ) extern x #endif
改成
#ifdef DLL_EXPORT #undef DLL_EXPORT #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif /* !DLL_EXPORT */
#ifndef FT_EXPORT
#ifdef __cplusplus #define FT_EXPORT( x ) extern "C" DLL_EXPORT x #else #define FT_EXPORT( x ) extern DLL_EXPORT x #endif
接下來修改工程,進入工程屬性的Release Multithreaded配置,我們編譯多線程版本哈 進入常規,修改配置類型為動態庫 進入C/C++ -> 預處理器,在預處理器定義中加入DLL_EXPORT
好了,現在我們可以開始編譯了。編譯成功后的目錄在objs/release_mt,現在可以拷貝 freetype.dll,freetype.lib和整個include文件夾,到我們的工程中了
2, 使用FreeType 這里就請大家參考帖子 http://www.unixresources.net/lin ... 0/59/21/592188.html 里面有詳細的介紹。
下面,我說一下自己使用FreeType的心得 1, 得到字符的正確繪制位置
首先在創建好FTFace,Freetype推薦使用基線作為繪制基准,但是通常都是設置字符左上角的位置開始繪制。需要獲
得基線到字符輪廓最高點的距離,這個信息放在
Ascender = FTFace->size->metrics.ascender >> 6; // 基線到字符輪廓最高點的距離, 由於是26.6的定點數,
因此獲取整數部分需要除以64
然后每個字符的高度是不同的,Freetype生成的bitmap一般剛剛好包圍到字符,比如a和l的bitmap圖高度是不同的。
因此還需要獲得每個字符的偏移寬度和高度,這兩個信息放在
bitmap_left = FTFace->glyph->bitmap_left; // 字符距離左邊界的距離 bitmap_top = FTFace->glyph->bitmap_top; // 字符最高點距離基線的距離
好了,現在假設要在(posx, posy)處繪制字符,(charposx, charposy)表示字符的正確繪制位置
charposx = posx + bitmap_left; charposy = posy + Ascender - bitmap_top;
2,行距 字符輪廓最大高度放在 FTFace->size->metrics.height // 字符輪廓最大高度, 26.6定點數 但是我實測發現,這個高度太高了點,所以我一般是這樣用的
Descender = FTFace->size->metrics.descender >> 6; // // 基線到字符輪廓最低點的距離 FontHeight = ((FTFace->size->metrics.height >> 6) + Ascender + Descender) / 2;
然后還可以在FontHeight上加上一個固定高度,比如1或2
3,字符顏色 Freetype生成的圖是8bit灰度圖(也有別的,不過8bit好看些),文字部分為白色,背景為黑色。 這就有個麻煩,一般字體都是黑的,那好如果把字體顏色取反,就黑的變白的,白的變黑的了。 可是呢,要加上顏色怎么辦?這就是Freetype的文字是白色的原因,因為是8bit灰度圖,因此不是黑色或白色的地方
,顏色就成了一個比例因子,只需將其與想要設置的顏色相乘再除以256即可,比如灰度圖中某點的顏色是156,想要
設置的顏色是RGB(127, 42, 186),那么實際的顏色是
(127 * 156 >> 8, 42 * 156 >> 8, 186 * 156 >> 8)
回到之前說的,如果將黑的變白的,白的變黑的,那么比例因子就要再取反一次,麻煩了。 而且,如果字體被設置過顏色后,灰度圖的比例因子效果就喪失了,不能再被設置成其他顏色了(重新獲取灰度圖就要
花多余的時間了)。 解決方法是,把8bit灰度圖保存在alpha通道中。如果想設置顏色就從alpha通道中獲取灰度值即可。
4,把字符變的好看些 上面把灰度圖保存在alpha通道中了,如果你的驅動支持alpha混合,那么恭喜你了,字符能和背景混合。 不錯,灰度圖還兼有alpha功能,如果想好看些就做alpha混合吧。 我的驅動不支持alpha混合,只好自己混合了。
源自 http://hi.baidu.com/yq_sun2008/blog/item/cbc18bfb5a52c71e6c22eb04.html
文字的顯示依賴於字體字庫,大致的字體字庫分為點陣字庫、筆畫字庫和輪廓字庫。
點陣字庫:缺點比較明顯,縮放存在鋸齒,渲染旋轉等操作相對復雜,且效果不理想,先大多用在嵌入式行業(基本拋棄),常見格式有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中添加頭文件聲明
1 |
#include <ft2build.h> |
2 |
#include FT_FREETYPE_H |
在view.h中添加成員變量
1 |
public : |
2 |
FT_Library library; |
3 |
FT_Face face; |
在view.cpp的構造函數中添加
01 |
// 初始化庫 |
02 |
bool bError = FT_Init_FreeType(&library); |
03 |
if (!bError) |
04 |
{ |
05 |
// 是否初始化成功 |
06 |
} |
07 |
// 加載一個字庫文件,這里為黑體中文字庫 |
08 |
bError = FT_New_Face(library, |
09 |
"C://WINDOWS//Fonts//simhei.ttf" , |
10 |
0, &face); |
11 |
if (bError == FT_Err_Unknown_File_Format) |
12 |
{ |
13 |
// 表示可以打開和讀此文件,但不支持此字體格式 |
14 |
} |
15 |
else if (bError) |
16 |
{ |
17 |
// 其他錯誤 |
18 |
} |
19 |
// 設定為UNICODE,默認也是 |
20 |
FT_Select_Charmap(face,FT_ENCODING_UNICODE); |
21 |
// 設定字體字符寬高和分辨率 |
22 |
bError = FT_Set_Char_Size(face, 0, 16*64, 300, 300); |
在::OnDraw(CDC* pDC)中添加代碼
01 |
bool bError; |
02 |
wchar_t wChar= _T( '博' ); |
03 |
// 查找‘好’的字符索引 |
04 |
FT_UInt glyph_index = FT_Get_Char_Index(face, wChar); |
05 |
// 裝載字型圖像到字形槽 |
06 |
bError = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); |
07 |
08 |
09 |
// 轉換為位圖數據 |
10 |
if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) |
11 |
{ |
12 |
// 第二個參數為渲染模式,這里渲染為1位位圖(黑白位圖),若為FT_RENDER_MODE_NORMAL則渲染為256級灰度圖 |
13 |
bError = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); |
14 |
} |
這里便可以通過face->glyph->bitmap獲得字體“博”的位圖數據了,bitmap中存放了如位圖的寬高、色深,調色板等信息,便可以通過GDI+繪制該圖像了
01 |
//創建位位圖 |
02 |
BITMAPINFO bmpinfo = {0}; |
03 |
// 初始化位圖結構體 |
04 |
bmpinfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); |
05 |
bmpinfo.bmiHeader.biWidth = face->glyph->bitmap.width; |
06 |
bmpinfo.bmiHeader.biHeight = face->glyph->bitmap.rows; |
07 |
bmpinfo.bmiHeader.biBitCount = 1; // 與渲染模式有關,詳見FreeType API手冊的FT_Bitmap部分說明 |
08 |
bmpinfo.bmiHeader.biClrImportant = 0; |
09 |
bmpinfo.bmiHeader.biClrUsed = 0; |
10 |
bmpinfo.bmiHeader.biCompression = BI_RGB; |
11 |
bmpinfo.bmiHeader.biPlanes = 1; |
12 |
bmpinfo.bmiHeader.biSizeImage = 0; |
13 |
14 |
15 |
// 創建內存位圖 |
16 |
unsigned char *pvBits = new unsigned char [10000]; |
17 |
HBITMAP hBitmap =CreateDIBSection(NULL, &bmpinfo, DIB_RGB_COLORS, ( void ** )&pvBits, NULL, 0 ); |
18 |
19 |
int iLineBytes = (bmpinfo.bmiHeader.biWidth + 7) / 8; |
20 |
for ( int i = 0; i != bmpinfo.bmiHeader.biHeight; ++i) |
21 |
{ |
22 |
memcpy (pvBits + i * iLineBytes, face->glyph->bitmap.buffer + i * iLineBytes, iLineBytes); |
23 |
} |
24 |
25 |
Bitmap *pBitmap = Bitmap::FromHBITMAP(hBitmap, NULL); |
26 |
Graphics graphic(pDC->m_hDC); |
27 |
graphic.DrawImage(pBitmap, Point(20, 150)); |
這部分代碼不多解釋,只是顯示位圖數據,這里face->glyph->bitmap是沒有調色板的1位位圖,源於使用FT_RENDER_MODE_MONO渲染模式
顯示預覽