1.目的及注意
- 目的: 可以"居左"和"居中"显示多行文字
- 注意:
1、 居左显示: 显示的时候,应该从下面一条红线下面显示第二行,而不应该从第一条红线显示,这样就需要先把第一行文字的边框计算出来,以防第二行文字和第一行文字有串扰。先描边,再算边框
2、居中显示: 先算出边框,再确定坐标,再描画
2.居左显示几行
- 确定第二行的非笛卡尔坐标
算出这一点的非笛卡尔坐标后,再 (横坐标不变,总高度 - 纵坐标 - 字长24) 转换为笛卡尔坐标,赋值给pen.x,pen.y
!!注意: 这里所说的非笛卡尔坐标,是指 一个字的左上角为起始 ,韦东山说的非笛卡尔坐标,是指一个字的左下角为起始,因为矢量字库在描点的时候是从左下角开始描的,所以韦认为从左下角为起始。哪个都行,就是以后看代码时要分清楚。 - 显示第二行文字
显示第二行文字只不过是更改一下 pen这个变量,重新确定第二行的坐标,然后再把显示第一行的代码重复一遍。
//显示一下上一行文字的 ymax 和 yMin
printf("first line yMax = %d , yMin = %d \n",(int)line_box_yMax , (int)line_box_yMin);
//正常坐标系 (0, 0+line_box_yMax-line_box_yMin)
pen.x = 0 * 64;
pen.y = (target_height - (0+line_box_yMax-line_box_yMin) - 24) *64 ; // !!!注意这里,我们想让从(0,0)开始显示,一定要再多减去一个字符的高度,
//因为它是从左下角往上走的,而不是从左上角往下走的
for ( n = 0; n < wcslen(wst2) ; n++ ) //一个符号循环一次
{
//设置字用不用旋转和开始显示的位置
#ifdef QINGXIE //要不要倾斜一个角度
FT_Set_Transform( face, &matrix, &pen );
#else
FT_Set_Transform( face, 0, &pen );
#endif
//转换为点阵
error = FT_Load_Char( face, wst2[n] , FT_LOAD_RENDER ); //FT_LOAD_RENDER表示要转换成一个位图
if ( error )
{
printf("FT_Load_Char error\n");
return -1;
}
//主要获取bbox下的 xMin xMax yMin yMax
error = FT_Get_Glyph( face->glyph, &glyph ); //将字形图像(face->glyph)存到glyph里
if ( error )
{
printf("FT_Get_Glyph error\n");
return -1;
}
FT_Glyph_Get_CBox(glyph,FT_GLYPH_BBOX_TRUNCATE,&bbox);
/* now, draw to our target surface (convert position) */
draw_bitmap( &slot->bitmap,
slot->bitmap_left,
target_height - slot->bitmap_top );
/* increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
2.居中显示几行
居中显示的流程:
- 首先把这一行要显示的所有字符全部都转换成glyph,放到一个数组里。
- 你然后再算出所有字符的长宽,进而算出这一整行字符的高度和宽度。
- 根据你要显示的位置,以及上面算出的这一行字符的长宽,求出这一行显示的起始位置。
- 再把数组里的那些glyph转换成位图,然后显示。
1.结构体定义:
//主要的结构体
typedef struct TGlyph_ {
FT_UInt index; /* glyph index */ //index
FT_Vector pos; /* glyph origin on the baseline */ //位置
FT_Glyph image; /* glyph image */ //glyph
} TGlyph, *PGlyph;
2.主函数
//主函数
#define MAX_GLYPHS 100 //一行显示最大的字符数
int main(){
wchar_t *wst1 = L"这是矢量文字一abc"; //宽字符是unicode码
wchar_t *wst2 = L"这是矢量文字二lcd";
int fd_fb;
struct fb_var_screeninfo var; //用来存屏的可变信息的,对应驱动
struct fb_fix_screeninfo fix; //用来存屏不可变信息的
FT_Library library; //句柄和字库
FT_Face face;
FT_BBox bbox; //这个就是用来存一行字符里面 最大最小的 xMin/xMax....
FT_Vector pen; //存储一行的起始位置
TGlyph glyphs[MAX_GLYPHS]; //一个数组,用来装每一个字符的glyph和位置的信息
FT_UInt num_glyphs; //数组里存放了多少个字符,用着来存
int error
/********************屏的初始化************************************/
fd_fb = open("/dev/fb0",O_RDWR);
ioctl(fd_fb , FBIOGET_VSCREENINFO, &var); //获得屏的一些可变信息
ioctl(fd_fb , FBIOGET_FSCREENINFO, &fix); //获得屏的一些不可变信息
fbmem =(unsigned char *) mmap(NULL ,screen_size ,PROT_READ|PROT_WRITE , MAP_SHARED , fd_fb , 0); //使屏可以以指针方式操作
memset(fbmem, 0 ,screen_size);//清屏
/********************屏的初始化end************************************/
/*******************freetype相关初始化************************************/
error = FT_Init_FreeType( &library ); //初始化句柄
error = FT_New_Face(library , "simsun.ttc" ,0 ,&face); //加载face对象
FT_Set_Pixel_Sizes(face,24,24);//设置字体大小
/*******************freetype相关初始化end************************************/
/*******************显示第一行字符************************************/
num_glyphs = Get_Glyphs_Frm_Wstr(face ,wst1 ,glyphs); //从一个宽字符串中获得相对应的glyphs
//计算这一行的大小
compute_string_bbox(glyphs , num_glyphs ,&bbox);
line_box_width = bbox.xMax - bbox.xMin; //计算宽度 是整个一行字符的宽度
line_box_height = bbox.yMax - bbox.yMin; //计算高度 同理也是整个一行字符的高度
//确定起始位置,最中间 就是以下这样的
pen.x = (var.xres - line_box_width)/2 *64;
pen.y = (var.yres - line_box_height)/2 *64;
//画图
Draw_Glyphs(glyphs, num_glyphs , pen);
/*******************显示第二行字符************************************/
num_glyphs = Get_Glyphs_Frm_Wstr(face ,wst2 ,glyphs);
compute_string_bbox(glyphs , num_glyphs ,&bbox);
line_box_width = bbox.xMax - bbox.xMin; //计算宽度 是整个一行字符的宽度
line_box_height = bbox.yMax - bbox.yMin; //计算高度 同理也是整个一行字符的高度
pen.x = (var.xres - line_box_width )/2 *64; //x的算法和上面一样
pen.y = ((var.yres - line_box_height)/2 -24 )*64; //y要比上面多减一个字高
Draw_Glyphs(glyphs, num_glyphs , pen);
}
3.Get_Glyphs_Frm_Wstr 字符转glyphs函数
//glyph需要从字库文件中获取,所以要用到face
//获得哪些字符的glyph,用到这个字符串 *wstr
/*获取的这些宽字符的glyph放在一个数组里
*这里就需要用到上面的结构体
*结构体里面不止可以存放这一个字符glyph,还可以放这个字符的位置和索引信息
*所以这里用一个TGlyph结构体类型的数组,把宽字符串放进来
*/
int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t * wstr, TGlyph glyphs[])
{
int n;
PGlyph glyph = glyphs; //定义一个指针指向这个数组
int pen_x = 0; //假设这个字符串是从(0,0)位置开始描绘的,就是从屏幕最左下角开始
int pen_y = 0;
int error;
for(n = 0; n < wcslen(wstr); n++)
{
glyph->index = FT_Get_Char_Index( face , wstr[n]) ; //在字库里获得这个字符的索引
glyph->pos.x = pen_x; //记录这个字符相对于起始位置的位置
glyph->pos.y = pen_y;
/*load时是把glyph 放入插槽 face->glyph 中,每次换字符的时候就会覆盖掉前一个 */
error = FT_Load_Glyph(face ,glyph->index , FT_LOAD_DEFAULT); //转换成矢量文件,不是位图,描的时候再转
if(error) continue;
/*把glyph取出来存到这个结构体的image中*/
error = FT_Get_Glyph(face->glyph , &glyph->image);
if(error) continue;
/*使得glyph->image里含有位置信息*/
FT_Glyph_Transform(glyph->image, 0 , &glyph->pos);
pen_x += face->glyph->advance.x; /*单位 1/64point */
pen_y += face->glyph->advance.y;
glyph ++;
}
return (glyph - glyphs); //返回这个数组中存了多少个glyph,也就是多少个字符
}
4.compute_string_bbox 计算一行字符大小函数
//计算一行字符串的大小
void compute_string_bbox(TGlyph glyphs[] , FT_UInt num_glyphs, FT_BBox *abbox)
{
FT_BBox bbox;
int n;
bbox.xMin = bbox.yMin = 30000;
bbox.xMax = bbox.yMax = -1;
for(n = 0; n < num_glyphs; n++)
{
FT_BBox glyph_bbox;
// 以像素为单位 主要是获取glyph_bbox
FT_Glyph_Get_CBox(glyphs[n].image , FT_GLYPH_BBOX_TRUNCATE,&glyph_bbox);
if(glyph_bbox.xMin < bbox.xMin)
bbox.xMin = glyph_bbox.xMin;
if(glyph_bbox.xMax > bbox.xMax)
bbox.xMax = glyph_bbox.xMax;
if(glyph_bbox.yMin < bbox.yMin)
bbox.yMin = glyph_bbox.yMin;
if(glyph_bbox.yMax > bbox.yMax)
bbox.yMax = glyph_bbox.yMax;
}
*abbox = bbox;
}
5.Draw_Glyphs 根据数组中glyph画图函数
Draw_Glyphs(TGlyph glyphs[],FT_UInt num_glyphs ,FT_Vector pen)
{
int n;
int error;
for(n = 0; n < num_glyphs; n++)
{ //FT_Set_Transform( face, 0, &pen ); 这个是通过给字库文件添加角度的
FT_Glyph_Transform( glyphs[n].image, 0, &pen ); //这个是根据image添加角度
error = FT_Glyph_To_Bitmap( &glyphs[n].image , FT_RENDER_MODE_NORMAL ,0 ,1); //转换成位图
if(!error)
{
FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image; //用一个变量中转一下
draw_bitmap(&bit->bitmap, bit->left, var.yres - bit->top); //画图
FT_Done_Glyph(glyphs[n].image ); //释放空间
}
}
}