Linux下,利用FreeType2的API实现字符的显示

网上的FreeType2例子太少,能显示汉字的比较难找,C语言代码写的更难找,能找到的,基本上是被转载了N遍的同一个示例代码,基本上解决不了我的问题。

于是乎,花费了不少时间才完成了这些代码。


主要是先解决编码问题,需要用wchar_t类型保存unicode编码的字符,字符串常量倒好弄,例如:wchar_t str[]=L"一段文本"; 编译时编译器就自动帮你转换好,但前提是源码文件的编码要为UTF-8,其它编码,例如ASCII,编译时会报错。

而字符串变量的话,需要程序自己转换,UTF-8转Unicode,代码在这里:

https://github.com/lc-soft/LCUI/blob/master/src/font/charset.c

看utf8_to_unicode函数的代码。


其次是要知道如何获取一个字的位图的相关度量,例如:字形的宽、高、左边界距、上边界距、水平跨距等等。

以前看中译版本的FreeType文档,没看明白,最近看了后,终于知道了如何获取字形的这些度量。


我目前使用的代码在这里:

https://github.com/lc-soft/LCUI/blob/master/src/font/bitmapfont.c 

主要看Convert_FTGlyph函数和Get_FontBMP函数的代码。

Get_FontBMP函数只获取单个字的位图信息,要获取字符串的话,连续调用Get_FontBMP函数并保存得到的字体数据,之后根据字体数据中的信息绘制到目标面上即可。


除了看代码外,建议看FreeType2的文档,网上有中译版本。


文字绘制的效果截图:


主要演示彩色文本的渲染,不同大小字体的绘制,字体使用的是 微软雅黑。


以下代码中用到的结构体:

/******************************保存字体信息********************************/
struct _LCUI_Font/* 字体信息数据 */
{
	int		type;		/* 类型(DEFAULT / CUSTOM) */ 
	LCUI_String	font_file;	/* 字体文件的路径 */
	LCUI_String	family_name;	/* 字体名称 */
	LCUI_String	style_name;	/* 字体风格名称 */ 
	void*		ft_lib;		/* FreeType2库的句柄  */
	void*		ft_face;	/* FreeType2的face对象的句柄 */
	int		load_flags;	/* 字形载入标志 */
	int		render_mode;	/* 字形转换模式标志 */
	int		status;		/* 状态,是否打开了字体库 */
};
/************************************************************************/
/********** 保存字体位图数据 ***************/
struct _LCUI_FontBMP
{
	int top;		/* 与顶边框的距离 */
	int left;		/* 与左边框的距离 */
	int width;		/* 位图宽度 */
	int rows;		/* 位图行数 */
	int pitch;
	uchar_t *buffer;	/* 字体位图数据 */
	short num_grays;
	char pixel_mode;
	LCUI_Pos advance;	/* XY轴的跨距 */
};
/*****************************************/


以下是部分代码,Convert_FTGlyph函数中主要获取字体位图的相关度量信息。

Open_Fontfile函数是打开指定路径的字体文件,并将FT库的句柄及face对象指针保存至结构体中。


   
   
   
   
int Open_Fontfile ( LCUI_Font * font_data , char * fontfile )
/* 打开指定路径中的字体文件,并保存数据至LCUI_Font结构体中 */
{
#ifdef USE_FREETYPE
int type ;
FT_Library library ;
FT_Face face ;
FT_Error face_error = 0 , lib_error = 0 ;
type = font_data -> type ;
if ( font_data -> status == ACTIVE ) {
/* 如果字体文件路径无效,或该路径和默认的字体文件路径一样,则退出函数 */
if ( ! fontfile || ! Strcmp ( & font_data -> font_file , fontfile ) ) {
return 0 ;
}
else if ( Strcmp ( & font_data -> font_file ,
LCUI_Sys . default_font . font_file . string )) {
/* 否则,如果不一样,就将type赋值为CUSTOM,表示自定义 */
type = CUSTOM ;
}
}
else if ( ! fontfile ) {
return - 1 ;
}
/* 初始化FreeType库 */
lib_error = FT_Init_FreeType ( & library );
/* 当初始化库时发生了一个错误 */
if ( lib_error ) {
printf ( "open fontfile: " FT_INIT_ERROR );
return - 1 ;
}
face_error = FT_New_Face ( library , fontfile , 0 , & face );
if ( face_error ) {
FT_Done_FreeType ( library );
if ( face_error == FT_Err_Unknown_File_Format ) {
/* 未知文件格式 */
printf ( "open fontfile: " FT_UNKNOWN_FILE_FORMAT );
} else {
/* 打开错误 */
printf ( "open fontfile: " FT_OPEN_FILE_ERROR );
}
/* 打印错误信息 */
perror ( fontfile );
return - 1 ;
}
/* 打印字体信息 */
printf ( "=============== font info ============== \n "
"family name: %s \n "
"style name : %s \n "
"======================================== \n " ,
face -> family_name ,
face -> style_name );
/* 先处理掉之前保存的字体信息 */
Font_Free ( font_data );
/* 保存新的字体信息 */
Strcpy ( & font_data -> family_name , face -> family_name );
Strcpy ( & font_data -> style_name , face -> style_name );
Strcpy ( & font_data -> font_file , fontfile );
font_data -> type = type ;
font_data -> status = ACTIVE ;
font_data -> ft_lib = library ;
font_data -> ft_face = face ;
return 0 ;
#else
printf ( "warning: not font engine support! \n " );
return - 1 ;
#endif
}
/* 如果定义了USE_FREETYPE宏定义,则使用FreeType字体引擎处理字体数据 */
#ifdef USE_FREETYPE
static int
Convert_FTGlyph ( LCUI_FontBMP * des , FT_GlyphSlot slot , int render_mode )
/* 转换FT_GlyphSlot类型数据为LCUI_FontBMP */
{
static FT_Error error ;
static size_t size ;
static FT_BitmapGlyph bitmap_glyph ;
static FT_Glyph glyph ;
/* 从字形槽中提取一个字形图像
* 请注意,创建的FT_Glyph对象必须与FT_Done_Glyph成对使用 */
error = FT_Get_Glyph ( slot , & glyph );
if ( error ) {
return - 1 ;
}
/*---------------------- 打印字体信息 --------------------------
printf(" width= %ld, met->height= %ld\n"
"horiBearingX = %ld, horiBearingY = %ld, horiAdvance = %ld\n"
"vertBearingX = %ld, vertBearingY = %ld, vertAdvance = %ld\n",
slot->metrics.width>>6, slot->metrics.height>>6,
slot->metrics.horiBearingX>>6, slot->metrics.horiBearingY>>6,
slot->metrics.horiAdvance>>6, slot->metrics.vertBearingX>>6,
slot->metrics.vertBearingY>>6, slot->metrics.vertAdvance>>6 );
------------------------------------------------------------*/
if ( glyph -> format != FT_GLYPH_FORMAT_BITMAP ) {
error = FT_Glyph_To_Bitmap ( & glyph , render_mode , 0 , 1 );
if ( error ) {
return - 1 ;
}
}
bitmap_glyph = ( FT_BitmapGlyph ) glyph ;
/*
* FT_Glyph_Metrics结构体中保存字形度量,通过face->glyph->metrics结
* 构访问,可得到字形的宽、高、左边界距、上边界距、水平跨距等等。
* 注意:因为不是所有的字体都包含垂直度量,当FT_HAS_VERTICAL为假时,
* vertBearingX,vertBearingY和vertAdvance的值是不可靠的,目前暂不考虑
* 此情况的处理。
* */
des -> top = bitmap_glyph -> top ;
des -> left = slot -> metrics . horiBearingX >> 6 ;
des -> rows = bitmap_glyph -> bitmap . rows ;
des -> width = bitmap_glyph -> bitmap . width ;
des -> pixel_mode = bitmap_glyph -> bitmap . pixel_mode ;
des -> num_grays = bitmap_glyph -> bitmap . num_grays ;
des -> advance . x = slot -> metrics . horiAdvance >> 6 ; /* 水平跨距 */
des -> advance . y = slot -> metrics . vertAdvance >> 6 ; /* 垂直跨距 */
/* 分配内存,用于保存字体位图 */
size = des -> rows * des -> width * sizeof ( uchar_t );
des -> buffer = malloc ( size );
if ( ! des -> buffer ) {
FT_Done_Glyph ( glyph );
return - 1 ;
}
/* 拷贝至该内存空间内 */
memcpy ( des -> buffer , bitmap_glyph -> bitmap . buffer , size );
FT_Done_Glyph ( glyph );
return size ;
}
#endif
int
Get_FontBMP ( LCUI_Font * font_data , wchar_t ch ,
int pixel_size , LCUI_FontBMP * out_bitmap )
/*
* 功能:获取单个wchar_t型字符的字体位图数据
* 说明:LCUI_Font结构体中储存着已被打开的字体文件句柄和face对象的句柄,如果字体文件
* 已经被成功打开一次,此函数不会再次打开字体文件。
*/
{
#ifdef USE_FREETYPE
size_t size ;
BOOL have_space = FALSE ;
FT_Face p_FT_Face = NULL ; /* face对象的句柄 */
FT_Error error ;
if ( font_data ) {
/* 如果font_data有效,则打开font_data中的指定的字体文件,并将字体文件
* 和face对象的句柄保存至结构体中。
* 当然,如果LCUI_Font结构体有有效的字体文件和face对象的句柄,就不会再重新
* 打开字体文件。
*/
if ( ! font_data -> ft_face || ! font_data -> ft_lib ) {
error = Open_Fontfile ( font_data ,
font_data -> font_file . string );
if ( error ) {
Get_Default_FontBMP ( ch , out_bitmap );
return 1 ;
}
}
/* 引用face对象句柄 */
p_FT_Face = font_data -> ft_face ;
} else {
/* 使用内置的字体位图 */
Get_Default_FontBMP ( ch , out_bitmap );
return - 1 ;
}
/* 设定为UNICODE,默认的也是 */
FT_Select_Charmap ( p_FT_Face , FT_ENCODING_UNICODE );
/* 设定字体尺寸 */
FT_Set_Pixel_Sizes ( p_FT_Face , 0 , pixel_size );
/* 如果是空格 */
if ( ch == ' ' ) {
ch = 'a' ;
have_space = TRUE ;
}
/* 这个函数只是简单地调用FT_Get_Char_Index和FT_Load_Glyph */
error = FT_Load_Char ( p_FT_Face , ch , font_data -> load_flags );
if ( error ) {
return error ;
}
size = Convert_FTGlyph ( out_bitmap , p_FT_Face -> glyph , font_data -> render_mode );
/* 如果是空格则将位图内容清空 */
if ( have_space ) {
memset ( out_bitmap -> buffer , 0 , size );
}
return 0 ;
#else
Get_Default_FontBMP ( ch , out_bitmap );
return - 1 ;
#endif
}



你可能感兴趣的:(C语言)