06.在LCD上显示多行矢量字

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.居中显示几行

居中显示的流程:

  1. 首先把这一行要显示的所有字符全部都转换成glyph,放到一个数组里。
  2. 你然后再算出所有字符的长宽,进而算出这一整行字符的高度和宽度。
  3. 根据你要显示的位置,以及上面算出的这一行字符的长宽,求出这一行显示的起始位置。
  4. 再把数组里的那些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 ); //释放空间
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值