【项目1_电子书】第2.3.4课、1/2_在LCD上显示显示一行 / 两行矢量文字

主 机: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节_1_在LCD上显示显示一行矢量文字

在02th_arm/02th_arm/02th_lcd/show_font.c的源码基础上修改,改名show_lines.c:
一.只保留矢量字体的操作,其余无关代码删除;

二、问题及解决
源码:
#include ...

int fd_fb;
static unsigned char *fbmem; /* fb的起始地址 */
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;
/*
* color: 0x00RRGGBB
*/
static unsigned short convert32to16(int color)
{
int red, green, blue;
red = (color>>16) & 0xff;
green = (color>>8) & 0xff;
blue = (color>>0) & 0xff;
return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3); //color: 565
}
/* 画点
* color: 32bit, 0x00RRGGBB
* 归根结底,是在帧缓冲器中填写数据,然后扫描显示到LCD屏幕;
*/
static void fb_put_pixel(int x, int y, unsigned int color)
{
unsigned char * pen_8;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned char *pixel_base = fbmem + (var.xres*y + x)*var.bits_per_pixel/8;
switch(var.bits_per_pixel)
{
case 8:
pen_8 = (unsigned char *)pixel_base;
*pen_8 = color;
break;
case 16:
pen_16 = (unsigned short *)pixel_base;
*pen_16 = convert32to16(color);
break;
case 32:
pen_32 = (unsigned int *)pixel_base;
*pen_32 = color;
break;
default:
printf("can't surpport %dbpp\n", var.bits_per_pixel);
break;
}
}
/* 绘制字符位图 */
void draw_bitmap(FT_Bitmap * bitmap, FT_Int x, FT_Int y)
{
FT_Int i, j;
for(j = y; j < y + bitmap->rows; j++)
for(i = x; i < x + bitmap->width; i++)
{
if(i < 0 || j < 0 || i >= var.xres || j >= var.yres)
continue;
fb_put_pixel(i, j, bitmap->buffer[(j - y)*bitmap->width + (i - x)]);
}
}
int main(int argc, char **argv)
{
FT_Library library; // typedef struct FT_LibraryRec_ *FT_Library;
// typedef struct FT_LibraryRec_{ ... } FT_LibraryRec;
FT_Face face; // typedef struct FT_FaceRec_* FT_Face;
// typedef struct FT_FaceRec_
{...
FT_GlyphSlot glyph; ... //typedef struct FT_GlyphSlotRec_* FT_GlyphSlot;
//同下面的变量slot的类型一样;
} FT_FaceRec;

FT_GlyphSlot slot; // typedef struct FT_GlyphSlotRec_* FT_GlyphSlot;
//typedef struct FT_GlyphSlotRec_
{...
FT_Library library;
FT_Face face;
FT_Glyph_Metrics metrics;
FT_Vector advance; //同下面变量pen的类型一样;
//vector:n.矢量,向量。
//advance:n.进步,进展; adj.预先的;事先的;先头部队。
FT_Glyph_Format format;
FT_Bitmap bitmap;
FT_Int bitmap_left;
FT_Int bitmap_top;
...
} FT_GlyphSlotRec;


FT_Vector pen; /* 未转换的起始点 */
typedef struct FT_Vector_
{
FT_Pos x; //typedef signed long FT_Pos;
FT_Pos y;
} FT_Vector;
FT_Matrix matrix; /* transformation matrix */
int error;
int i;
wchar_t wstr1[] = L"百问网gif";
wchar_t wstr2[] = L"www.100ask.org";
/* 一、LCD初始化 */
/* 二、显示矢量字体 */
error = FT_Init_FreeType( &library ); /* 初始化 Freetype 库*/
if ( error ) {。。。}
error = FT_New_Face( library, argv[1], 0, &face ); /* 打开一个字体文件 */
if ( error ) {。。。}

slot = face->glyph; //指针变量slot里面存放的是
FT_Set_Pixel_Sizes(face, 24, 0); /* 字体尺寸: 24x24像素 */

/* 确定起始点坐标:
* 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, 0, &pen ); /* 设置转换参数: 旋转0度 */

/* 根据编码值加载glyph到slot */
/* load时是把glyph放入插槽face->glyph */
error = FT_Load_Char( face, chinese_str[i], FT_LOAD_RENDER );
if(error)
{
printf("FT_Load_Char error.\n");
return -1;
}
draw_bitmap( &slot->bitmap,
slot->bitmap_left,
var.yres - slot->bitmap_top );
/* 增加pen的位置*/
pen.x += slot->advance.x;
}
return 0;
}
问题1:对于每次更替pen的位置,对于slot变量并没有在for()循环中显性重新赋值,但为什么可以通过
pen.x += slot->advance.x;
pen.y += slot->advance.y;
增加pen的位置?
答:slot = face->glyph;
1.指针变量slot是结构体指针类型:struct FT_GlyphSlotRec_* ;
2.指针变量face是结构体指针类型:struct FT_FaceRec_*;
3.指针变量face->glyph成员是结构体指针类型:struct FT_GlyphSlotRec_*; 且与 slot 同一类型;
for()循环之前,slot被赋予 字形结构体指针face->glyph成员的


问题2:插槽slot里面的数据是自动装载的吗?
猜想与推论1:pen.x += slot->advance.x;可以增加pen的位置,证明 advance.x/y是当下矢量
字体chinese_str[i]的尺寸(单位:像素),因此slot当中存放的是当下矢量字体chinese_str[i]
的glyph。而slot变量并没有在for()循环中被矢量字体chinese_str[i]的 glyph 显性重新赋值,
却可以通过slot->advance.x/y来改变pen的位置,因此推论插槽slot里面的数据是自动装载的。

猜想与推论2:插槽slot里面的数据是在函数FT_Load_Char()中自动装载的。
/* 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 );
而函数 error = FT_Load_Char( face, wstr1[i], FT_LOAD_RENDER ); /* 根据编码值加载glyph到slot */
的功能相当于FT_Get_Char_Index(), FT_Load_Glyph(), FT_Render_Glyph()三个函数的综合。
因此,插槽slot里面的数据应该是在函数FT_Load_Char()中自动装载的。


【注释】
1.FT_EXPORT( FT_Error ) FT_Set_Pixel_Sizes( FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height );
//typedef unsigned int FT_UInt;

2.FT_EXPORT( FT_Error ) FT_Load_Char( FT_Face face, FT_ULong char_code, FT_Int32 load_flags );
//typedef unsigned long FT_ULong;
//typedef signed XXX FT_Int32;
【函数解析】
解析:由LCD是按照帧缓冲器fb的数据从LCD自左到右,自上到下扫描可知,可知fb_put_pixel(x, y, color))的参数坐标(x, y)都是LCD坐标。
因此,draw_bitmap(bitmap, x, y)函数中的参数(x, y)都是LCD坐标,且是字体的左上角的像素做原点的坐标。
又因为draw_bitmap( &slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top ),所以:
slot->bitmap_left = x_LCD_字体左上角,var.yres - slot->bitmap_top = y_LCD_字体左上角。
所以,slot->bitmap_top = var.yres - y_LCD_字体左上角 = y_笛卡尔坐标_字体左上角。


三、编译及上板操作
a. 从左边开始显示几行文字
$ arm-linux-gcc -finput-charset=GBK -o show_lines show_lines.c -lfreetype -lm
# nfs 32000000 192.168.0.106:/work/nfs_root/uImage_lcd_3th; bootm 32000000
# nfs 32000000 192.168.0.101:/work/nfs_root/uImage_lcd_3th; bootm 32000000


输入编码集是国标码,但是在字符串chinese_str[]的数组内存里面存储的是宽字符的类型,
宽字符的类型里面即Unicode码。
如果源代码是用UTF-8写的,即可不必添加 -finput-charset=GBK 参数,但是SourceInsight3
不支持UTF-8编码()。大陆简体中文默认国标码。

$ arm-linux-gcc -finput-charset=GBK -o show_lines_1 show_lines_1.c -lfreetype -lm
$ sudo cp show_lines_1 /work/nfs_root/fs_mini_mdev_new/driver_test3/2.3freetype/02th_arm/
# ./show_lines_1 ../../simsun.ttc
//LCD显示:百问网gif

=======================================================
------------------------------------
2.3.4节_2_显示两行矢量文字
1、打印方框?
FT_Glyph glyph; /* a handle to the glyph image */
FT_BBox bbox; /* 含有每一个矢量文字的xMin, yMin; xMax, yMax;*/

for(i = 0; i < wcslen(wstr1); i++)
{
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 );

}

补充:
typedef struct FT_BBox_
{
FT_Pos xMin, yMin;
FT_Pos xMax, yMax;

} FT_BBox;
<Struct> */
/* FT_BBox */
/* */
/* <Description> */
/* A structure used to hold an outline's bounding box, i.e., the */
/* coordinates of its extrema in the horizontal and vertical */
/* directions.
/* 翻译:用于保存轮廓边界框的结构体,即,在水平和垂直方向上其极值的坐标。
/* outline:概述; 略述; 显示…的轮廓; 勾勒…的外形; 梗概; 轮廓线; 略图;
/* bounding: 边界;
修改源码:
int line_box_ymin = 10000; //笛卡尔坐标系;
int line_box_ymax = 0; //笛卡尔坐标系;

pen.x = 0 * 64;
pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64;

for(i = 0; i < wcslen(wstr1); i++)
{
error = FT_Get_Glyph( face->glyph, &glyph );
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );

if (line_box_ymin > bbox.yMin)
line_box_ymin = bbox.yMin;
if (line_box_ymax < bbox.yMax)
line_box_ymax = bbox.yMax;
}


猜你喜欢

转载自www.cnblogs.com/xiaohujian/p/11318226.html