主 机:VMWare--Ubuntu-16.04.2-x64-100ask
开发板:Mini2440--256M NandFlash,   2M NorFlash,   64M SDRAM,   LCD-TD35;
    bootlorder:u-boot1.16,      Kernel:4.3.2;
编译器:arm-linux-gcc-4.3.2
2.3.4节_3_居中显示几行文字
一、源码修改
先算出长宽,再确定原点,再去描绘。
参考:
FreeType 2 Tutorial Step 2 — managing glyphs
	5. Advanced text rendering: transformation + centering + kerning
		a. packing & translating glyphs
		b. Rendering a transformed glyph sequence
源码笔记:
/* 从wstr[]里面获得字形glyph并存入glyphs[]数组 */
int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t *wstr, TGlyph glyphs[])
{
	int i;
  	PGlyph glyph = glyphs;		/* current glyph in table */
	int pen_x = 0;				/* 假设开始点坐标为(笛卡尔坐标): (0, 0), 单位: 1/64point */
	int pen_y = 0;
	int error;
	FT_GlyphSlot  slot = face->glyph;
	for(i = 0; i < wcslen(wstr); i++)
	{
		glyph->index = FT_Get_Char_Index( face, wstr[i] );	/* 根据字符串wstr的unicode码,
															 * 获得这个glyph的索引,即
															 * unicode码。
															 * index: n.索引;
															 */
		/* 存储当前 pen 的位置 */
    	glyph->pos.x = pen_x;
    	glyph->pos.y = pen_y;
		/* load是把字符wstr[i]的glyph放入插槽 face->glyph,下次for()循环时再把新的
		 * 字符的glyph放入插槽, 插槽会被覆盖掉的。
		 *
		 * 注释1: 根据glyph->index把字符wstr[i]的glyph从face里面加载出来。
		 * FT_LOAD_DEFAULT: 不需要转换为位图,只需要一个原原本本的矢量数据,即glyph数据,
		 * 以后描绘的时候再转换为位图,这样可以节省时间。
	     */
		error = FT_Load_Glyph( face, glyph->index, FT_LOAD_DEFAULT );
		
    	if ( error ) continue;
		/* 由于下次for()循环时再把新的字符的glyph放入插槽, 插槽会被覆盖掉的。所以,
		 * 把插槽中的face->glyph位图复制出来,存到数组glyphs[i].image中保留; 
		 * 注1: FT_Glyph   image; 
		 */
		error = FT_Get_Glyph( face->glyph, &glyph->image );
    	if ( error ) continue;
		/* translate the glyph image now, 现在转换字形图像;
		 * 函数说明: 如果字形图像的格式是可伸缩的,即矢量字体,则转换它。
		 * 
  		 * 把字符wstr[i]的位置信息存入glyph,即其对应的glyphs[i].image中;
  		 * 这使得glyphs[i].image里面含有位置信息。
  		 * 问题1: 位置信息是从glyph->pos,即glyphs[i].pos取出放入glyphs[i]->image->advance.x/y吗?
  		 * 猜想1: 应该是的。
		 */
    	FT_Glyph_Transform( glyph->image, 0, &glyph->pos );
		pen_x += slot->advance.x;		/* 单位:1/64point */
		/* increment number of glyphs */
    	glyph++;
	}
	/* 返回值: count number of glyphs loaded, 即加载的字形计数 */
  	return (glyph - glyphs);
}
/* 计算宽字符串的边框的长/宽,(假设开始点坐标为(笛卡尔坐标): (0, 0)) */
void compute_string_bbox(TGlyph glyphs[], FT_UInt num_glyphs, FT_BBox *abbox)
{
	FT_BBox  bbox;
	FT_BBox  glyph_bbox;
	int i;
    bbox.xMin = bbox.yMin =  32000;
    bbox.xMax = bbox.yMax = -32000;
	for(i = 0; i < num_glyphs; i++)
	{
    	FT_Glyph_Get_CBox(glyphs[i].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;
}
void Draw_Glyphs(TGlyph glyphs[], FT_UInt num_glyphs, FT_Vector pen)
{
	int i, error;
	for(i = 0; i < num_glyphs; i++)
	{
		/* transform copy (this will also translate it to the  correct position 
		 */
    	FT_Glyph_Transform(glyphs[i].image, 0, &pen);	/*delta:相当于(0, 0)的pen*/
		/* convert glyph image to bitmap (destroy the glyph copy!) */
    	error = FT_Glyph_To_Bitmap(
	              &glyphs[i].image,
	              FT_RENDER_MODE_NORMAL,
	              0,                  /* no additional translation */
	              1 );                /* destroy copy in "image"   */
	    if ( !error )	/* 如果没有错误,则: */
	    {
	    	FT_BitmapGlyph  bit = (FT_BitmapGlyph)glyphs[i].image;		/* 获得位图 */
	    	draw_bitmap(&bit->bitmap,
	                    bit->left,
	                    var.yres - bit->top );				/* 描绘 */
	    	FT_Done_Glyph(glyphs[i].image);
	    }
	}
}
int main(...)
{
....
num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr1, glyphs);
}
二、 问题及解析
问题1:关于源码中,坐标初始化部分的代码:
	int pen_x = 0;	/* start at (0,0) */
	int pen_y = 0;
	for(i = 0; i < wcslen(wstr); i++){
		glyph->pos.x = pen_x;
    	glyph->pos.y = pen_y;
		...
		FT_Glyph_Transform( glyph->image, 0, &glyph->pos );
		pen_x += slot->advance.x;
    	glyph++;
	}
可否修改为这样初始化:
	FT_Vector     pen;	  /* untransformed origin  */
	...
	pen.x = 0 * 64;	  	/* start at (0,0) */
	pen.y = 0 * 64;
	for(i = 0; i < wcslen(wstr1); i++){
		...
		FT_Glyph_Transform( glyph->image, 0, &pen );
		pen.x += slot->advance.x;
		glyph++;
	}
猜想1:应该可以的,实验一下!实验源码的名字是?
答:猜想正确,下面的附录中的源码就是上机验证成功的例子!
注释1:
函数 FT_Glyph_Transform()
Defined in FT_GLYPH_H (freetype/ftglyph.h).
	FT_EXPORT( FT_Error )  FT_Glyph_Transform(FT_Glyph glyph, FT_Matrix* matrix, FT_Vector* delta);
函数 FT_Set_Transform()
Defined in FT_FREETYPE_H (freetype/freetype.h).
	FT_EXPORT( void )  FT_Set_Transform(FT_Face face,  FT_Matrix* matrix, FT_Vector* delta);
问题2:函数  Get_Glyphs_Frm_Wstr()  可否修改为:
int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t *wstr, TGlyph glyphs[])
{
	  for(i = 0; i < wcslen(wstr); i++)
	  {
	        error = FT_Load_Char( face, wstr1[i], FT_LOAD_RENDER ); 	/* 根据编码值加载glyph到slot */
		    glyphs[i].image = face->glyph 或者 slot;
		
		    FT_Glyph_Transform( glyph->image, 0, &glyph->pos );			/* 转换字符位图 */
		    pen_x += slot->advance.x;		/* 单位:1/64point */
    	    glyph++;
	  }
}
但是这样修改会对原来的程序产生一些不必要的问题吗?如果是的,则不建议如此用。
答:不可以这样改,经验证错误!glyphs[i].image 与 face->glyph 或者 slot;不是同一个类型,同名不同人!!!
三、编译与上板实验
$ arm-linux-gcc -finput-charset=GBK -o show_lines5_1  show_lines5_1.c  -lfreetype -lm
$ ls
show_lines5_1  show_lines5_1.c
$ sudo cp show_lines5_1  /work/nfs_root/fs_mini_mdev_new/driver_test3/2.3freetype/02th_arm/06th_show_lines_center
# ./show_lines5_1  ../../simsun.ttc
如此,LCD中央显示:  [	  	百问网gif	    ]
					             [   www.100ask.org    ]
源码:
1 /* 2 * 2019-05-30 3 * 目的: 在LCD上居中显示两行矢量文字; 4 */ 5 #include <stdio.h> 6 #include <sys/mman.h> 7 #include <sys/types.h> 8 #include <sys/stat.h> 9 #include <unistd.h> 10 #include <linux/fb.h> 11 #include <string.h> 12 #include <fcntl.h> 13 14 #include <math.h> 15 #include <wchar.h> 16 #include <ft2build.h> 17 #include FT_FREETYPE_H 18 #include FT_GLYPH_H 19 20 typedef struct TGlyph_ 21 { 22 FT_UInt index; /* glyph index */ 23 FT_Vector pos; /* glyph origin on the baseline */ 24 FT_Glyph image; /* glyph image */ 25 26 } TGlyph, *PGlyph; 27 28 #define MAX_GLYPHS 100 /* 矢量字符串长度 */ 29 30 int fd_fb; 31 static unsigned char *fbmem; /* fb的起始地址 */ 32 static struct fb_var_screeninfo var; 33 static struct fb_fix_screeninfo fix; 34 35 36 /* 37 * color: 0x00RRGGBB 38 */ 39 static unsigned short convert32to16(int color) 40 { 41 int red, green, blue; 42 red = (color>>16) & 0xff; 43 green = (color>>8) & 0xff; 44 blue = (color>>0) & 0xff; 45 return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3); //color: 565 46 } 47 /* 画点 48 * color: 32bit, 0x00RRGGBB 49 * 归根结底,是在帧缓冲器中填写数据,然后扫描显示到LCD屏幕; 50 */ 51 static void fb_put_pixel(int x, int y, unsigned int color) 52 { 53 unsigned char * pen_8; 54 unsigned short *pen_16; 55 unsigned int *pen_32; 56 unsigned char *pixel_base = fbmem + (var.xres*y + x)*var.bits_per_pixel/8; 57 58 switch(var.bits_per_pixel) 59 { 60 case 8: 61 pen_8 = (unsigned char *)pixel_base; 62 *pen_8 = color; 63 break; 64 case 16: 65 pen_16 = (unsigned short *)pixel_base; 66 *pen_16 = convert32to16(color); 67 break; 68 case 32: 69 pen_32 = (unsigned int *)pixel_base; 70 *pen_32 = color; 71 break; 72 default: 73 printf("can‘t surpport %dbpp\n", var.bits_per_pixel); 74 break; 75 } 76 } 77 78 /* 绘制字符位图 */ 79 void draw_bitmap(FT_Bitmap * bitmap, FT_Int x, FT_Int y) 80 { 81 FT_Int i, j; 82 83 for(j = y; j < y + bitmap->rows; j++) 84 for(i = x; i < x + bitmap->width; i++) 85 { 86 if(i < 0 || j < 0 || i >= var.xres || j >= var.yres) 87 continue; 88 //image[j][i] |= bitmap->buffer[(j - y)*bitmap->width + (i - x)]; 89 fb_put_pixel(i, j, bitmap->buffer[(j - y)*bitmap->width + (i - x)]); 90 91 } 92 } 93 94 /* 从face里加载字符wstr[]的glyph到glyphs[] */ 95 int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t * wstr, TGlyph glyphs[]) 96 { 97 FT_GlyphSlot slot = face->glyph; /* a small shortcut */ 98 FT_UInt glyph_index; 99 FT_Vector pen; 100 PGlyph pglyph = glyphs; /* current glyph in table */ 101 int i, error; 102 103 pen.x = 0; /* 假设起始点坐标(笛卡尔坐标)为: (0, 0); */ 104 pen.y = 0; 105 for(i = 0; i < wcslen(wstr); i++) 106 { 107 /* 从face中得到wstr[i]的索引值 */ 108 pglyph->index = FT_Get_Char_Index( face, wstr[i] ); 109 110 /* store current pen position */ 111 //pglyph->pos = pen; 112 /* 根据索引值加载wstr[i]的glyph到插槽slot=face->glyph */ 113 error = FT_Load_Glyph( face, pglyph->index, FT_LOAD_DEFAULT ); 114 if ( error ) continue; 115 /* 把插槽slot=face->glyph复制到glyphs[i]中 */ 116 error = FT_Get_Glyph( face->glyph, &pglyph->image ); 117 if ( error ) continue; 118 119 /* 转换字形: 旋转0度,设置起始点坐标 */ 120 FT_Glyph_Transform(pglyph->image, 0, &pen); 121 122 pen.x += slot->advance.x; 123 pglyph++; 124 } 125 return (pglyph - glyphs); 126 } 127 128 /* 计算字符串的边框的长/宽 */ 129 void compute_string_bbox(TGlyph glyphs [], FT_UInt num_glyphs, FT_BBox * abbox) 130 { 131 FT_BBox bbox; 132 FT_BBox glyph_bbox; 133 int i; 134 135 136 bbox.xMin = bbox.yMin = 32000; 137 bbox.xMax = bbox.yMax = -32000; 138 139 for ( i = 0; i < num_glyphs; i++ ) 140 { 141 FT_Glyph_Get_CBox( glyphs[i].image, FT_GLYPH_BBOX_PIXELS, &glyph_bbox ); 142 143 if (glyph_bbox.xMin < bbox.xMin) 144 bbox.xMin = glyph_bbox.xMin; 145 if (glyph_bbox.yMin < bbox.yMin) 146 bbox.yMin = glyph_bbox.yMin; 147 if (glyph_bbox.xMax > bbox.xMax) 148 bbox.xMax = glyph_bbox.xMax; 149 if (glyph_bbox.yMax > bbox.yMax) 150 bbox.yMax = glyph_bbox.yMax; 151 } 152 *abbox = bbox; 153 } 154 /* 从一个正确的坐标开始描绘字符点阵 */ 155 void Draw_Glyphs(TGlyph glyphs[], FT_UInt num_glyphs, FT_Vector start) 156 { 157 FT_Glyph image; 158 FT_Vector pen; 159 FT_BBox bbox; 160 int i, error; 161 162 for ( i = 0; i < num_glyphs; i++ ) 163 { 164 /* transform copy (this will also translate it to the correct position */ 165 FT_Glyph_Transform( glyphs[i].image, 0, &start ); 166 167 /* convert glyph image to bitmap (destroy the glyph copy!) */ 168 error = FT_Glyph_To_Bitmap( 169 &glyphs[i].image, 170 FT_RENDER_MODE_NORMAL, 171 0, /* no additional translation */ 172 1 ); /* destroy copy in "image" */ 173 if ( !error ) 174 { 175 FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[i].image; 176 177 draw_bitmap( &bit->bitmap, 178 bit->left, 179 var.yres - bit->top ); 180 181 FT_Done_Glyph( glyphs[i].image ); 182 } 183 } 184 } 185 186 int main(int argc, char **argv) 187 { 188 FT_Library library; 189 FT_Face face; 190 191 FT_Vector pen; /* untransformed origin */ 192 FT_GlyphSlot slot; 193 194 int error; 195 int i; 196 wchar_t wstr1[] = L"百问网gif"; 197 wchar_t wstr2[] = L"www.100ask.org"; 198 199 TGlyph glyphs[MAX_GLYPHS]; /* glyphs table */ 200 PGlyph pglyph; /* current glyph in table */ 201 FT_UInt num_glyphs; 202 203 FT_BBox bbox; 204 int line_box_width; 205 int line_box_height; 206 207 208 if(argc != 2) 209 { 210 printf("Usage: %s <font_file>\n", argv[0]); 211 return -1; 212 } 213 214 /* 一、显示固定尺寸汉字/字符 */ 215 /* 1、LCD初始化 */ 216 fd_fb = open("/dev/fb0", O_RDWR); 217 if(fd_fb < 0) 218 { 219 printf("can‘t open /dev/fb0\n"); 220 return -1; 221 } 222 if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) //可变参数,成功,返回0; 出错,返回-1; 223 { 224 printf("can‘t get var\n"); 225 return -1; 226 } 227 if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) //固定参数,成功,返回0; 出错,返回-1; 228 { 229 printf("can‘t get fix\n"); 230 return -1; 231 } 232 233 234 fbmem = (unsigned char *)mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); 235 if(fbmem == (unsigned char *)-1) 236 { 237 printf("can‘t mmap fbmem\n"); 238 return -1; 239 } 240 241 /* 2、清屏 */ 242 memset(fbmem, 0, fix.smem_len); 243 244 245 246 /* 二、显示矢量字体 */ 247 error = FT_Init_FreeType( &library ); /* 初始化 Freetype 库*/ 248 if ( error ) 249 { 250 printf("FT_Init_FreeType error!\n"); 251 return -1; 252 } 253 error = FT_New_Face( library, argv[1], 0, &face ); /* 打开一个字体文件 */ 254 if ( error ) 255 { 256 printf("FT_New_Face error!\n"); 257 return -1; 258 } 259 slot = face->glyph; 260 FT_Set_Pixel_Sizes(face, 24, 0); /* 设置字体大小: 24*24 Pixel */ 261 262 /* 居中显示字符串wstr1[] */ 263 num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr1, glyphs); 264 compute_string_bbox(glyphs, num_glyphs, &bbox); 265 line_box_width = bbox.xMax - bbox.xMin; 266 line_box_height = bbox.yMax - bbox.yMin; 267 268 pen.x = (var.xres - line_box_width)/2 * 64; 269 pen.y = (var.yres - line_box_height)/2 * 64; 270 Draw_Glyphs(glyphs, num_glyphs, pen); 271 272 273 /* 居中显示字符串wstr2[] */ 274 num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr2, glyphs); 275 compute_string_bbox(glyphs, num_glyphs, &bbox); 276 line_box_width = bbox.xMax - bbox.xMin; 277 line_box_height = bbox.yMax - bbox.yMin; 278 279 pen.x = (var.xres - line_box_width)/2 * 64; 280 pen.y -= 24 * 64; 281 Draw_Glyphs(glyphs, num_glyphs, pen); 282 283 return 0; 284 }
【项目1_电子书】第2.3.4课、3_在LCD上居中显示两行矢量文字
原文:https://www.cnblogs.com/xiaohujian/p/11318484.html