1. 程式人生 > >數碼相框(二)freetype庫實現向量顯示

數碼相框(二)freetype庫實現向量顯示

一、向量字型原理

將漢字的筆劃邊緣用直線段描述成封閉的曲線,並將線段各端點的座標經壓縮儲存,如下圖所示:

由於每個漢字的比劃不一樣,從而每個漢字資料長度也不同,所以只能採用索引的方法。因而每種向量字型檔都是由兩部分組成,一部分是漢字的字形(glyph)資料。當顯示文字時,便提取出各端點,並通過貝塞爾曲線來連線各個座標,最後填充封閉空間。

接下來使用freetype庫製作向量字型

二、安裝freetype-2.4.10庫

freetype庫是一個開源的字型引擎,支援多種字符集編碼(utf-8等)

2.1 如何使用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)設定字型大小

方法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[]裡的一個位元組。

三、PC虛擬機器裡程式設計例程:example1.c

/* example1.c                                                      */
/*                                                                 */
/* This small program shows how to print a rotated string with the */
/* FreeType 2 library.                                             */


#include <stdio.h>
#include <string.h>
#include <math.h>

#include <ft2build.h>
#include FT_FREETYPE_H


#define WIDTH   80
#define HEIGHT  80


/* origin is the upper left corner */
unsigned char image[HEIGHT][WIDTH];


/* Replace this function with something useful. */

void
draw_bitmap( FT_Bitmap*  bitmap,
             FT_Int      x,
             FT_Int      y)
{
  FT_Int  i, j, p, q;
  FT_Int  x_max = x + bitmap->width;
  FT_Int  y_max = y + bitmap->rows;


  for ( i = x, p = 0; i < x_max; i++, p++ )
  {
    for ( j = y, q = 0; j < y_max; j++, q++ )
    {
      if ( i < 0      || j < 0       ||
           i >= WIDTH || j >= HEIGHT )
        continue;

      image[j][i] |= bitmap->buffer[q * bitmap->width + p];
    }
  }
}


void
show_image( void )
{
  int  i, j;


  for ( i = 0; i < HEIGHT; i++ )
  {
    for ( j = 0; j < WIDTH; j++ )
      putchar( image[i][j] == 0 ? ' '
                                : image[i][j] < 128 ? '+'
                                                    : '*' );
    putchar( '\n' );
  }
}


int
main( int     argc,
      char**  argv )
{
  FT_Library    library;
  FT_Face       face;

  FT_GlyphSlot  slot;
  FT_Matrix     matrix;                 /* transformation matrix */
  FT_Vector     pen;                    /* untransformed origin  */
  FT_Error      error;

  char*         filename;
  char*         text;

  double        angle;
  int           target_height;
  int           n, num_chars;


  if ( argc != 3 )
  {
    fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );
    exit( 1 );
  }

  filename      = argv[1];                           /* first argument     */
  text          = argv[2];                           /* second argument    */
  num_chars     = strlen( text );
  angle         = ( 0.0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */
  target_height = HEIGHT;

  error = FT_Init_FreeType( &library );              /* initialize library */
  /* error handling omitted */

  error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
  /* error handling omitted */

#if 0
  /* use 50pt at 100dpi */
  error = FT_Set_Char_Size( face, 50 * 64, 0,
                            100, 0 );                /* set character size */

	/* pixels = 50 /72 * 100 = 69  */
#else
	FT_Set_Pixel_Sizes(face, 24, 0);
#endif
  /* error handling omitted */

  slot = face->glyph;

  /* set up matrix */
  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 );

  /* the pen position in 26.6 cartesian space coordinates; */
  /* start at (0,40) relative to the upper left corner  */
  pen.x = 0 * 64;
  pen.y = ( target_height - 40 ) * 64;

  for ( n = 0; n < num_chars; n++ )
  {
    /* set transformation */
    FT_Set_Transform( face, &matrix, &pen );

    /* load glyph image into the slot (erase previous one) */
    error = FT_Load_Char( face, text[n], FT_LOAD_RENDER );
    if ( error )
      continue;                 /* ignore errors */

    /* now, draw to our target surface (convert position) */
    draw_bitmap( &slot->bitmap,
                 slot->bitmap_left,
                 target_height - slot->bitmap_top );

    /* increment pen position */
    pen.x += slot->advance.x;
    pen.y += slot->advance.y;
  }

  show_image();

  FT_Done_Face    ( face );
  FT_Done_FreeType( library );

  return 0;
}

/* EOF */

3.1 安裝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 --host=arm-linux --prefix=/root/code/Project/數碼相框/freetype-2.4.10/freetype(自定義目錄) //配置
make                                        //編譯
make install                           //直接將庫安裝到根目錄/usr/local/裡,所以需要加

由於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;
pen.y = ( target_height - 40 ) * 64;

3.2 編譯執行

gcc -o example1 example1.c

所以通過-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

3.3 執行example1

將C:\Windows\Fonts下的simsun.ttc(宋體)字型檔案拷到虛擬機器裡,輸入./example1   simsun.ttc  agf,發現是斜的:

這是因為example1.c裡通過FT_Set_Transform()設定了字型旋轉

3.4 修改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畫素

編譯執行:

3.5 顯示漢字

如果用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,用來存放每個文字之間的間隔資訊,每當載入一個新的影象時,系統便會更新該資料。

3.6 獲取點陣圖文字的資訊

當我們每次將新的字形影象(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

四、在LCD上顯示向量文字

安裝freetype到交叉編譯目錄裡(供arm-linux-gcc編譯)

4.1首先檢視,需要安裝到哪個lib和include目錄

1)通過$PATH找到arm-linu-gcc交叉編譯位於:/work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/bin然後進入.../arm/4.3.2/目錄,通過find查詢stdio.h檔案,找到:

 

所以編譯出來的標頭檔案應該放入:/work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

2)通過find查詢lib,找到:

 

由於ARM9屬於ARMv4T架構,所以編譯出來的庫檔案應該放入:/work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

4.2 安裝

參考:freetype-2.4.10/docs/INSTALL.CROSS

tar -xjf freetype-2.4.10.tar.bz2   
mv freetype-2.4.10 freetype-2.4.10_arm
cd freetype-2.4.10_arm
mkdir   tmp                                    //建立安裝的臨時目錄,後面會拷貝到交叉編譯目錄裡
./configure --host=arm-linux  --prefix=$PWD/tmp  //配置交叉編譯,安裝字首
make
make install
 
cd tmp/

cp  ./include/*  /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include/ -rfd 
  //將include下的標頭檔案拷貝到交叉編譯裡去

cp lib/*  /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/  -rfd 
 //將lib下的庫檔案拷貝到交叉編譯裡去

cp lib/ * /work/nfs_root/3.4_fs_mini_mdev/lib/  -rfd    
//將lib下的庫檔案拷貝到nfs檔案系統去

4.3 寫程式碼(參考上章程式碼和example1.c)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <math.h>
#include<wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

unsigned char *fbmem;
unsigned char *hzkmem;

struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix;

unsigned int screensize;
#define FONTDATAMAX 4096

static const unsigned char fontdata_8x16[FONTDATAMAX] = {
//ASCII碼點陣太長,省略...
};

/*rgb565*/
void pixel_show(int x,int y, unsigned int color)
{
       unsigned int red,green,blue;
       switch(fb_var.bits_per_pixel)        //rgb   畫素
        {
            case 32:
            {
                unsigned int  *addr=(unsigned int  *)fbmem+(fb_var.xres*y+x);
                *addr=color;   
                 break;
            }
            case 24:
           {
                unsigned int  *addr=(unsigned int  *)fbmem+(fb_var.xres*y+x);
                *addr=color;
                 break;
           }
           case 16:            //將RGB888 轉為RGB565
           {
                unsigned short  *addr=(unsigned short  *)fbmem+(fb_var.xres*y+x);
                red   = (color >> 16) & 0xff;
                green = (color >> 8) & 0xff;
                blue  = (color >> 0) & 0xff;
                color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
                *addr = color;
                break;
           }
           case 8:
          {
               unsigned char  *addr=(unsigned char  *)fbmem+(fb_var.xres*y+x);
               *addr = (unsigned char)color;
               break;
          }

          default:
         {
            printf("can't  surport %dbpp \n",fb_var.bits_per_pixel);
            break;
         }
       }
}

/*顯示ascii碼*/
void lcd_put_char(int x,int y, unsigned char  s)
{
     unsigned char  *index=(unsigned char *)&fontdata_8x16[s*16];
     unsigned char i,j;
      for(i=0;i<16;i++)          //8*16
      for(j=0;j<8;j++)           
    {
           //從高位到低
         if(index[i]&(1<<(7-j)))         //亮
                pixel_show(x+j,y+i, 0xffffff);        //白色
        else             //滅
                pixel_show(x+j,y+i, 0x0);          //黑色       
    }
}
 
/*顯示GBK碼*/
void lcd_put_chinese(int x,int y, unsigned char  *s)
{
    unsigned char i,j,k;  
    //將編碼轉為區碼
    unsigned int   index=(s[0]-0xA1)*94+(s[1]-0xA1);

    //轉為點陣碼(每個漢字32位元組)
    unsigned char  *dots=hzkmem+index*32;

     for(i=0;i<16;i++)          //16*16
     for(k=0;k<2;k++)
     for(j=0;j<8;j++)
    {
          if((dots[i*2+k]>>(7-j))&0X01)         //亮
               pixel_show(x+8*k+j,y+i, 0xffffff);        //白色

          else             //滅
                pixel_show(x+8*k+j,y+i, 0x0);          //黑色   
       }
}

void lcd_put(int x,int y, unsigned char  *s)
{
    while(*s)
   {
        if(*s<0xA1)         //ASCII碼8*16
        {
           printf("ASCII %x  \r\n",*s  );
            lcd_put_char(x,y,*s);
            s+=1;
            x+=8;       
        }
        else                  //GB2313   16*16
        {
           printf("GBK %x %x\r\n",*s, *(s+1));
           lcd_put_chinese(x,y,s);       
           s+=2;
           x+=16; 
        }
   }
}

void draw_bitmap( FT_Bitmap*  bitmap,
             FT_Int      x,
             FT_Int      y)
{
  FT_Int  i, j, p, q;  
  FT_Int  x_max = x + bitmap->width;        //x:當前X位置, bitmap->width:該字寬度
  FT_Int  y_max = y + bitmap->rows;

  for ( i = x, p = 0; i < x_max; i++, p++ )   //i:lcd的x軸
  {
    for ( j = y, q = 0; j < y_max; j++, q++ )  //j:lcd的y軸
    {
      if ( i < 0      || j < 0       ||
           i >= fb_var.xres || j >= fb_var.yres )
        continue;
        pixel_show( i, j,  bitmap->buffer[q * bitmap->width + p]);
    }
  }
}

void lcd_vector_show(char *argv,wchar_t  *str)
{
    FT_Library    library;
    FT_Face       face;
    FT_GlyphSlot  slot;
    FT_Vector     pen;                    /* untransformed origin  */
    unsigned char error;
    unsigned char  n,font_size;

    error = FT_Init_FreeType( &library );              /* initialize library */
      if(error)
       {
            printf("FT_Init_FreeType ERROR\n");
            return ;
        }

     error = FT_New_Face( library, argv, 0, &face ); /* create face object */
     if(error)
        {
            printf("FT_New_Face ERROR\n");
            return ;
        }

     slot = face->glyph;

     /*顯示座標(從LCD中間顯示)
      *x=fb_var.xres /2
      *y=fb_var.yres-fb_var.yres/2-16   (減16,是因為笛卡爾座標以左下方開始計算座標值的)
      */
     pen.x = fb_var.xres /2* 64;
     pen.y = ( fb_var.yres/2-16) * 64;  

     for ( n = 0; n < wcslen(str); n++ )
  {
    font_size=(n%6)*4+20;            // 20*20  24*24  28*28  32*32  36*36 40*40  

    error = FT_Set_Pixel_Sizes( face, 0,font_size);     /* set character size */

    FT_Set_Transform( face, 0, &pen );

    error = FT_Load_Char( face,str[n], FT_LOAD_RENDER );
      if ( error )
         {
         printf("FT_Load_Char ERROR\n"); 
         continue; 
        }

        draw_bitmap( &slot->bitmap,
                 slot->bitmap_left,
                 fb_var.yres- slot->bitmap_top );

    pen.x += slot->advance.x;
    pen.y += slot->advance.y;
   }
    FT_Done_Face( face );
     FT_Done_FreeType( library );
}

int main(int argc,char **argv)
{
    int fd_fb,fd_hzk;
    struct stat  hzk_start;             //HZK16檔案資訊

    unsigned char  s[]="abc 中國chinese";
    wchar_t  *chinese_str=L"韋東山g h ";

    if ( argc != 2 )
    {
      printf ("usage: %s  font_file \n", argv[0] );
      return 0;
    }

    fd_hzk=open("HZK16",O_RDONLY);
    if(fd_hzk<0)
    {
        printf("can't open HZK16 \n");
        return 0;
    }

    if(fstat(fd_hzk,&hzk_start)<0)         //獲取HZK16檔案資訊
    {
        printf("can't get fstart \n");
        return 0;
    }

    hzkmem =(unsigned char *)mmap(NULL,hzk_start.st_size, PROT_READ,MAP_SHARED,
                  fd_hzk, 0);                       //對映HZK16檔案
    if(!hzkmem)
    {
        printf("can't map HZK16 \n");
        return 0;
    }
 
    fd_fb=open("/dev/fb0", O_RDWR);
    if(fd_fb<0)
    {
        printf("can't open /dev/fb0 \n");
        return 0;
     }

    if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&fb_var)<0)
    {
        printf("can't get var \n");
        return 0;
    }

   if(ioctl(fd_fb,FBIOGET_FSCREENINFO,&fb_fix)<0)
    {
        printf("can't get fix \n");
        return 0;
    }

    screensize=fb_var.xres*fb_var.yres*(fb_var.bits_per_pixel/8);       //視訊記憶體大小

    fbmem =(unsigned char *)mmap(NULL,screensize, PROT_READ|PROT_WRITE,MAP_SHARED,
                  fd_fb, 0);                       //對映fb0

    if(!fbmem)
    {
        printf("can't map /dev/fb0 \n");
        return 0;
    }
    memset(fbmem, 0, screensize);            //清屏黑色

    /*顯示資料*/
    lcd_put(0,fb_var.yres/2,s);     

    /*顯示向量文字*/
    lcd_vector_show(argv[1], chinese_str);

    munmap(hzkmem,hzk_start.st_size);
    munmap(fbmem,screensize);
    return 0;
}

4.4 編譯程式

編譯報錯: 56:38: error: freetype/config/ftheader.h: No such file or directory

通過find找到ftheader.h的位置是位於:../include/freetype2/freetype/config/ftheader.h

輸入:

cd ./arm-none-linux-gnueabi/libc/usr/include/freetype2 
mv freetype/ ../freetype //將freetype2下的freetype移到include目錄下

編譯:

arm-linux-gcc -o show_font show_font.c -lfreetype -lm -finput-charset=GBK -fexec-charset=GBK

執行:

 (發現,顯示16*16字型時,會亂碼, 新宋字型simsun不支援16點陣大小的字型)