您的位置:首页 > 运维架构 > Linux

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

2011-11-04 18:37 393 查看
网上的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}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: