數碼相框_在PC機上測試freetype(4)
數碼相框_在PC機上測試freetype(4)
如何來使用freetype
1)包含標頭檔案
#include <ft2build.h>
#include FT_FREETYPE_H
2)初始化庫
使用FT_Init_FreeType()函式初始化一個FT_Library型別的變數,例如:
FT_LIBRARY library; //庫的控制代碼 error = FT_Init_FreeType( &library ); if ( error ) { //初始化失敗 } ... ...
3)載入face物件:
通過FT_NEW_Face()開啟一個字型檔案,然後提取該檔案的一個FT_Face型別的face變數,
例如:
FT_LIBRARY library; //庫的控制代碼 FT_Face face; /* face物件的控制代碼 */ error = FT_Init_FreeType ( &library ); if ( error ) {... ...} ... ... error = FT_New_Face( library, "/usr/share/fonts/truetype/arial.ttf", //字形檔案 0, &face );
4)設定字型大小(參考freetype-2.4.10/docs/reference/ft2-base_interface.html):
方法1:
FT_Set_Char_Size( FT_Face face, FT_F26Dot6 char_width, //字元寬度,單位為1/64點 FT_F26Dot6 char_height, //字元高度,單位為1/64點 FT_UInt horz_resolution, //水平解析度 FT_UInt vert_resolution ); //垂直解析度
字元寬度和高度以1/64點為單位表示。點是物理上的距離,一個點代表1/72英寸(2.54cm)
解析度以dpi(dots per inch)為單位表示,表示一個英寸有多少個畫素
例如:
error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 ); //0表示與另一個尺寸值相等。
得出:
字元物理大小為: 50*64* (1/64) * (1/72)英寸
字元的畫素為: 50*64* (1/64) * (1/72)*100
方法2:
FT_Set_Pixel_Sizes( FT_Face face,
FT_UInt pixel_width, //畫素寬度
FT_UInt pixel_height ); //畫素高低
例如:
error = FT_Set_Pixel_Sizes( face, 0,16); //把字元畫素設定為16*16畫素, 0表示與另一個尺寸值相等。
5)設定字型位置,以及旋轉度數(不設定的話表示原點位於0,0):
error = FT_Set_Transform(
face, /* 目標face物件 */
&matrix, /* 指向2x2矩陣的指標,寫0表示不旋轉,使用正矩形 */
&delta ); /*字型座標位置(用的笛卡爾座標),以1/64畫素為單位表示,寫0表示原點是(0,0) */
由於我們LCD的座標原點是位於左上方
笛卡爾座標:表示座標原點位於左下方(與LCD的y軸相反)
所以轉換之前填寫座標時,需要轉換一下y軸值(總高度-y)
轉換成功後還需要轉換回來(總高度-y)
比如,旋轉25,並在(300,200)處顯示:
FT_Vector pen; /* */
FT_Matrix matrix; /* transformation matrix */
angle = ( 25.0 / 360 ) * 3.14159 * 2; /* use 25 degrees */
/*將該文字座標轉為笛卡爾座標*/
pen.x = 300 * 64;
pen.y = ( target_height - 200 ) * 64; // target_height: LCD總高度
//設定 矩形引數
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
FT_Set_Transform( face, &matrix, &pen );
6)載入字形影象
a.獲取編碼的索引
通過FT_Get_Char_Inde()函式將字元編碼轉換為一個字形(glyph)索引 (Freetype預設是utf-16編碼型別)
例如:
glyph_index = FT_Get_Char_Index( face, charcode );
若glyph_index為NULL,表示沒找到字形(glyph)索引
如果使用其它字元編碼,則通過FT_Select_Charmap()來獲取,例如獲取big5編碼:
error = FT_Select_Charmap(
face, /* 目標face物件 */
FT_ENCODING_BIG5 ); /* big5編碼 */
//FT_ENCODING_BIG5列舉定義在FT_FREETYPE_H中
//FT_ENCODING_GB2312 :GB2312編碼
//該函式標頭檔案位於:FT_FREETYPE_H (freetype/freetype.h).
b.通過索引,從face中載入字形
獲得字形索引後,接下來便根據字形索引,來將字形影象儲存到字形槽(glyph slot)中.
字形槽:每次只能儲存一個字形影象,每個face物件都有一個字形槽,位於face->glyph
通過FT_Load_Glyph()來載入一個字形影象到字形槽:
error = FT_Load_Glyph(
face, /* face物件的控制代碼 */
glyph_index, /* 字形索引 */
load_flags ); /* 裝載標誌,一般填FT_LOAD_DEFAULT*/
並更新face->glyph下的其它成員,比如:
FT_Int bitmap_left; //該字形影象的最左邊的X值
FT_Int bitmap_top; //該字形影象的最上邊的Y值
c.轉為點陣圖
通過FT_Render_Glyph()函式,將字形槽的字形影象轉為點陣圖,並存到 face->glyph->bitmap->buffer[]裡
error = FT_Render_Glyph( face->glyph, /* 字形槽 */
render_mode ); /* 渲染模式 */
render_mode標誌可以設為以下幾種:
FT_RENDER_MODE_NORMAL:表示生成點陣圖每個畫素是RGB888的
FT_RENDER_MODE_MONO :表示生成點陣圖每個畫素是1位的(黑白圖)
並更新face->glyph->bitmap下的其它成員,比如:
int rows; //該點陣圖總高度,有多少行
int width; //該點陣圖總寬度,有多少列畫素點
int pitch: //指一行的資料跨度(位元組數),比如對於24位(3位元組)的24*30漢字,則pitch=24*3
char pixel_mode //畫素模式,1 指單色的,8 表示反走樣灰度值
unsigned char* buffer //glyph 的點陣點陣圖記憶體綬衝區
d.也可以直接使用FT_Load_Char()來代替FT_Get_Char_Index()、FT_Get_Load_Glyph()和FT_Render_Glyph().
例如:
error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );
其中FT_LOAD_RENDER:表示直接將影象轉為點陣圖,所以不需要使用FT_Render_Glyph()函式
該函式預設生成的點陣圖是預設生成的FT_RENDER_MODE_NORMAL型別,RGB888的
若想生成FT_RENDER_MODE_MONO(黑白圖)型別,操作如下:
error = FT_Load_Char( face, charcode, FT_LOAD_RENDER | FT_LOAD_MONOCHROME );
生成出來的點陣圖畫素,每8個畫素點便表示 face->glyph->bitmap->buffer[]裡的一個位元組.
參考example1.c例程
example1.c位於freetype-doc-2.4.10.tar.bz2\freetype-2.4.10\docs\tutorial下
在PC虛擬機器裡編譯例程:example1.c
安裝freetype到/usr/local/裡(拿給PC用)
tar -xjf freetype-2.4.10.tar.bz2
mv freetype-2.4.10 freetype-2.4.10_pc
cd freetype-2.4.10_pc/
./configure //配置
make //編譯
sudo make install //直接將庫安裝到根目錄/usr/local/裡,所以需要加sudo
由於example1.c的列印範圍是640*480,而我們secureCRT沒有那麼大,所以修改example1.c.
將:
#define WIDTH 640
#define HEIGHT 480
改為:
#define WIDTH 80
#define HEIGHT 80
然後將119行處的文字顯示座標:
pen.x = 300 * 64;
pen.y = ( target_height - 200 ) * 64;
改為:
pen.x = 0 * 64; //在座標(0,40)處顯示
pen.y = ( target_height - 40 ) * 64;
編譯執行
gcc -o example1 example1.c
編譯出錯:
通過ls,發現又有這個檔案:
所以通過-I,直接指定標頭檔案目錄:
gcc -o example1 example1.c -I /usr/local/include/freetype2/
編譯再次出錯:
發現這些出錯的都是函式,其中FT開頭的是freetype庫的函式,cos等都是數學庫的函式,
freetype庫的檔名是 libfreetype.so
數學庫的檔名是libm.so
所以編譯時,加上-l,指定庫檔案:
gcc -o example1 example1.c -I /usr/local/include/freetype2/ -lfreetype -lm
執行example1
將C:\Windows\Fonts下的simsun.ttc(宋體)字型檔案拷到虛擬機器裡,輸入./example1 simsun.ttc agf,發現是斜的:
這是因為example1.c裡通過FT_Set_Transform()設定了字型旋轉
繼續修改example1.c
關閉字型旋轉,將
FT_Set_Transform( face, &matrix, &pen );
改為
FT_Set_Transform( face, 0, &pen );
修改字型大小,將
error = FT_Set_Char_Size( face, 50 * 64, 0, 100, 0 );
改為:
error = FT_Set_Pixel_Sizes( face, 24, 0 ); //24*24畫素
編譯執行:
顯示漢字
如果用char儲存漢字英文等,則還需要判斷資料型別,而wchar_t剛好可以放一個unicode字元。
注意:wchar_t在windows佔2byte,在linux佔4bytes.
寬字元:wchar_t
標頭檔案: #include<wchar.h>
通過wcslen()判斷wchar_t陣列大小
修改example1.c
...
#include<wchar.h> //新增此行
...
int main( int argc,char** argv )
{
... ...
wchar_t *chinese_str=L"韋東山g"; //新增此行
... ...
for ( n = 0; n <wcslen(chinese_str); n++ ) //修改此行
{
FT_Set_Transform( face, 0, &pen ); //字型轉換
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER ); //修改此行
... ...
}
return 0;
}
通過另存為檔案,來看看檔案本身是什麼編碼格式
如下圖所示,看到是ANSI編碼, 對於中文PC,ANSI編碼對應的是GBK編碼:
linux預設是utf-8編碼,所以編譯時,需要指定字符集:
gcc -o example1 example1.c -I /usr/local/include/freetype2/ -lfreetype -lm -finput-charset=GBK -fexec-charset=utf-8
// -finput-charset:告訴編譯器,檔案裡的字元是GBK格式
//-fexec-charset:告訴編譯器,需要先將裡面的內容轉換為utf-8格式後,再來編譯
執行程式碼:
新增座標列印資訊:
發現,我們列印座標是在(40,0),為什麼文字座標還會超過原點?,參考以下圖所示:
advance: 位於face->glyph-> advance,用來存放每個文字之間的間隔資訊,每當載入一個新的影象時,系統便會更新該資料.
獲取點陣圖文字的資訊
當我們每次將新的字形影象(face->glyph)轉為點陣圖後,而存放的前一個字形影象就會被刪除.
當有時候,有可能需要提取字形影象的座標,該怎麼做?
1)首先新增標頭檔案:
#include FT_GLYPH_H
2)通過FT_Get_Glyph()將一個字形影象(face->glyph)存到FT_Glyph型別的變數裡,例如:
FT_Glyph glyph; /* a handle to the glyph image */
...
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NORMAL );
//通過字元編碼,獲取字形影象存到face->glyph裡,並轉為點陣圖存到face->glyph->bitmap->buffer[]裡
if ( error ) { ... }
error = FT_Get_Glyph( face->glyph, &glyph ); //將字形影象(face->glyph)存到glyph裡
if ( error ) { ... }
3) 通過FT_Glyph_Get_CBox()獲取文字的xMin, xMax, yMin, yMax座標資訊
參考: /freetype-2.4.10/docs/reference/ft2-index.html
FT_Glyph_Get_CBox( FT_Glyph glyph, //該值通過FT_Get_Glyph()來獲取
FT_UInt bbox_mode, //模式,填入FT_GLYPH_BBOX_TRUNCATE即可
FT_BBox *acbox ); //用來存放獲取到的xMin, xMax, yMin, yMax資訊
其中FT_GLYPH_BBOX_TRUNCATE表示:獲取的座標資訊是畫素座標,而不是點座標
修改example1.c,使它能列印每個漢字的座標資訊:
#include FT_GLYPH_H //新增此行
... ...
int main( int argc, char** argv )
{
FT_Glyph glyph;
FT_BBox acbox;
... ...
for ( n = 0; n < wcslen(chinese_str); n++ )
{
... ...
error = FT_Load_Char( face,chinese_str[n], FT_LOAD_RENDER );
if ( error )
continue; /* ignore errors */
error = FT_Get_Glyph( face->glyph, &glyph ); //新增此行
FT_Glyph_Get_CBox( glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox ); //新增此行
printf("0x%x:xMin=%ld,xMax=%ld,yMin=%ld,yMax=%ld\n",chinese_str[n],acbox.xMin,acbox.xMax,acbox.yMin,acbox.yMax); //新增此行
... ...
編譯執行:
表示韋字(97e6)的笛卡爾座標 : X座標在0~23,y座標在37~60,是個24*24字型.
由於笛卡爾座標的原點座標位於左下方.
所以對應韋字(97e6)的LCD座標: X座標在0~23 ,y座標為20~43