【项目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:
一.只保留矢量字体的操作,其余无关代码删除;

 

1.2、函数及结构体说明

定义变量glyph:
FT_Glyph glyph; /* a handle to the glyph image */
typedef struct FT_GlyphRec_* FT_Glyph;
/* 根glyph结构体包含一个给定的glyph图像加上16.16固定浮点格式的前进宽度。
*/
typedef struct FT_GlyphRec_
{
FT_Library library;
const FT_Glyph_Class* clazz;
FT_Glyph_Format format;
FT_Vector advance;

} FT_GlyphRec;

定义变量slot:
FT_GlyphSlot slot;
typedef struct FT_GlyphSlotRec_* FT_GlyphSlot;
/* FreeType根 glyph 插槽类结构体。glyph slot是一个容器,可以在其中加载单个glyph,
* 无论它们是大纲格式还是位图格式。
*/
typedef struct FT_GlyphSlotRec_
{
FT_Library library;
FT_Face face;
FT_GlyphSlot next;
FT_UInt reserved; /* retained for binary compatibility */

FT_Vector advance;
FT_Glyph_Format format;

FT_Bitmap bitmap;
FT_Int bitmap_left;
FT_Int bitmap_top;
...
} FT_GlyphSlotRec;

定义变量face:
FT_Face face;
typedef struct FT_FaceRec_* FT_Face;
/* freetype根face类结构体。Face对象为字体文件中的字体建模。
*/
typedef struct FT_FaceRec_
{
FT_Long num_faces;
FT_Long face_index;

FT_Long face_flags;
FT_Long style_flags;

FT_Long num_glyphs;

FT_BBox bbox;
FT_GlyphSlot glyph;

/*@private begin */
/*@private end */
} FT_FaceRec;

因此,slot = face->glyph;中的glyph是FT_GlyphSlot类型变量,而一般单独定义的glyph变量是:FT_Glyph glyph;/* a handle to the glyph image */
同名不同人啊!!!不可以相互赋值!!!赋值则错误!!!

二、问题及解决
源码:
#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信息(包括bitmap, advance, bitmap_left,bitmap_top等及其他信息)。而slot变量并没有在for()循环中被矢量字体chinese_str[i]的 glyph 显性重新赋值,
却可以通过slot->advance.x/y来改变pen的位置,因此推论插槽slot里面的数据是自动装载的。

猜想与推论2:插槽slot里面的数据是在函数FT_Load_Char()或函数FT_Load_Glyph()中自动装载的。

函数FT_Load_Char() / FT_Load_Glyph()使用说明:
/* 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;


问题3: 函数draw_bitmap( &slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top )解析及参数含义
解析:由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: 边界;

2、修改源码:
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;
}


 源码: show_lines4.c

  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 int fd_fb;
 21 static unsigned char *fbmem;            /* fb的起始地址 */
 22 static struct fb_var_screeninfo var;
 23 static struct fb_fix_screeninfo fix;
 24 
 25 
 26 /*
 27  * color: 0x00RRGGBB
 28  */
 29 static unsigned short convert32to16(int color)
 30 {
 31     int red, green, blue;
 32     red = (color>>16) & 0xff;
 33     green = (color>>8) & 0xff;
 34     blue = (color>>0) & 0xff;
 35     return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);        //color: 565
 36 }
 37 /* 画点
 38  * color: 32bit, 0x00RRGGBB
 39  * 归根结底,是在帧缓冲器中填写数据,然后扫描显示到LCD屏幕;
 40  */
 41 static void fb_put_pixel(int x, int y, unsigned int color)
 42 {
 43     unsigned char * pen_8;
 44     unsigned short *pen_16;
 45     unsigned int *pen_32;
 46     unsigned char *pixel_base = fbmem + (var.xres*y + x)*var.bits_per_pixel/8;
 47 
 48     switch(var.bits_per_pixel)
 49     {
 50         case 8:
 51             pen_8 = (unsigned char *)pixel_base;
 52             *pen_8 = color;
 53             break;
 54         case 16:
 55             pen_16 = (unsigned short *)pixel_base;
 56             *pen_16 = convert32to16(color);
 57             break;
 58         case 32:
 59             pen_32 = (unsigned int *)pixel_base;
 60             *pen_32 = color;
 61             break;
 62         default:
 63             printf("can't surpport %dbpp\n", var.bits_per_pixel);
 64             break;
 65     }
 66 }
 67 
 68 /* 绘制字符位图 */
 69 void draw_bitmap(FT_Bitmap * bitmap, FT_Int x, FT_Int y)
 70 {
 71     FT_Int i, j;
 72 
 73     for(j = y; j < y + bitmap->rows; j++)
 74         for(i = x; i < x + bitmap->width; i++)
 75         {
 76             if(i < 0 || j < 0 || i >= var.xres || j >= var.yres)
 77                 continue;
 78             //image[j][i] |= bitmap->buffer[(j - y)*bitmap->width + (i - x)];
 79             fb_put_pixel(i, j, bitmap->buffer[(j - y)*bitmap->width + (i - x)]);
 80             
 81         }
 82 }
 83 
 84 
 85 int main(int argc, char **argv)
 86 {
 87     FT_Library    library;
 88     FT_Face       face;
 89 
 90     FT_Vector     pen;                    /* untransformed origin  */
 91     FT_GlyphSlot  slot;
 92 
 93     FT_Glyph  glyph;                         /* a handle to the glyph image */
 94     FT_BBox  bbox;
 95 
 96     int error;
 97     int i;
 98     wchar_t wstr1[] = L"百问网gif";
 99     wchar_t wstr2[] = L"www.100ask.org";
100     int line_box_ymin = 10000;
101     int line_box_ymax = 0;
102 
103 
104     if(argc != 2)
105     {
106         printf("Usage:    %s <font_file>\n", argv[0]);
107         return -1;
108     }
109     
110     /* 一、显示固定尺寸汉字/字符 */
111     /* 1、LCD初始化 */
112     fd_fb = open("/dev/fb0", O_RDWR);
113     if(fd_fb < 0)
114     {
115         printf("can't open /dev/fb0\n");
116         return -1;
117     }
118     if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))        //可变参数,成功,返回0; 出错,返回-1;
119     {
120         printf("can't get var\n");
121         return -1;
122     }
123     if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))        //固定参数,成功,返回0; 出错,返回-1;
124     {
125         printf("can't get fix\n");
126         return -1;
127     }
128 
129 
130     fbmem = (unsigned char *)mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
131     if(fbmem == (unsigned char *)-1)
132     {
133         printf("can't mmap fbmem\n");
134         return -1;
135     }
136     
137     /* 2、清屏 */
138     memset(fbmem, 0, fix.smem_len);
139 
140 
141 
142     /* 二、显示矢量字体 */
143     error = FT_Init_FreeType( &library );                  /* 初始化 Freetype 库*/
144     if ( error ) 
145     {
146         printf("FT_Init_FreeType error!\n");
147         return -1;
148     }
149      error = FT_New_Face( library, argv[1], 0, &face );     /* 打开一个字体文件 */
150     if ( error ) 
151     {
152         printf("FT_New_Face error!\n");
153         return -1;
154     }
155     slot = face->glyph;
156     FT_Set_Pixel_Sizes(face, 24, 0);                    /* 设置字体大小: 24*24 Pixel */
157 
158     /* 确定起始点坐标: 
159      * lcd_x = 0;
160      * lcd_y = 24;
161      * 笛卡尔坐标系: 
162      * x = lcd_x =  0;
163      * y = var.yres - lcd_y = var.yres - 24;
164      */
165       pen.x = 0 * 64;
166       pen.y = (var.yres - 24) * 64;
167 
168     for(i = 0; i < wcslen(wstr1); i++)
169     {
170         /* 设置矩阵 */
171         FT_Set_Transform( face, 0, &pen );            /* 字符保持不变换 */
172 
173         /* 根据编码值加载glyph到slot */
174         error = FT_Load_Char( face, wstr1[i], FT_LOAD_RENDER );
175         if ( error ) 
176         {
177             printf("FT_Load_Char error!\n");
178             return -1;
179         }
180 
181         /* 确定字体边框 */
182         error = FT_Get_Glyph( face->glyph, &glyph );
183         if ( error ) 
184         {
185             printf("FT_Get_Glyph error!\n");
186             return -1;
187         }
188         FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
189         if(line_box_ymin > bbox.yMin)
190             line_box_ymin = bbox.yMin;
191         if(line_box_ymax < bbox.yMax)
192             line_box_ymax = bbox.yMax;
193 
194         draw_bitmap( &slot->bitmap,
195                      slot->bitmap_left,
196                      var.yres - slot->bitmap_top );
197         pen.x += slot->advance.x;
198     }
199 
200     /* 确定起始点坐标: 
201      * lcd_x = 0;
202      * lcd_y = line_box_ymax - line_box_ymin + 24;
203      * 笛卡尔坐标系: 
204      * x = lcd_x =  0;
205      * y = var.yres - lcd_y = var.yres - (line_box_ymax - line_box_ymin + 24);
206      */
207       pen.x = 0 * 64;
208       pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64;
209 
210     for(i = 0; i < wcslen(wstr2); i++)
211     {
212         /* 设置矩阵 */
213         FT_Set_Transform( face, 0, &pen );            /* 字符保持不变换 */
214 
215         /* 根据编码值加载glyph到slot */
216         error = FT_Load_Char( face, wstr2[i], FT_LOAD_RENDER );
217         if ( error ) 
218         {
219             printf("FT_Load_Char error!\n");
220             return -1;
221         }
222 
223         /* 确定字体边框 */
224         error = FT_Get_Glyph( face->glyph, &glyph );
225         if ( error ) 
226         {
227             printf("FT_Get_Glyph error!\n");
228             return -1;
229         }
230         FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
231         if(line_box_ymin < bbox.yMin)
232             line_box_ymin = bbox.yMin;
233         if(line_box_ymax > bbox.yMax)
234             line_box_ymax = bbox.yMax;
235 
236         draw_bitmap( &slot->bitmap,
237                      slot->bitmap_left,
238                      var.yres - slot->bitmap_top );
239         pen.x += slot->advance.x;
240     }
241 
242     
243     return 0;
244 }

 

posted @ 2019-08-07 22:18  大秦长剑  阅读(465)  评论(0编辑  收藏  举报