网上的FreeType2例子太少,能显示汉字的比较难找,C语言代码写的更难找,能找到的,基本上是被转载了N遍的同一个示例代码,基本上解决不了我的问题。
于是乎,花费了不少时间才完成了这些代码;
主要功能是:
将传入的GB2312编码的char型字符串转换成图片数组并输出。
主要原理是:
将GB2312编码的char型字符串,转换成unicode编码的wchar_t型字符串;
之后,利用FreeType2的API获取汉字的字体位图。
代码看似不怎么复杂,之前找char转wchar_t的代码,没找到一个合适的,最后呢,东拼西凑,就得到了想要的代码;
还有,输出的是记录每个像素点的256级灰度的数组,也就是和png图片中alpha通道一样,0 - 255表示透明度, 0为完全透明,255为不透明;
想要将这些文字贴到图片上,有个公式:
r2 = (r1 * alpha + r2 * (255 - alpha)) /255;
g2 = (g1 * alpha + g2 * (255 - alpha)) /255;
b2 = (b1 * alpha + b2 * (255 - alpha)) /255;
r、g、b表示图片的red、green、blue三种颜色,这三种颜色通过组合可以变成不同的颜色;
alpha是文字位图的alpha通道;
r2、b2、g2是图片重叠后该像素点显示的颜色;
r1、b1、g1是文字位图的每个像素点显示的颜色。
有需要这些代码的人的话,请把代码改一下,因为这是从我的LCUI图形库的代码中复制过来的,不能直接使用。
[cpp]
#include "LCUI_Build.h" #include LCUI_MAIN_H #include LCUI_FONTS_H #include "all.h" /*代码转换:从一种编码转为另一种编码*/ int code_convert(char *from_charset,char *to_charset,const char *inbuf,unsigned int inlen, unsigned char *outbuf,unsigned int outlen) { iconv_t cd; const char **pin = &inbuf; unsigned char **pout = &outbuf; cd = iconv_open(to_charset,from_charset); if (cd==0) return -1; memset(outbuf,0,outlen); if (iconv(cd,(char**)pin,&inlen,(char**)pout,&outlen)==-1) return -1; iconv_close(cd); return 0; } /*GB2312码转为utf-8码*/ int GB2312_To_UTF8(const char *inbuf,unsigned int inlen,unsigned char *outbuf,unsigned int outlen) { return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen); } unsigned short Get_Unicode(char *in_gb2312) { unsigned char out[256]; int rc; unsigned int length_gb2312; /* gb2312码转为utf8码 */ length_gb2312 = strlen(in_gb2312); rc = GB2312_To_UTF8(in_gb2312,length_gb2312,out,256); /* utf8转unicode码 */ unsigned short unicode; unicode = out[0]; if (unicode >= 0xF0) { unicode = (unsigned short) (out[0] & 0x07) << 18; unicode |= (unsigned short) (out[1] & 0x3F) << 12; unicode |= (unsigned short) (out[2] & 0x3F) << 6; unicode |= (unsigned short) (out[3] & 0x3F); } else if (unicode >= 0xE0) { unicode = (unsigned short) (out[0] & 0x0F) << 12; unicode |= (unsigned short) (out[1] & 0x3F) << 6; unicode |= (unsigned short) (out[2] & 0x3F); } else if (unicode >= 0xC0) { unicode = (unsigned short) (out[0] & 0x1F) << 6; unicode |= (unsigned short) (out[1] & 0x3F); } return unicode; } int Show_Font_Bitmap(Font_Bitmap_Data *in_fonts) /* 功能:在屏幕上以0和1表示字体位图 */ { int x,y; for(y=0;y<in_fonts->height;++y){ for(x=0;x<in_fonts->width;++x){ if(in_fonts->text_alpha[y*in_fonts->width+x]>0) printf("1"); else printf("0"); } printf("\n"); } printf("\n"); return 0; } int Get_Fonts_Bitmap( char *font_file, /* 字体文件路径 */ char *in_text, /* 输入的字符串 */ int fonts_pixel_size, /* 字体大小 */ int space, /* 间距 */ Font_Bitmap_Data *out_fonts /* 输出的位图数据,Pic_Data是结构体 */ ) /* ****************************************** */ /* 根据传入的字体库路径、字符串、字体尺寸,输 */ /* 出该字符串的位图数组 */ /* 本函数使用了freetype2的API */ /* ****************************************** */ { FT_Library p_FT_Lib = NULL; /* 库的句柄 */ FT_Face p_FT_Face = NULL; /* face对象的句柄 */ FT_Error error = 0; FT_Bitmap bitmap; FT_BitmapGlyph bitmap_glyph; FT_Glyph glyph; FT_GlyphSlot slot; int i , j ,temp,num,bg_height; char error_str[200]; error = FT_Init_FreeType( & p_FT_Lib); /* 初始化FreeType库 */ if (error) /* 当初始化库时发生了一个错误 */ { p_FT_Lib = 0 ; printf(FT_INIT_ERROR); return - 1 ; } /* 从字体库文件中获取字体 */ error = FT_New_Face(p_FT_Lib, font_file , 0 , & p_FT_Face); if ( error == FT_Err_Unknown_File_Format ) { printf(FT_UNKNOWN_FILE_FORMAT); /* 未知文件格式 */ return - 1 ; } else if (error) { printf(FT_OPEN_FILE_ERROR);/* 打开错误 */ perror("FreeeType2"); return - 1 ; } j = 0; wchar_t *unicode_text;/* 用于存储unicode字符 */ char ch[256]; unicode_text = (wchar_t*)calloc(1,sizeof(wchar_t)*(strlen(in_text)*2));/* 申请内存 */ for(i=0;i<strlen(in_text);++i){ memset(ch,0,sizeof(ch)); /* 所有元素置零 */ ch[0] = in_text[i]; /* 获取in_text中的第i个元素 */ if(ch[0] < 0) { /* GB2312编码的汉字,每byte是负数,因此,可以用来判断是否有汉字 */ if(i < strlen(in_text)-1){/* 如果没有到字符串末尾 */ ch[1] = in_text[i+1]; ++i; } else break; } unicode_text[j] = Get_Unicode(ch); /* 开始转换编码 */ ++j; } num = j; /* 记录字符的数量 */ int start_x = 0,start_y = 0; int ch_height = 0,ch_width = 0; int k,text_width = 0; size_t size = 0; unsigned char **text_alpha; bg_height = fonts_pixel_size+5; /* 背景图形的高度,这个高度要大于字体的高度,所以是+5 */ /* 分配内存,用于存储字体背景图的数据 */ text_alpha = (unsigned char**)malloc(sizeof(unsigned char*)*bg_height); for(i=0;i<bg_height;++i){ /* 预先为背景图的每一行分配内存 */ text_alpha[i] = (unsigned char*)malloc(sizeof(unsigned char)*1); } FT_Select_Charmap(p_FT_Face,FT_ENCODING_UNICODE); /* 设定为UNICODE,默认的也是 */ FT_Set_Pixel_Sizes(p_FT_Face,0,fonts_pixel_size); /* 设定字体大小 */ slot = p_FT_Face->glyph; for(temp=0;temp<num;++temp){ /* 开始遍历unicode编码的字符串中的每个元素 */ /* 这个函数只是简单地调用FT_Get_Char_Index和FT_Load_Glyph */ error = FT_Load_Char( p_FT_Face, unicode_text[temp], FT_LOAD_RENDER | FT_LOAD_NO_AUTOHINT); if(!error){ /* 从插槽中提取一个字形图像 */ /* 请注意,创建的FT_Glyph对象必须与FT_Done_Glyph成对使用 */ error = FT_Get_Glyph(p_FT_Face -> glyph, &glyph); if (!error) { if(unicode_text[temp] == ' ') { /* 如果有空格 */ k = 0; ch_width = (fonts_pixel_size -2)/2; ch_height = fonts_pixel_size; text_width = start_x + ch_width; start_y = 0; for(i=0;i<bg_height;++i){ text_alpha[i] = (unsigned char*)realloc(text_alpha[i],sizeof(unsigned char)*text_width); for(j=start_x-space;j<text_width;++j) text_alpha[i][j] = 0; } for ( i = 0 ; i < ch_height; ++i) { for ( j = 0 ; j < ch_width; ++j) { text_alpha[start_y + i][start_x + j] = 0; ++k; } } start_x += (ch_width+space); /* 画笔向右边移动 */ } else{ /* 256级灰度字形转换成位图 */ FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0 ,1); /* FT_RENDER_MODE_NORMAL 这是默认渲染模式,它对应于8位抗锯齿位图。 */ bitmap_glyph = (FT_BitmapGlyph)glyph; bitmap = bitmap_glyph -> bitmap; k = 0; start_y = fonts_pixel_size - slot->bitmap_top + 2; /* 获取起点的y轴坐标 */ if(start_y < 0) start_y = 0; if(bitmap.rows > bg_height) ch_height = fonts_pixel_size; else ch_height = bitmap.rows; if(ch_height+start_y > bg_height) ch_height = bg_height - start_y; ch_width = bitmap.width; text_width = start_x + bitmap.width; for(i=0;i<bg_height;++i){ /* 动态扩增存储字体位图的背景图形占用的空间 */ text_alpha[i] = (unsigned char*)realloc(text_alpha[i],sizeof(unsigned char)*text_width); for(j=start_x-space;j<text_width;++j) text_alpha[i][j] = 0;/* 多出来的空间全部置零 */ } /* 开始将字体位图贴到背景图形中 */ for(i = 0; i < bg_height; ++i){ for(j = 0;j < ch_width; ++j){ if(i >= start_y && i < start_y + ch_height){ /* 如果在字体位图的范围内 */ text_alpha[i][start_x + j] = bitmap.buffer[k]; ++k; } else text_alpha[i][start_x + j] = 0;/* 否则就置零 */ } } start_x += (ch_width+space); /* 画笔向右边移动 */ /* 释放字形占用的内存 */ FT_Done_Glyph(glyph); glyph = NULL; } } else{ sprintf(error_str,"FreeType2 错误[%d]",error); perror(error_str); } } else{ sprintf(error_str,"FreeType2 错误[%d]",error); perror(error_str); } } /* 释放face占用的内存 */ FT_Done_Face(p_FT_Face); p_FT_Face = NULL; /* 释放FreeType Lib占用的内存 */ FT_Done_FreeType(p_FT_Lib); p_FT_Lib = NULL; temp = 0; out_fonts->width = text_width; /* 要输出的位图的宽度 */ out_fonts->height = bg_height; /* 要输出的位图的高度 */ if(out_fonts->malloc == IS_TRUE) free(out_fonts->text_alpha); size = sizeof(unsigned char) * text_width * bg_height; out_fonts->text_alpha = (unsigned char*)calloc(1,size); /* 申请内存用来存储 */ k = 0; for ( i = 0 ; i < bg_height; ++i) { for ( j = 0 ; j < text_width; ++j) { out_fonts->text_alpha[k] = text_alpha[i][j]; ++k; } } out_fonts->malloc = IS_TRUE; /* 释放内存 */ for(i=0;i<bg_height;++i){ free(text_alpha[i]); } free(text_alpha); free(unicode_text); return 0; }这些代码在我的工程里的运行效果: