当前位置:网站首页>framebuffer应用编程及文字显示(2)
framebuffer应用编程及文字显示(2)
2022-08-05 05:16:00 【乛 乛 .】
framebuffer应用编程及文字显示(2)
#6 .1Freetype介绍
Freetype是开源的字体引擎库,它提供统一的接口来访问多种字体格式文件,从而实现矢量字体显示。我们只需要移植这个字体引擎,调用对应的API接口,提供字体文件,就可以让freetype库帮我们取出关键点、实现闭合曲线,填充颜色,达到显示矢量字体的目的。
关键点(glyph)存在字体文件中,Windows使用的字体文件在c:\Windows\Fonts目录下,扩展名为TTF的都是矢量字库,本次使用实验使用的是新宋字体simsun.ttc。
给定一个字符,怎么在字体文件中找到它的关键点?
首先要确定该字符的编码值:比如ASCII码、GB2312码、UNICODE码。如果字体文件支持某种编码格式(charset),就可以使用这类编码值去找到该字符的关键点(glyph)。有些字体文件支持多种编码格式(charset),这在文件中被称为charmaps(注意:这个单词是复数,意味着可能支持多种charset)。
以simsun.ttc为值,该字体文件的格如下:头部含有charmaps,可以使用某种编码值去charmaps中找到它对应的关键点。下图中的“A、B、中、国、韦”等只是glyph的示意图,表示关键点。
Charmaps表示字符映射表,字体文件可能支持哪一些编码,GB2312、UNICODE、BIG5或其他。如果字体文件支持该编码,使用编码值通过charmap就可以找到对应的glyph,一般而言都支持UNICODE码。
一个文字的显示过程可以概括如下:
① 给定一个字符可以确定它的编码值(ASCII、UNICODE、GB2312);
② 设置字体大小;
③ 根据编码值,从文件头部中通过charmap找到对应的关键点(glyph),它会根据字体大小调整关键点;
④ 把关键点转换为位图点阵;
⑤ 在LCD上显示出来
而对于freetype库的使用,总结出下列步骤:
① 初始化:FT_InitFreetype
② 加载(打开)字体Face:FT_New_Face
③ 设置字体大小:FT_Set_Char_Sizes 或 FT_Set_Pixel_Sizes
④ 选择charmap:FT_Select_Charmap
⑤ 根据编码值charcode找到glyph_index:glyph_index = FT_Get_Char_Index(face,charcode)
⑥ 根据glyph_index取出glyph:FT_Load_Glyph(face,glyph_index)
⑦ 转为位图:FT_Render_Glyph
⑧ 移动或旋转:FT_Set_Transform
⑨ 最后显示出来。
上面的⑤⑥⑦可以使用一个函数代替:FT_Load_Char(face, charcode, FT_LOAD_RENDER),它就可以得到位图。
#6 .2在LCD上显示一个矢量字体
- 使用wchar_t获得字符的UNICODE值
- 使用freetype得到位图
要使用freetype得到一个字符的位图,只需要4个步骤
① 初始化freetype库
158 error = FT_Init_FreeType( &library ); /* initialize library /
② 加载字体文件,保存在&face中:
161 error = FT_New_Face( library, argv[1], 0, &face ); / create face object /
162 / error handling omitted /
163 slot = face->glyph;
第163行是从face中获得FT_GlyphSlot,后面的代码中文字的位图就是保存在FT_GlyphSlot里。
③ 设置字体大小
165 FT_Set_Pixel_Sizes(face, font_size, 0);
④ 根据编码值得到位图
使用FT_Load_Char函数,就可以实现这3个功能:
a. 根据编码值获得glyph_index:FT_Get_Char_Index
b. 根据glyph_idex取出glyph:FT_Load_Glyph
c. 渲染出位图:FT_Render_Glyph
代码如下:
175 / load glyph image into the slot (erase previous one) */
176 error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );
执行FT_Load_Char之后,字符的位图被存在slot->bitmap里,即face->glyph->bitmap。 - 在屏幕上显示位图
位图里的数据格式是怎样的?参考example1.c的代码,可以得到下面这个图
在屏幕上显示出这些位图:
183 draw_bitmap( &slot->bitmap,
184 var.xres/2,
185 var.yres/2);
draw_bitmap函数代码如下,由于位图中每一个像素用一个字节来表示,在0x00RRGGBB的颜色格式中它只能表示蓝色,所以在LCD上显示出来的文字是蓝色的:
执行以下命令:
arm-buildroot-linux-gnueabihf-gcc -o freetype_show_font freetype_show_font.c -lfreetype
将编译好的freetype_show_font文件与simsun.ttc字体文件拷贝至开发板,这2个文件放在同一个目录下,然后执行以下命令。
./freetype_show_font ./simsun.ttc 300
观察到屏幕中间看到一个蓝色的“繁”字。完整代码如下:
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H //包含必要头文件
int fd_fb;
struct fb_var_screeninfo var; /* Current var */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
/********************************************************************** * 函数名称: lcd_put_pixel * 功能描述: 在LCD指定位置上输出指定颜色(描点) * 输入参数: x坐标,y坐标,颜色 ***********************************************************************/
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
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:
{
/* 565 */
red = (color >> 16) & 0xff;
green = (color >> 8) & 0xff;
blue = (color >> 0) & 0xff;
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
/********************************************************************** * 函数名称: draw_bitmap * 功能描述: 根据bitmap位图,在LCD指定位置显示汉字 * 输入参数: x坐标,y坐标,位图指针 ***********************************************************************/
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 ( j = y, q = 0; j < y_max; j++, q++ )
{
for ( i = x, p = 0; i < x_max; i++, p++ )
{
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 *chinese_str = L"繁"; //如果想在代码中能直接使用UNICODE值,需要使用wchar_t,宽字符“繁”为想要显示的汉字
FT_Library library;
FT_Face face;
int error;
FT_Vector pen;
FT_GlyphSlot slot;
int font_size = 24;
if (argc < 2)
{
printf("Usage : %s <font_file> [font_size]\n", argv[0]);
return -1;
}
if (argc == 3)
font_size = strtoul(argv[2], NULL, 0);
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
//lcd初始化
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * 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't mmap\n");
return -1;
}
/* 清屏: 全部设为黑色 */
memset(fbmem, 0, screen_size);
/* 显示矢量字体 */
error = FT_Init_FreeType( &library ); //初始化freetype库
error = FT_New_Face( library, argv[1], 0, &face ); //加载字体文件,将读取到的字体文件保存至face, argv[1]为字体文件路径
slot = face->glyph;
FT_Set_Pixel_Sizes(face, font_size, 0); //设置字体大小
/* 确定座标: */
//pen.x = 0;
//pen.y = 0;
/* set transformation */
//FT_Set_Transform( face, 0, &pen);
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
draw_bitmap( &slot->bitmap,
var.xres/2,
var.yres/2);
return 0;
}
#6 .3 在LCD上显示一行矢量字体
##6 .3 .1 笛卡尔坐标系
在LCD的坐标系中,原点在屏幕的左上角。对于笛卡尔坐标系,原点在左下角。freetype使用笛卡尔坐标系,在显示时需要转换为LCD坐标系。
从下图可知,X方向坐标值是一样的。
在Y方向坐标值需要换算,假设LCD的高度是V。
在LCD坐标系中坐标是(x, y),那么它在笛卡尔坐标系中的坐标值为(x, V-y)。
反过来也是一样的,在笛卡尔坐标系中坐标是(x, y),那么它在LCD坐标系中坐标值为(x, V-y)。
##6 .3 .2 每个字符的大小可能不同
在显示一行文字时,这些文字会基于同一个基线来绘制位图:baseline。
在baseline上,每一个字符都有它的原点(origin),比如上图中baseline左边的黑色圆点就是字母“g”的原点。当前origin加上advance就可以得到下一个字符的origin,比如上图中baseline右边的黑色圆点。在显示一行中多个文件字时,后一个文字的原点依赖于前一个文字的原点及advance。
字符的位图是有可能越过baseline的,比如上图中字母“g”在baseline下方还有图像。
上图中红色方框内就是字母“g”所点据的位图,它的四个角落不一定与原点重合。
上图中那些xMin、xMax、yMin、yMax如何获得?可以使用FT_Glyph_Get_CBox函数获得一个字体的这些参数,将会保存在一个FT_BBox结构体中,以后想计算一行文字的外框时要用到这些信息:
##6 .3 .3 怎么在指定位置显示一行文字
怎么在指定位置显示一行文字:
要显示一行文字时,每一个字符都有自己外框:xMin、xMax、yMin、yMax。把这些字符的xMin、yMin中的最小值取出来,把这些字符的xMax、yMax中的最大值取出来,就可以确定这行文字的外框了。
要想在指定位置(x, y)显示一行文字,步骤:
① 先指定第1个字符的原点pen坐标为(0, 0),计算出它的外框
② 再计算右边字符的原点,也计算出它的外框
把所有字符都处理完后就可以得到一行文字的整体外框:假设外框左上角坐标为(x’, y’)。
③ 想在(x, y)处显示这行文字,调整一下pen坐标即可
怎么调整?
pen为(0, 0)时对应左上角(x’, y’);
那么左上角为(x, y)时就可以算出pen为(x-x’, y-y’)。
##6 .3 .4 freetype的几个重要数据结构
- FT_Library
对应freetype库,使用freetype之前要先调用以下代码:
FT_Library library; /* 对应freetype库 /
error = FT_Init_FreeType( &library ); / 初始化freetype库 */ - FT_Face
它对应一个矢量字体文件,在源码中使用FT_New_Face函数打开字体文件后,就可以得到一个face。
代码如下:
error = FT_New_Face(library, font_file, 0, &face ); /* 加载字体文件 */ - FT_GlyphSlot
插槽?用来保存字符的处理结果:比如转换后的glyph、位图,如下图:
一个face中有很多字符,生成一个字符的点阵位图时,位图保存在哪里?保存在插槽中:face->glyph。
生成第1个字符位图时,它保存在face->glyph中;生成第2个字符位图时,也会保存在face->glyph中,会覆盖第1个字符的位图。
代码如下:
FT_GlyphSlot slot = face->glyph; /* 插槽: 字体的处理结果保存在这里 */ - FT_Glyph
字体文件中保存有字符的原始关键点信息,使用freetype的函数可以放大、缩小、旋转,这些新的关键点保存在插槽中(注意:位图也是保存在插槽中)。
新的关键点使用FT_Glyph来表示,可以使用这样的代码从slot中获得glyph:
error = FT_Get_Glyph(slot , &glyph); - FT_BBox
FT_BBox结构体定义如下,它表示一个字符的外框,即新glyph的外框:
可以使用以下代码从glyph中获得这些信息:
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
针对上述流程,示例代码如下:
##6 .3 .5 计算一行文字的外框
前面提到过,一行文字中:后一个字符的原点=前一个字符的原点+advance。
所以要计算一行文字的外框,需要按照排列顺序处理其中的每一个字符。
代码如下:
102 int compute_string_bbox(FT_Face face, wchar_t *wstr, FT_BBox *abbox)
103 {
104 int i;
105 int error;
106 FT_BBox bbox;
107 FT_BBox glyph_bbox;
108 FT_Vector pen;
109 FT_Glyph glyph;
110 FT_GlyphSlot slot = face->glyph;
111
112 /* 初始化 */
113 bbox.xMin = bbox.yMin = 32000;
114 bbox.xMax = bbox.yMax = -32000;
115
116 /* 指定原点为(0, 0) */
117 pen.x = 0;
118 pen.y = 0;
119
120 /* 计算每个字符的bounding box */
121 /* 先translate, 再load char, 就可以得到它的外框了 */
122 for (i = 0; i < wcslen(wstr); i++)
123 {
124 /* 转换:transformation */
125 FT_Set_Transform(face, 0, &pen);
126
127 /* 加载位图: load glyph image into the slot (erase previous one) */
128 error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
129 if (error)
130 {
131 printf("FT_Load_Char error\n");
132 return -1;
133 }
134
135 /* 取出glyph */
136 error = FT_Get_Glyph(face->glyph, &glyph);
137 if (error)
138 {
139 printf("FT_Get_Glyph error!\n");
140 return -1;
141 }
142
143 /* 从glyph得到外框: bbox */
144 FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
145
146 /* 更新外框 */
147 if ( glyph_bbox.xMin < bbox.xMin )
148 bbox.xMin = glyph_bbox.xMin;
149
150 if ( glyph_bbox.yMin < bbox.yMin )
151 bbox.yMin = glyph_bbox.yMin;
152
153 if ( glyph_bbox.xMax > bbox.xMax )
154 bbox.xMax = glyph_bbox.xMax;
155
156 if ( glyph_bbox.yMax > bbox.yMax )
157 bbox.yMax = glyph_bbox.yMax;
158
159 /* 计算下一个字符的原点: increment pen position */
160 pen.x += slot->advance.x;
161 pen.y += slot->advance.y;
162 }
163
164 /* return string bbox */
165 *abbox = bbox;
166 }
##6 .3 .6 调整原点并绘制
169 int display_string(FT_Face face, wchar_t *wstr, int lcd_x, int lcd_y)
170 {
171 int i;
172 int error;
173 FT_BBox bbox;
174 FT_Vector pen;
175 FT_Glyph glyph;
176 FT_GlyphSlot slot = face->glyph;
177
178 /* 把LCD坐标转换为笛卡尔坐标 */
179 int x = lcd_x;
180 int y = var.yres - lcd_y;
181
182 /* 计算外框 */
183 compute_string_bbox(face, wstr, &bbox);
184
185 /* 反推原点 */
186 pen.x = (x - bbox.xMin) * 64; /* 单位: 1/64像素 */
187 pen.y = (y - bbox.yMax) * 64; /* 单位: 1/64像素 */
188
189 /* 处理每个字符 */
190 for (i = 0; i < wcslen(wstr); i++)
191 {
192 /* 转换:transformation */
193 FT_Set_Transform(face, 0, &pen);
194
195 /* 加载位图: load glyph image into the slot (erase previous one) */
196 error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
197 if (error)
198 {
199 printf("FT_Load_Char error\n");
200 return -1;
201 }
202
203 /* 在LCD上绘制: 使用LCD坐标 */
204 draw_bitmap( &slot->bitmap,
205 slot->bitmap_left,
206 var.yres - slot->bitmap_top);
207
208 /* 计算下一个字符的原点: increment pen position */
209 pen.x += slot->advance.x;
210 pen.y += slot->advance.y;
211 }
212
213 return 0;
214 }
##6 .3 .7 完整代码
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
int fd_fb;
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
/* color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
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:
{
/* 565 */
red = (color >> 16) & 0xff;
green = (color >> 8) & 0xff;
blue = (color >> 0) & 0xff;
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
/********************************************************************** * 函数名称: draw_bitmap * 功能描述: 根据bitmap位图,在LCD指定位置显示汉字 * 输入参数: x坐标,y坐标,位图指针 ***********************************************************************/
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 ( j = y, q = 0; j < y_max; j++, q++ )
{
for ( i = x, p = 0; i < x_max; i++, p++ )
{
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 compute_string_bbox(FT_Face face, wchar_t *wstr, FT_BBox *abbox)
{
int i;
int error;
FT_BBox bbox;
FT_BBox glyph_bbox;
FT_Vector pen;
FT_Glyph glyph;
FT_GlyphSlot slot = face->glyph;
/* 初始化 */
bbox.xMin = bbox.yMin = 32000;
bbox.xMax = bbox.yMax = -32000;
/* 指定原点为(0, 0) */
pen.x = 0;
pen.y = 0;
/* 计算每个字符的bounding box */
/* 先translate, 再load char, 就可以得到它的外框了 */
for (i = 0; i < wcslen(wstr); i++)
{
/* 转换:transformation */
FT_Set_Transform(face, 0, &pen);
/* 加载位图: load glyph image into the slot (erase previous one) */
error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
/* 取出glyph */
error = FT_Get_Glyph(face->glyph, &glyph);
if (error)
{
printf("FT_Get_Glyph error!\n");
return -1;
}
/* 从glyph得到外框: bbox */
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
/* 更新外框 */
if ( glyph_bbox.xMin < bbox.xMin )
bbox.xMin = glyph_bbox.xMin;
if ( glyph_bbox.yMin < bbox.yMin )
bbox.yMin = glyph_bbox.yMin;
if ( glyph_bbox.xMax > bbox.xMax )
bbox.xMax = glyph_bbox.xMax;
if ( glyph_bbox.yMax > bbox.yMax )
bbox.yMax = glyph_bbox.yMax;
/* 计算下一个字符的原点: increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
/* return string bbox */
*abbox = bbox;
}
int display_string(FT_Face face, wchar_t *wstr, int lcd_x, int lcd_y)
{
int i;
int error;
FT_BBox bbox;
FT_Vector pen;
FT_Glyph glyph;
FT_GlyphSlot slot = face->glyph;
/* 把LCD坐标转换为笛卡尔坐标 */
int x = lcd_x;
int y = var.yres - lcd_y;
/* 计算外框 */
compute_string_bbox(face, wstr, &bbox);
/* 反推原点 */
pen.x = (x - bbox.xMin) * 64; /* 单位: 1/64像素 */
pen.y = (y - bbox.yMax) * 64; /* 单位: 1/64像素 */
/* 处理每个字符 */
for (i = 0; i < wcslen(wstr); i++)
{
/* 转换:transformation */
FT_Set_Transform(face, 0, &pen);
/* 加载位图: load glyph image into the slot (erase previous one) */
error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
/* 在LCD上绘制: 使用LCD坐标 */
draw_bitmap( &slot->bitmap,
slot->bitmap_left,
var.yres - slot->bitmap_top);
/* 计算下一个字符的原点: increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
return 0;
}
int main(int argc, char **argv)
{
wchar_t *wstr = L"yiyi.net"; //要显示的字符
FT_Library library;
FT_Face face;
int error;
FT_BBox bbox;
int font_size = 24;
int lcd_x, lcd_y;
if (argc < 4)
{
printf("Usage : %s <font_file> <lcd_x> <lcd_y> [font_size]\n", argv[0]);
return -1;
}
lcd_x = strtoul(argv[2], NULL, 0);
lcd_y = strtoul(argv[3], NULL, 0);
if (argc == 5)
font_size = strtoul(argv[4], NULL, 0);
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
{
printf("can't get fix\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * 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't mmap\n");
return -1;
}
/* 清屏: 全部设为黑色 */
memset(fbmem, 0, screen_size);
error = FT_Init_FreeType( &library ); /* 初始化字体库 */
error = FT_New_Face( library, argv[1], 0, &face ); /* 加载字体文件*/
FT_Set_Pixel_Sizes(face, font_size, 0); /*设置字体大小 */
display_string(face, wstr, lcd_x, lcd_y); /*显示一行字体 */
return 0;
}
交叉编译完成后将可执行程序与字体文件拷贝至开发板,运行程序时指定字体文件、坐标原点、字体大小可观察到一行蓝色文字。
边栏推荐
- [Database and SQL study notes] 8. Views in SQL
- AIDL detailed explanation
- Tensorflow steps on the pit notes and records various errors and solutions
- Detailed explanation of BroadCast Receiver (broadcast)
- CVPR 2022 | 70% memory savings, 2x faster training
- SharedPreferences and SQlite database
- You should write like this
- 服务网格istio 1.12.x安装
- 基于STM32F407的WIFI通信(使用的是ESP8266模块)
- 【ts】typescript高阶:模版字面量类型
猜你喜欢
Redis设计与实现(第一部分):数据结构与对象
1008 数组元素循环右移问题 (20 分)
【Pytorch学习笔记】11.取Dataset的子集、给Dataset打乱顺序的方法(使用Subset、random_split)
读论文- pix2pix
【数据库和SQL学习笔记】9.(T-SQL语言)定义变量、高级查询、流程控制(条件、循环等)
【论文阅读-表情捕捉】ExpNet: Landmark-Free, Deep, 3D Facial Expressions
读论文 - Unpaired Portrait Drawing Generation via Asymmetric Cycle Mapping
Tensorflow2 与 Pytorch 在张量Tensor基础操作方面的对比整理汇总
Redis集群(docker版)——从原理到实战超详细
五、请求处理—Rest映射是怎样实现的?
随机推荐
MySQL
MySQL主从复制—有手就能学会的MySQL集群搭建教程
华科提出首个用于伪装实例分割的一阶段框架OSFormer
神经网络也能像人类利用外围视觉一样观察图像
Redis集群(docker版)——从原理到实战超详细
[Pytorch study notes] 9. How to evaluate the classification results of the classifier - using confusion matrix, F1-score, ROC curve, PR curve, etc. (taking Softmax binary classification as an example)
SQL (2) - join window function view
对象比较
11%的参数就能优于Swin,微软提出快速预训练蒸馏方法TinyViT
【Over 15】A week of learning lstm
BroadCast Receiver(广播)详解
【数据库和SQL学习笔记】7.SQL中的插入(INSERT)、删除(DELETE)、更新(UPDATE)
【ts】typescript高阶:typeof使用
【数据库和SQL学习笔记】6.SELECT查询4:嵌套查询、对查询结果进行操作
MSRA提出学习实例和分布式视觉表示的极端掩蔽模型ExtreMA
常见的 PoE 错误和解决方案
Redis设计与实现(第二部分):单机数据库的实现
用GAN的方法来进行图片匹配!休斯顿大学提出用于文本图像匹配的对抗表示学习,消除模态差异!
读论文 - Unpaired Portrait Drawing Generation via Asymmetric Cycle Mapping
【shell编程】第三章:函数