2019年3月18日 星期一

初探FreeType

初探FreeType

前言

  繪圖API並不支援畫字型的功能,以前使用Direct2D搭配DirectWrite來畫字型,但不幸地現在繪圖引擎要跨平台,Direct2D的方法最多只能在Windows平台使用,FreeType就是我找到的可以跨平台的畫字型方法,這裡把學習心得做個紀錄。

內容

  首先先來說說"建置",FreeType自帶的建置個人覺得實在是不怎麼好用,Windows版的建置是由官方給個Visual studio專案直接開啟後建置即可,但Linux的建置就完全不一樣,是類似透過Shell script的方式來建置,Android則是透過NDK的專案來建置,最後我並沒選擇官方的建置是因為FreeType在下載時是在Windows平台,所以裡面的文字檔的換行是"\r\n",結果當我在Ubuntu建置時都會報錯,也就是說跟建置相關的檔案絕不能在Windows的環境編輯,不然上傳後就沒辦法用了。解決的方案很簡單,就是自己建置,還記得官方有自帶一個Visual studio專案嗎?我依據該專案的建置方案來製作Linux與Android的建置,這方法有風險,但我還是做了,幸運的是Linux與Android的建置與Windows是差不多,差別的地方是Linux與Android版並沒有所謂的"Debug"版,編譯時不用加"FT_DEBUG_LEVEL_ERROR"與"FT_DEBUG_LEVEL_TRACE"編譯,其它的部分和Windows版是一樣的。

  接著來看看如何使用,先看以下範例
#include "ft2build.h"
#include FT_FREETYPE_H

int main()
{
  //...
  //
  FT_Library library;
  FT_Error error=FT_Init_FreeType(&library);
  if(error!=0)
    return 1;
  //
  //...
  //Free
  FT_Done_FreeType(library);

  return 0;
}

這個範例會去製造FT_Library,整個程式應該只要製造一個,在程式要結束時,透過FT_Done_FreeType()來釋放。FT_Library製造完後就可以來讀取font檔,範例如下
#include "ft2build.h"
#include FT_FREETYPE_H

int main()
{
  //...
  //
  FT_Library library;
  FT_Error error=FT_Init_FreeType(&library);
  if(error!=0)
    return 1;
  //Load font file
  FT_Face face;
  error=FT_New_Face(library,"arial.ttf",0,&face);
  //...
  //Free
  FT_Done_Face(face);
  FT_Done_FreeType(library);

  return 0;
}

讀取的方法很簡單,透過FT_New_Face()來讀取,透過FT_Done_Face()來釋放。在Android時,由於Android的Asset不提供Handle,如果要將Font檔放在Asset的話,就要透過FT_New_Memory_Face()來讀取。接下來就來讀取字型的資料,範例如下
#include "ft2build.h"
#include FT_FREETYPE_H

int main()
{
  //...
  //
  FT_Library library;
  FT_Error error=FT_Init_FreeType(&library);
  if(error!=0)
    return 1;
  //Load font file
  FT_Face face;
  error=FT_New_Face(library,"arial.ttf",0,&face);
  //Set font size
  error=FT_Set_Pixel_Sizes(face,0,60);
  //Load glyph
  FT_UInt glyphIndex=FT_Get_Char_Index(face,'a');
  if(glyphIndex==0)
    return 1;
  error=FT_Load_Glyph(face,glyphIndex,FT_LOAD_DEFAULT);
  if(face->glyph->format!=FT_GLYPH_FORMAT_BITMAP)
  {
    error=FT_Render_Glyph(face->glyph,FT_RENDER_MODE_MONO);
    if(error!=0)
      return 1;
  }
  //Get glyph bitmap data from face->glyph->bitmap.buffer
  //...
  //Free
  FT_Done_Face(face);
  FT_Done_FreeType(library);

  return 0;
}

 透過FT_Set_Pixel_Sizes()來設定字型的大小,接著透過Glyph index來寫資料到"buffer"裡,"buffer"在哪呢?透過face->glyph->bitmap.buffer來取得。

  Buffer的資料就是一張圖,整個Buffer的資料的大小為face->glyph->bitmap.pitch*face->glyph->bitmap.rows,"face->glyph->bitmap.rows"就是高,但"face->glyph->bitmap.pitch"並不是寬,每個Pitch指的是把寬度以每8個Pixel存成一個Byte來計算的話會有幾個Byte,如果寬度是60Pixel,Pitch值為8,如果寬度是40Pixel,Pitch值為5,依此類推。

參考資料

FreeType官網
Text Rendering with Direct2D and DirectWrite

沒有留言:

張貼留言