字形指标是与每个字形关联的特定距离,以描述如何使用它来布局文本。
对于单个字形,通常有两组度量:用于在水平文本布局(拉丁,西里尔字母,阿拉伯语,希伯来语等)中设置字形的度量,以及用于在垂直文本布局中对字形进行布局的度量(中文,日语) ,韩文等)。
FT_Vector pen;
pen.x = 10;
pen.y = 10;
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Vector pen;
error = FT_Init_FreeType( &library );
error = FT_New_Face( library, argv[1], 0, &face );
FT_Set_Pixel_Sizes(face, 24, 0);
slot = face->glyph;
pen.x += slot->advance.x;
pen.y += slot->advance.y;
typedef struct FT_BBox_
{
FT_Pos xMin, yMin;
FT_Pos xMin, yMin;;
} FT_BBox;
FreeType所使用的坐标是笛卡尔坐标,与LCD使用的坐标不一样:
在这里,我们需要显示两行文字,具体步骤如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include FT_FREETYPE_H
#include FT_GLYPH_H
/* 文件操作 */
static int fd_fb;
static unsigned char *fbmem;
/* lcd参数 */
static int screen_size;
static unsigned int line_width;
static unsigned int pixel_width;
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;
/* lcd描色 color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
/* 该坐标在内存中对应像素的位置 */
pen_8 = fbmem+y*line_width+x*pixel_width;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
switch (var.bits_per_pixel) {
case 8:
*pen_8 = color;
break;
case 16:
/* RGB:565 */
red = ((color >> 16) & 0xffff) >> 3;
green = ((color >> 8) & 0xffff) >> 2;
blue = ((color >> 0) & 0xffff) >> 3;
*pen_16 = (red << 11) | (green << 5) | blue;
break;
case 32:
*pen_32 = color;
break;
default:
printf("can not surport &dbpp\n", var.bits_per_pixel);
break;
}
}
void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y)
{
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
//printf("x = %d, y = %d\n", x, y);
for (i = x, p = 0; i < x_max; i++, p++) {
for (j = y, q = 0; j < y_max; j++, q++) {
if (i < 0 || j < 0|| i >= var.xres || j >= var.yres)
continue;
//image[j][i] |= bitmap->buffer[q * bitmap->width + p];
lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);
}
}
}
int main(int argc, char **argv)
{
wchar_t *wstr1 = L"百问网gif";
wchar_t *wstr2 = L"www.100ask.com";
FT_Library library;
FT_Face face;
FT_Vector pen;
FT_GlyphSlot slot;
FT_Matrix matrix;
FT_BBox bbox;
FT_Glyph glyph;
double angle;
int error;
int line_box_ymin;
int line_box_ymax;
int i;
line_box_ymin = 10000;
line_box_ymax = 0;
/* 提示信息 */
if (argc != 3) {
printf("Usage : %s \n" , argv[0]);
return -1;
}
/* 打开设备:支持读写 */
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0) {
printf("can not open /dev/fb0 , err code :%d\n", fd_fb);
return -1;
}
/* 获得可变信息 */
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) {
printf("can not get var\n");
return -1;
}
/* 获得固定信息 */
if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) {
printf("can not get var\n");
return -1;
}
/* 直接映射到内存的Framebuffer */
screen_size = var.xres * var.yres * var.bits_per_pixel / 8; // 屏幕总像素所占的字节数
line_width = var.xres * var.bits_per_pixel / 8; // 每行像素所占的字节数
pixel_width = var.bits_per_pixel / 8; // 每个像素所占字节数
fbmem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fbmem == (unsigned char *)-1) {
printf("can not mmap\n");
return -1;
}
/* 清屏 */
memset(fbmem, 0, screen_size);
/* 显示矢量字 */
/* 初始化库 */
error = FT_Init_FreeType(&library);
/* 装载字体文件 */
error = FT_New_Face(library, argv[1], 0, &face);
slot = face->glyph;
/* 设置大小:24*24 */
FT_Set_Pixel_Sizes(face, 24, 0);
/* 设置旋转角度 */
angle = (1.0 * strtoul(argv[2], NULL, 0) / 360) * 3.14159 * 2; /* use 25 degrees */
/* 设置矩阵 */
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L);
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L);
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L);
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L);
/* 确定座标:
* lcd_x = 0
* lcd_y = 24
* 笛卡尔座标系:
* x = lcd_x = 0
* y = var.yres - lcd_y = var.yres - 24
*/
pen.x = 0 * 64;
pen.y = (var.yres - 24) * 64;
/* 显示第一行文字 */
for (i = 0; i < wcslen(wstr1); i++) {
/* 设置转换方法 */
FT_Set_Transform(face, &matrix, &pen);
/* 根据给定的文字信息,加载文字 */
error = FT_Load_Char(face, wstr1[i], FT_LOAD_RENDER);
if (error) {
printf("FT_Load_Char error\n");
return -1;
}
/* 从插槽中取出face->glyph,存到glyph中 */
error = FT_Get_Glyph(face->glyph, &glyph);
if (error) {
printf("FT_Get_Glyph error!\n");
return -1;
}
/* 得到相关字体参数信息 */
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
/* 寻该行最大的字符的height,即最小的yMin,最大的yMax */
if (line_box_ymax < bbox.yMax) line_box_ymax = bbox.yMax;
if (line_box_ymin > bbox.yMin) line_box_ymin = bbox.yMin;
/* 描绘位图信息 */
draw_bitmap(&slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top);
/* 打印位图信息 */
printf("Unicode: 0x%x\n", wstr1[i]);
printf("origin.x/64 = %d, origin.y/64 = %d\n", pen.x/64, pen.y/64);
printf("xMin = %d, xMax = %d, yMin = %d, yMax = %d\n", bbox.xMin, bbox.xMax, bbox.yMin, bbox.yMax);
printf("slot->advance.x/64 = %d, slot->advance.y/64 = %d\n", slot->advance.x/64, slot->advance.y/64);
/* 移动笔的位置:同一水平方向 */
pen.x += slot->advance.x;
}
/* 确定座标:
* lcd_x = 0
* lcd_y = line_box_ymax - line_box_ymin + 24
* 笛卡尔座标系:
* x = lcd_x = 0
* y = var.yres - lcd_y = var.yres - (line_box_ymax - line_box_ymin + 24)
*/
pen.x = 0 * 64;
pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64;
/* 显示第二行文字 */
for (i = 0; i < wcslen(wstr2); i++) {
/* 设置转换方法 */
FT_Set_Transform(face, &matrix, &pen);
/* 根据给定的文字信息,加载文字 */
error = FT_Load_Char(face, wstr2[i], FT_LOAD_RENDER);
if (error) {
printf("FT_Load_Char error\n");
return -1;
}
/* 从插槽中取出face->glyph,存到glyph中 */
error = FT_Get_Glyph(face->glyph, &glyph);
if (error) {
printf("FT_Get_Glyph error!\n");
return -1;
}
/* 得到相关字体参数信息 */
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
/* 寻该行最大的字符的height,即最小的yMin,最大的yMax */
if (line_box_ymax < bbox.yMax) line_box_ymax = bbox.yMax;
if (line_box_ymin > bbox.yMin) line_box_ymin = bbox.yMin;
/* 描绘位图信息 */
draw_bitmap(&slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top);
/* 打印位图信息 */
printf("Unicode: 0x%x\n", wstr1[i]);
printf("origin.x/64 = %d, origin.y/64 = %d\n", pen.x/64, pen.y/64);
printf("xMin = %d, xMax = %d, yMin = %d, yMax = %d\n", bbox.xMin, bbox.xMax, bbox.yMin, bbox.yMax);
printf("slot->advance.x/64 = %d, slot->advance.y/64 = %d\n", slot->advance.x/64, slot->advance.y/64);
/* 移动笔的位置:同一水平方向 */
pen.x += slot->advance.x;
}
return 0;
}
arm-linux-gcc -finput-charset=GBK -o show_line_left show_line_left.c -lfreetype -lm
show_line_left
可执行文件传到开发板,执行./show_line_left ./simsun.ttc
运行在这里,我们需要显示两行文字,具体步骤如下:
Get_Glyphs_Form_Wstr()
:根据字符串得到每个字符的glyph,并把glyph存储到Glyphs数组中compute_string_bbox()
:根据上述得到的Glyphs数组,计算得到该字符串的边框根据官方文档资料 【5.高级文本渲染:转换,居中和紧缩】进行编写
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include FT_FREETYPE_H
#include FT_GLYPH_H
/* FreeType */
#define MAX_GLYPHS 100
typedef struct TGlyph_
{
FT_UInt index; /* glyph index */
FT_Vector pos; /* glyph origin on the baseline */
FT_Glyph image; /* glyph image */
} TGlyph, *PGlyph;
/* 文件操作 */
static int fd_fb;
static unsigned char *fbmem;
/* lcd参数 */
static int screen_size;
static unsigned int line_width;
static unsigned int pixel_width;
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;
/* lcd描色 color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
/* 该坐标在内存中对应像素的位置 */
pen_8 = fbmem+y*line_width+x*pixel_width;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
switch (var.bits_per_pixel) {
case 8:
*pen_8 = color;
break;
case 16:
/* RGB:565 */
red = ((color >> 16) & 0xffff) >> 3;
green = ((color >> 8) & 0xffff) >> 2;
blue = ((color >> 0) & 0xffff) >> 3;
*pen_16 = (red << 11) | (green << 5) | blue;
break;
case 32:
*pen_32 = color;
break;
default:
printf("can not surport &dbpp\n", var.bits_per_pixel);
break;
}
}
void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y)
{
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
for (i = x, p = 0; i < x_max; i++, p++) {
for (j = y, q = 0; j < y_max; j++, q++) {
if (i < 0 || j < 0|| i >= var.xres || j >= var.yres)
continue;
lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);
}
}
}
/* 根据字符串得到Glyph,并把Glyph存储到Glyphs数组中 */
int Get_Glyphs_Form_Wstr(FT_Face face, wchar_t *wstr, TGlyph glyphs[])
{
int n;
int error;
int pen_x;
int pen_y;
PGlyph glyph;
FT_GlyphSlot slot;
glyph = glyphs;
slot = face->glyph;
pen_x = 0;
pen_y = 0;
for (n = 0; n < wcslen(wstr); n++) {
/* 根据该字符的Unicode码,获得在face中该字符的索引 */
glyph->index = FT_Get_Char_Index(face, wstr[n]);
/* 记录描绘坐标 */
glyph->pos.x = pen_x;
glyph->pos.y = pen_y;
/* 从face中根据glyph->index把glyph加载到插槽face->glyph中,不需要转换为位图 */
error = FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT);
if (error) continue;
/* 从插槽face->glyph中把信息加载到glyph->image中 */
error = FT_Get_Glyph(face->glyph, &glyph->image);
if (error) continue;
/* 设置变换方式:使得glyph->image中含有位置信息 */
FT_Glyph_Transform(glyph->image, 0, &glyph->pos);
/* 下一个字符的原点x坐标 */
pen_x += slot->advance.x;
glyph++;
}
/* 返回glyph的个数 */
return (glyph - glyphs);
}
/* 计算Glyphs数组中的字符串的边框 */
void compute_string_bbox(TGlyph glyphs[], FT_UInt num_glyphs, FT_BBox *abbox)
{
FT_BBox bbox;
int n;
bbox.xMin = bbox.yMin = 32000;
bbox.xMax = bbox.yMax = -32000;
for (n = 0; n < num_glyphs; n++) {
FT_BBox glyph_bbox;
/* 以像素为单位从glyphs[n]的数组项取值,得到该字符的边框box */
FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
/* 寻该行最大的字符的height和width,即最小的yMin和xMin,最大的yMax和xMax */
if (bbox.xMin > glyph_bbox.xMin) bbox.xMin = glyph_bbox.xMin;
if (bbox.xMax < glyph_bbox.xMax) bbox.xMax = glyph_bbox.xMax;
if (bbox.yMin > glyph_bbox.yMin) bbox.yMin = glyph_bbox.yMin;
if (bbox.yMax < glyph_bbox.yMax) bbox.yMax = glyph_bbox.yMax;
}
*abbox = bbox;
}
/* 描绘Glyphs中的信息——渲染 */
void Draw_Glyphs(TGlyph glyphs[], FT_UInt num_glyphs, FT_Vector pen)
{
int n;
int error;
for (n = 0; n < num_glyphs; n++) {
/* 设置变换方式:使得glyph->image中含有位置信息 */
FT_Glyph_Transform(glyphs[n].image, 0, &pen);
/* 把gylph转换为位图 */
error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0, 1); /* destroy copy in "image" */
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);
}
}
}
int main(int argc, char **argv)
{
wchar_t *wstr1 = L"百问网gif";
wchar_t *wstr2 = L"www.100ask.com";
FT_Library library;
FT_Face face;
FT_Vector pen;
FT_GlyphSlot slot;
FT_Matrix matrix;
FT_BBox bbox;
FT_UInt num_glyphs;
TGlyph glyphs[MAX_GLYPHS]; //负责存储字符信息的数组
PGlyph glyph;
double angle;
int error;
int line_box_ymin;
int line_box_ymax;
int line_box_height;
int line_box_width;
int i;
int num;
line_box_ymin = 10000;
line_box_ymax = 0;
/* 打开设备:支持读写 */
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0) {
printf("can not open /dev/fb0 , err code :%d\n", fd_fb);
return -1;
}
/* 获得可变信息 */
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) {
printf("can not get var\n");
return -1;
}
/* 获得固定信息 */
if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) {
printf("can not get var\n");
return -1;
}
/* 直接映射到内存的Framebuffer */
screen_size = var.xres * var.yres * var.bits_per_pixel / 8; // 屏幕总像素所占的字节数
line_width = var.xres * var.bits_per_pixel / 8; // 每行像素所占的字节数
pixel_width = var.bits_per_pixel / 8; // 每个像素所占字节数
fbmem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fbmem == (unsigned char *)-1) {
printf("can not mmap\n");
return -1;
}
/* 清屏 */
memset(fbmem, 0, screen_size);
/* 显示矢量字 */
/* 初始化库 */
error = FT_Init_FreeType(&library);
/* 装载字体文件 */
error = FT_New_Face(library, argv[1], 0, &face);
slot = face->glyph;
/* 设置像素大小:24*24 */
FT_Set_Pixel_Sizes(face, 24, 0);
/* 显示第一个字符串 */
/* 根据字符串得到字符的glyph,并把glyph存储到Glyphs数组中 */
num_glyphs = Get_Glyphs_Form_Wstr(face, wstr1, glyphs);
/* 计算Glyphs数组中的字符串的边框 */
compute_string_bbox(glyphs, num_glyphs, &bbox);
/* 计算一行中最高的高度和最宽的宽度 */
line_box_height = bbox.yMax - bbox.yMin;
line_box_width = bbox.xMax - bbox.xMin;
/* 确定原点坐标 */
pen.x = (var.xres - line_box_width)/2 * 64;
pen.y = (var.yres - line_box_height)/2 * 64;
/* 描绘Glyphs中的信息 */
Draw_Glyphs(glyphs, num_glyphs, pen);
/* 显示第二个字符串 */
/* 根据字符串得到Glyph,并把Glyph存储到Glyphs数组中 */
num_glyphs = Get_Glyphs_Form_Wstr(face, wstr2, glyphs);
/* 计算Glyphs数组中的字符串的边框 */
compute_string_bbox(glyphs, num_glyphs, &bbox);
/* 计算一行中最高的高度和最宽的宽度 */
line_box_height = bbox.yMax - bbox.yMin;
line_box_width = bbox.xMax - bbox.xMin;
/* 确定原点坐标 */
pen.x = (var.xres - line_box_width)/2 * 64;
pen.y = pen.y - 24 * 64;
/* 描绘Glyphs中的信息 */
Draw_Glyphs(glyphs, num_glyphs, pen);
return 0;
}