freeType2.9.1移植到A7(2)

上一篇文章说了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文件下载地址

posted @ 2020-03-25 19:45  字由人  阅读(456)  评论(0编辑  收藏  举报