1. 程式人生 > >數碼相框_在PC機上測試freetype(4)

數碼相框_在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,在linux4bytes.

寬字元: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