字体(Fonts),在LVGL中,字体是位图和呈现字母(字形)图像所需的其他信息的集合。字体存储在 lv_font_t
变量中,可以在样式的text_font字段中进行设置。例如:
lv_style_set_text_font(&my_style, LV_STATE_DEFAULT, &lv_font_montserrat_28); /*Set a larger font*/
字体具有 bpp(每像素位数) 属性。它显示了多少位用于描述字体中的像素。为像素存储的值确定像素的不透明度。这样,如果bpp较高,则字母的边缘可以更平滑。可能的bpp值是1、2、4和8(值越高表示质量越好)。
bpp还会影响存储字体所需的内存大小。例如,bpp = 4使字体比bpp = 1大近4倍。
Unicode支持
LVGL支持 UTF-8 编码的Unicode字符。需要配置的编辑器,以将的代码/文本保存为 UTF-8 (通常是默认值),并确保在 lv_conf.h 中将 LV_TXT_ENC
其设置为: LV_TXT_ENC_UTF8
。(这是默认值) 测试一下试试:
lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label1, LV_SYMBOL_OK);
如果一切正常,则应显示一个 ✓ 字符。
内置字体
有几种不同大小的内置字体,可以通过 LVFONT … 定义在 lv_conf.h
中启用。
普通字体
包含所有ASCII字符,度数符号(U + 00B0),项目符号(U + 2022)和内置符号(请参见下文)。
LV_FONT_MONTSERRAT_12
12 px fontLV_FONT_MONTSERRAT_14
14 px fontLV_FONT_MONTSERRAT_16
16 px fontLV_FONT_MONTSERRAT_18
18 px fontLV_FONT_MONTSERRAT_20
20 px fontLV_FONT_MONTSERRAT_22
22 px fontLV_FONT_MONTSERRAT_24
24 px fontLV_FONT_MONTSERRAT_26
26 px fontLV_FONT_MONTSERRAT_28
28 px fontLV_FONT_MONTSERRAT_30
30 px fontLV_FONT_MONTSERRAT_32
32 px fontLV_FONT_MONTSERRAT_34
34 px fontLV_FONT_MONTSERRAT_36
36 px fontLV_FONT_MONTSERRAT_38
38 px fontLV_FONT_MONTSERRAT_40
40 px fontLV_FONT_MONTSERRAT_42
42 px fontLV_FONT_MONTSERRAT_44
44 px fontLV_FONT_MONTSERRAT_46
46 px fontLV_FONT_MONTSERRAT_48
48 px font
特殊字体
LV_FONT_MONTSERRAT_12_SUBPX
与常规12像素字体相同,但具有亚像素渲染LV_FONT_MONTSERRAT_28_COMPRESSED
与普通的28 px字体相同,但压缩字体为3 bppLV_FONT_DEJAVU_16_PERSIAN_HEBREW
正常范围内的16像素字体+希伯来语,阿拉伯语,Perisan字母及其所有形式LV_FONT_SIMSUN_16_CJK
16 px字体,具有正常范围+ 1000个最常见的CJK部首LV_FONT_UNSCII_8
仅包含ASCII字符的8 px像素完美字体
内置字体是全局变量,其名称像 lv_font_montserrat_16
一样,代表 16 px 高的字体。要以某种样式使用它们,只需添加一个指向如上所示的字体变量的指针。
内置字体的 bpp = 4,包含 ASCII 字符并使用 Montserrat 字体。
除了 ASCII 范围,以下符号也从 FontAwesome 字体添加到内置字体中。
LVGL的内置符号
这些符号可以这样使用:
lv_label_set_text(my_label, LV_SYMBOL_OK);
或与字符串一起使用:
lv_label_set_text(my_label, LV_SYMBOL_OK "Apply");
或更多个符号一起使用:
lv_label_set_text(my_label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY);
特殊功能
双向支持
大多数语言使用从左到右(简称LTR)的书写方向,但是某些语言(例如希伯来语,波斯语或阿拉伯语)使用从右到左(简称RTL)的书写方向。
LVGL不仅支持RTL文本,而且还支持混合(又称双向,BiDi)文本渲染。一些例子:
LVGL的双向文字范例
可以通过lv_conf.h中的 LV_USE_BIDI
启用 BiDi 支持
所有文本都有一个基本方向(LTR或RTL),该方向确定一些渲染规则和文本的默认对齐方式(左或右)。但是,在LVGL中,基本方向不仅适用于标签。这是可以为每个对象设置的常规属性。如果未设置,则它将从父级继承。因此,设置屏幕的基本方向就足够了,每个对象都会继承它。
屏幕的默认基本方向可以通过 lv_conf.h 中的 LV_BIDI_BASE_DIR_DEF
设置,其他对象从其父对象继承基本方向。
要设置对象的基本方向,请使用 lv_obj_set_base_dir(obj, base_dir)
。可能的基本方向是:
- LV_BIDI_DIR_LTR: 从左到右基本方向
- LV_BIDI_DIR_RTL: 从右到左基本方向
- LV_BIDI_DIR_AUTO: A自动检测基准方向
- LV_BIDI_DIR_INHERIT: 从父级继承基本方向(非屏幕对象的默认方向)
此列表总结了RTL基本方向对对象的影响:
默认情况下在右侧创建对象
lv_tabview
: displays tabs from right to leftlv_checkbox
: Show the box on the rightlv_btnmatrix
: Show buttons from right to leftlv_list
: Show the icon on the rightlv_dropdown
: Align the options to the rightlv_table
,lv_btnmatrix
,lv_keyboard
,lv_tabview
,lv_dropdown
,lv_roller
中的文本为“ BiDi处理”,可以正确显示
阿拉伯语和波斯语支持
显示阿拉伯字符和波斯字符有一些特殊规则:字符的形式取决于它们在文本中的位置。如果隔离,开始,中间或结束位置,则需要使用同一字母的不同形式。除了这些合取规则外,还应考虑其他规则。
如果启用了 LV_USE_ARABIC_PERSIAN_CHARS
,则 LVGL 支持应用这些规则。
但是,存在一些限制:
- 仅支持显示文本(例如在标签上),文本输入(例如文本区域)不支持此功能
- 静态文本(即const)不会被处理。例如,由
lv_label_set_text()
设置的文本将被处理为“阿拉伯语”,但lv_lable_set_text_static()
不会。 - 文本获取函数(例如
lv_label_get_text()
)将返回处理后的文本。
亚像素渲染
亚像素渲染意味着通过在红色,绿色和蓝色通道而不是像素级别上渲染将水平分辨率提高三倍。它利用了每个像素的物理颜色通道的位置。这样可以产生更高质量的字母抗锯齿。在这里学习更多。 亚像素渲染需要生成具有特殊设置的字体:
- 在网络转换器勾选
Subpixel
框 - 在命令行工具中使用
--lcd
标志。请注意,生成的字体大约需要3倍的内存。
仅当像素的颜色通道具有水平布局时,子像素渲染才有效。也就是说,R,G,B通道彼此相邻而不位于彼此之上。颜色通道的顺序也需要与库设置匹配。默认情况下,LVGL 采用 RGB
顺序,但是可以通过在 lv_conf.h 中将 LV_SUBPX_BGR
设置为 1 来交换它。
压缩字体
- 字体的位图可以通过以下方式压缩
- 勾选
Compressed
在线转换器中的复选框 - 不将
--no-compress
标志传递给脱机转换器(默认情况下应用压缩)
较大的字体和较高的bpp压缩更有效。但是,渲染压缩字体的速度要慢30%。因此,建议仅压缩用户界面的最大字体,因为 – 他们需要最多的内存 – 他们可以更好地压缩 – 并且它们的使用频率可能不如中等大小的字体。(因此性能成本较小)
添加新字体
有几种方法可以向项目中添加新字体:
- 最简单的方法是使用在线字体转换器(https://lvgl.io/tools/fontconverter)。只需设置参数,单击“转换”按钮,将字体复制到的项目中并使用它。**请务必仔细阅读该网站上提供的步骤,否则转换时会出错。**
- 使用脱机字体转换器(https://github.com/lvgl/lv_font_conv)。 (需要安装Node.js)
- 如果要创建类似内置字体(Roboto字体和符号)但大小和/或范围不同的东西,可以在
lvgl/scripts/built_in_font
文件夹中使用built_in_font_gen.py
脚本。(它需要安装Python
和lv_font_conv
)
要在文件中声明字体,请使用 LV_FONT_DECLARE(my_font_name)
。
要使字体在全局范围内可用(如内置字体),请将它们添加到 lv_conf.h 中的 LV_FONT_CUSTOM_DECLARE
中。
添加新符号
内置符号是从FontAwesome字体创建的。
- 在https://fontawesome.com上搜索符号。例如USB符号。复制它的Unicode ID,在这种情况下为
0xf287
。 - 打开在线字体转换器。添加添加FontAwesome.woff。 。
- 设置名称,大小, BPP 等参数。将使用此名称在代码中声明和使用字体。
- 将符号的 Unicode ID 添加到范围字段。例如。 USB 符号为
0xf287
。可以用,枚举更多符号。 - 转换字体并将其复制到的项目。确保编译字体的.c文件。
- 使用
extern lv_font_t my_font_name11 声明字体;或者只是
LV_FONT_DECLARE(my_font_name)
;。
使用符号
- 将Unicode值转换为UTF8。可以在此网站上进行操作。对于
0xf287
,十六进制 UTF-8 字节为EF 8A 87
。 - 根据UTF8值创建定义:
#define MY_USB_SYMBOL "\xEF\x8A\x87"
- 创建一个标签并设置文本。例如:
lv_label_set_text(label, MY_USB_SYMBOL)
注- lv_label_set_text(label, MY_USB_SYMBOL)
使用 `style.text.font
属性中定义的字体搜索此符号。要使用该符号,可能需要对其进行更改。例如 style.text.font = my_font_name
在运行时加载字体
lv_font_load
可用于从文件中加载字体。要加载的字体需要具有特殊的二进制格式。 (不是TTF或WOFF)。使用带有 --format bin
选项的 lv_font_conv 生成与LVGL兼容的字体文件。
请注意,要加载字体,需要启用 LVGL的文件系统,并需要添加驱动程序。
范例:
lv_font_t * my_font;
my_font = lv_font_load(X/path/to/my_font.bin);
/*Use the font*/
/*Free the font if not required anymore*/
lv_font_free(my_font);
添加新的字体引擎
LVGL的字体界面设计得非常灵活。不需要使用LVGL的内部字体引擎,但可以添加自己的字体。例如,使用 FreeType 从TTF字体实时渲染字形,或使用外部闪存存储字体的位图,并在库需要它们时读取它们。
可以在 lv_freetype库 中找到使用FreeType的传统。
为此,需要创建一个自定义 lv_font_t
变量:
/*Describe the properties of a font*/
lv_font_t my_font;
my_font.get_glyph_dsc = my_get_glyph_dsc_cb; /*Set a callback to get info about gylphs*/
my_font.get_glyph_bitmap = my_get_glyph_bitmap_cb; /*Set a callback to get bitmap of a glyp*/
my_font.line_height = height; /*The real line height where any text fits*/
my_font.base_line = base_line; /*Base line measured from the top of line_height*/
my_font.dsc = something_required; /*Store any implementation specific data here*/
my_font.user_data = user_data; /*Optionally some extra user data*/
...
/* Get info about glyph of `unicode_letter` in `font` font.
* Store the result in `dsc_out`.
* The next letter (`unicode_letter_next`) might be used to calculate the width required by this glyph (kerning)
*/
bool my_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
{
/*Your code here*/
/* Store the result.
* For example ...
*/
dsc_out->adv_w = 12; /*Horizontal space required by the glyph in [px]*/
dsc_out->box_h = 8; /*Height of the bitmap in [px]*/
dsc_out->box_w = 6; /*Width of the bitmap in [px]*/
dsc_out->ofs_x = 0; /*X offset of the bitmap in [pf]*/
dsc_out->ofs_y = 3; /*Y offset of the bitmap measured from the as line*/
dsc_out->bpp = 2; /*Bits per pixel: 1/2/4/8*/
return true; /*true: glyph found; false: glyph was not found*/
}
/* Get the bitmap of `unicode_letter` from `font`. */
const uint8_t * my_get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter)
{
/* Your code here */
/* The bitmap should be a continuous bitstream where
* each pixel is represented by `bpp` bits */
return bitmap; /*Or NULL if not found*/
}