寫在前面:
freeType2.9.1移植到A7(1)
上一篇文章說了freeType移植並編譯通過,但是還沒有調試並顯示字體,今天就講講freeType接口的調用。
在調試過程中發現,freeType在解碼時對RAM的大小是有要求的,否則會堆棧溢出,這裏我們將MCIMX6Y2xxx05_ram.icf文件中的堆空間設置爲0x60000,正好是384K,此條件下,調用freeType接口是沒有問題的。
創建一個字體的結構體,方便gui進行調用,因爲是基於C語言的,爲了方便gui後期能夠打包爲lib庫,這裏使用回調函數的方式來調用字體渲染函數。
typedef struct {
U16 Flags; //取值參考 GUI_TTF_MAP_FILE_MEMERY_MODE
GUI_DISPCHAR * pfDispChar; //繪製字形的函數
GUI_GETCHARDISTX * pfGetCharDistX; //獲取字形所佔的像素個數
GUI_GETFONTINFO * pfGetFontInfo; //獲取字號大小,及字體的顯示方式
union{
const GUI_TTF_DATA *pTtfData;
const GUI_TTF_FONT_MAP *pMap;
}p;
U8 height;
U8 bold;//加粗,0-不加粗
U8 itailc; //斜體
void *matrix;
}GUI_FONT;
上篇文章提到,因爲要支持三種模式來顯示字體,所以需要3個字體的結構體
typedef struct
{
// FONT_TYPE font_type;
U8* ASCII_addr;
U8* HZ_addr;
U8 width;
U8 height;
}GUI_TTF_FONT_MAP;
//ttf矢量字庫文件
typedef struct{
const void * pData;//ttf字體文件地址
U32 NumBytes;//大小
}GUI_TTF_DATA;
typedef struct{
GUI_TTF_DATA *pTTF;
int height;//字體像素高度
int faceIndex;//有些字體文件可能包含多種字體風格。對於多種風格,此索引指定使用基於零的風格索引來創建字體。通常爲 0。
}GUI_TTF_CS;
第一種,預先在PC端,用軟件轉換ttf對應字號的字模數據文件,然後在單片機中使用,初始化函數如下:
int GUI_MAP_CreateFont(GUI_FONT * pFont,GUI_TTF_FONT_MAP *pMap)
{
pFont->Flags = GUI_TTF_MAP_FILE_MEMERY_MODE;
pFont->pfDispChar = (GUI_DISPCHAR*)GUI_X_DispCharMap;
pFont->pfGetCharDistX = (GUI_GETCHARDISTX*)GUI_GetCharDistX;
pFont->height = pMap->height;
pFont->p.pMap = pMap;
return 0;
}
顯示字體函數:
//先用工具生成字體位圖文件,根據字符編碼定位字庫數據
/*
style 獲取背景色顏色
*/
I16 GUI_X_DispCharMap(int x,int y,const GUI_FONT* font,U16 c,U32 color,U32 bk_color,U8 type,U8 style)
{
U32 addrsse = 0;
U8 msb,lsb;
U8 *pData;
U8 fontwidth;
const GUI_TTF_FONT_MAP* pMap =font->p.pMap;
int i,j;
U32 *pIndex;
if(c&0x80){//漢字
lsb = c&0xff;
msb = (c>>8)&0xff;
addrsse = ( ( lsb - 0xA0) * 94 + msb - 0xA1 )*pMap->width*font->height;
pData = (U8*)(pMap->HZ_addr+addrsse);
fontwidth = pMap->width;
}else{//assic
pIndex = (U32*)pMap->ASCII_addr;
addrsse = pIndex[c];
fontwidth = (addrsse>>24)&0xff;
addrsse &= 0x00ffffff;
pData = (U8*)(pMap->ASCII_addr+addrsse);
}
for(i=y;i<pMap->height +y;i++){
for(j = x;j <fontwidth + x;j++){
if(style)
bk_color = INDEX2COLOR_FUNC(GUI_GetPixelIndex(j, i));
GUI_SET_PIXEL(type, i*GUI_Context.xSize+j, setcolor( pData[(i - y)*fontwidth + (j - x)] ,color,bk_color));
// GUI_SET_PIXEL(0, i*GUI_Context.xSize+j, setcolor( pData[(i - y)*fontwidth + (j - x)] ,color,bk_color));
}
}
return fontwidth;
}
第二種,將ttf文件寫入內存,然後調用freeType接口渲染字體。
字體初始化函數:主要負責文件的加載,以及字庫的生成。
I16 GUI_loadFontData(GUI_TTF_DATA *ttfData,U8 *pData,U32 fileSize)
{
FT_Error error = 0;
if(ttfData->pData==NULL)
return 1;
ttfData->pData = pData;
ttfData->NumBytes = fileSize;
error = FT_Init_FreeType(&pFTLib);
error = FT_New_Memory_Face(pFTLib,pData,fileSize,0,&pFTFace);
if(error)
return 1;
return 0;
}
創建字庫函數,根據字號不同,創建不同字號的字體:
int GUI_TTF_CreateFont(GUI_FONT * pFont, GUI_TTF_CS * pCS,GUI_TTF_DATA *ttfData,U8 fontsize)
{
pCS->pTTF = ttfData;
pCS->height = fontsize;
FT_Set_Char_Size(pFTFace, fontsize << 6 , fontsize << 6 , 72 , 72 );
pFont->pfDispChar = (GUI_DISPCHAR *)GUI_X_DispCharTTF;
pFont->pfGetCharDistX = (GUI_GETCHARDISTX*)GUI_GetCharDistX;
pFont->Flags = GUI_TTF_FILE_MEMERY_MODE;
pFont->height = pCS->height;
pFont->itailc = 0;
pFont->matrix = NULL;
pFont->bold = 0;
return 0;
}
最後一種,是基於文件流方式讀取ttf文件,也是我們工程推薦採用的方式,可以節省大量內存資源。
加載文件函數
int GUI_loadFontFile(const char* path)
{
FT_Error error = 0;
error = FT_Init_FreeType(&pFTLib);
error = FT_New_Face(pFTLib,path,0,&pFTFace);
if(error)
return 1;
return 0;
}
創建字體函數
int GUI_TTF_CreateFontStream(GUI_FONT * pFont,U8 fontSize)
{
FT_Set_Char_Size(pFTFace, fontSize << 6 , fontSize << 6 , 72 , 72 );
pFont->Flags = GUI_TTF_FILE_STREAM_MODE;
pFont->pfDispChar = (GUI_DISPCHAR *)GUI_X_DispCharTTF;
pFont->pfGetCharDistX = (GUI_GETCHARDISTX*)GUI_GetCharDistX;
pFont->height = fontSize;
pFont->itailc = 0;
pFont->matrix = NULL;
pFont->bold = 0;
return 0;
}
除了第一種方式外,我們用到了freeType的以下接口:
FT_Init_FreeType //初始化freeType
FT_New_Memory_Face //從內存中加載ttf文件數據生成pFTFace
FT_New_Face//直接加載ttf文件生成pFTFace
FT_Set_Char_Size//設置字體大小
具體使用方式可以參考官方網站的api說明。
渲染的時候,有一個注意的地方,對於漢字,字符編碼參數傳進來是gb2312碼,需要轉換成unicode碼,需要用到db2312轉unicode碼的映射表。文章末尾會附上這個映射表。
使用這個表的關鍵代碼如下:
if(code&0x80){//判斷是否爲漢字編碼
U8 msb = (code>>8)&0xff;
U8 lsb = (code)&0xff;
offset = (lsb-GB_MIN_ZONE)*GB_OFFSET_NUMBER+(msb-GB_MIN_OFFSET);
code = gb2312_to_ucs2_table[offset];
}else{
y+=2;//字符統一在垂直方向向下偏移2個像素
}
而字符編碼是ascii碼是不需要轉換的。
經測試,gui對着三種方式都能很好的支持,同時添加了部分功能的api
將字體加粗;
void GUI_TTF_SetBold(GUI_FONT * pFont,U8 bold)//設置粗體
{
pFont->bold = bold;
}
在渲染的函數中會判斷pFont->bold的值,從而確定是否執行
FT_Outline_Embolden(&pFTFace->glyph->outline,font->bold<<6);
生成斜體:
FT_Outline_Transform(&pFTFace->glyph->outline,(FT_Matrix *)(font->matrix));
這裏需要初始化一個FT_Matrix這樣的結構體變量,FT_Matrix matrix ,並初始化
matrix.xx = 0x10000;
matrix.xy = 0x8000;
matrix.yx = 0;
matrix.yy = 0x10000;
其中xx是xy的倍數關係,這個係數可以自己調節,到目前還是覺得2倍的關係,效果能夠接受。
在移植過程中,參考了不少csdn上各位大神的文章,在此表示感謝,就不在此貼博文鏈接了(找不着鏈接了o(╥﹏╥)o)。
這個是unicode.h文件下載地址