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

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

主要是先解决编码问题,需要用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/* 字体信息数据 */{inttype;/* 类型(DEFAULT / CUSTOM) */ LCUI_Stringfont_file;/* 字体文件的路径 */LCUI_Stringfamily_name;/* 字体名称 */LCUI_Stringstyle_name;/* 字体风格名称 */ void*ft_lib;/* FreeType2库的句柄  */void*ft_face;/* FreeType2的face对象的句柄 */intload_flags;/* 字形载入标志 */intrender_mode;/* 字形转换模式标志 */intstatus;/* 状态,是否打开了字体库 */};/************************************************************************//********** 保存字体位图数据 ***************/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_FREETYPEinttype;FT_Librarylibrary;FT_Faceface;FT_Errorface_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;#elseprintf("warning: not font engine support!\n");return -1;#endif}/* 如果定义了USE_FREETYPE宏定义,则使用FreeType字体引擎处理字体数据 */#ifdef USE_FREETYPEstatic int Convert_FTGlyph( LCUI_FontBMP *des, FT_GlyphSlot slot, int render_mode )/* 转换FT_GlyphSlot类型数据为LCUI_FontBMP */{static FT_Errorerror;static size_tsize;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;}#endifint Get_FontBMP(LCUI_Font *font_data, wchar_t ch, int pixel_size, LCUI_FontBMP *out_bitmap)/* * 功能:获取单个wchar_t型字符的字体位图数据 * 说明:LCUI_Font结构体中储存着已被打开的字体文件句柄和face对象的句柄,如果字体文件 * 已经被成功打开一次,此函数不会再次打开字体文件。 */{#ifdef USE_FREETYPEsize_t size;BOOL have_space = FALSE;FT_Facep_FT_Face = NULL;   /* face对象的句柄 */ FT_Errorerror;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;#elseGet_Default_FontBMP( ch, out_bitmap );return -1;#endif}

看不见我将要去的地方,记不得我已经去过的地方。

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

相关文章:

你感兴趣的文章:

标签云: