字体(Fonts)

在LVGL中,字体是位图和呈现字母(字形)图像所需的其他信息的集合。字体存储在 lv_font_t 变量中,可以在样式的text_font字段中进行设置。例如:

1    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。(这是默认值) 测试一下试试:

1    lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL);
2    lv_label_set_text(label1, LV_SYMBOL_OK);

如果一切正常,则应显示一个 ✓ 字符。

内置字体

有几种不同大小的内置字体,可以通过 LV_FONT _… 定义在 lv_conf.h 中启用。

普通字体

包含所有ASCII字符,度数符号(U + 00B0),项目符号(U + 2022)和内置符号(请参见下文)。

  • LV_FONT_MONTSERRAT_12 12 px font

  • LV_FONT_MONTSERRAT_14 14 px font

  • LV_FONT_MONTSERRAT_16 16 px font

  • LV_FONT_MONTSERRAT_18 18 px font

  • LV_FONT_MONTSERRAT_20 20 px font

  • LV_FONT_MONTSERRAT_22 22 px font

  • LV_FONT_MONTSERRAT_24 24 px font

  • LV_FONT_MONTSERRAT_26 26 px font

  • LV_FONT_MONTSERRAT_28 28 px font

  • LV_FONT_MONTSERRAT_30 30 px font

  • LV_FONT_MONTSERRAT_32 32 px font

  • LV_FONT_MONTSERRAT_34 34 px font

  • LV_FONT_MONTSERRAT_36 36 px font

  • LV_FONT_MONTSERRAT_38 38 px font

  • LV_FONT_MONTSERRAT_40 40 px font

  • LV_FONT_MONTSERRAT_42 42 px font

  • LV_FONT_MONTSERRAT_44 44 px font

  • LV_FONT_MONTSERRAT_46 46 px font

  • LV_FONT_MONTSERRAT_48 48 px font

特殊字体

  • LV_FONT_MONTSERRAT_12_SUBPX 与常规12像素字体相同,但具有亚像素渲染

  • LV_FONT_MONTSERRAT_28_COMPRESSED 与普通的28 px字体相同,但压缩字体为3 bpp

  • LV_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 字体添加到内置字体中。

http://photos.100ask.net/lvgl/03_overview/07_font/01_symbols.png

LVGL的内置符号

这些符号可以这样使用:

1    lv_label_set_text(my_label, LV_SYMBOL_OK);

或与字符串一起使用:

1    lv_label_set_text(my_label, LV_SYMBOL_OK "Apply");

或更多个符号一起使用:

1    lv_label_set_text(my_label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY);

特殊功能

双向支持

大多数语言使用从左到右(简称LTR)的书写方向,但是某些语言(例如希伯来语,波斯语或阿拉伯语)使用从右到左(简称RTL)的书写方向。

LVGL不仅支持RTL文本,而且还支持混合(又称双向,BiDi)文本渲染。一些例子:

http://photos.100ask.net/lvgl/03_overview/07_font/02_bidi.png

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 left

  • lv_checkbox : Show the box on the right

  • lv_btnmatrix: Show buttons from right to left

  • lv_list: Show the icon on the right

  • lv_dropdown : Align the options to the right

  • lv_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%。因此,建议仅压缩用户界面的最大字体,因为  - 他们需要最多的内存 - 他们可以更好地压缩 - 并且它们的使用频率可能不如中等大小的字体。(因此性能成本较小)

添加新字体

有几种方法可以向项目中添加新字体:

  1. 最简单的方法是使用在线字体转换器(https://lvgl.io/tools/fontconverter)。只需设置参数,单击“转换”按钮,将字体复制到的项目中并使用它。请务必仔细阅读该网站上提供的步骤,否则转换时会出错。

  2. 使用脱机字体转换器(https://github.com/lvgl/lv_font_conv)。 (需要安装Node.js)

  3. 如果要创建类似内置字体(Roboto字体和符号)但大小和/或范围不同的东西,可以在 lvgl/scripts/built_in_font 文件夹中使用 built_in_font_gen.py 脚本。(它需要安装 Pythonlv_font_conv

要在文件中声明字体,请使用 LV_FONT_DECLARE(my_font_name)

要使字体在全局范围内可用(如内置字体),请将它们添加到 lv_conf.h 中的 LV_FONT_CUSTOM_DECLARE 中。

添加新符号

内置符号是从FontAwesome字体创建的。

  1. 在https://fontawesome.com上搜索符号。例如USB符号。复制它的Unicode ID,在这种情况下为 0xf287

  2. 打开在线字体转换器。添加添加FontAwesome.woff。 。

  3. 设置名称,大小, BPP 等参数。将使用此名称在代码中声明和使用字体。

  4. 将符号的 Unicode ID 添加到范围字段。例如。 USB 符号为 0xf287 。可以用,枚举更多符号。

  5. 转换字体并将其复制到的项目。确保编译字体的.c文件。

  6. 使用 extern lv_font_t my_font_name11 声明字体;或者只是 ``LV_FONT_DECLARE(my_font_name) ;。

使用符号

  1. 将Unicode值转换为UTF8。可以在此网站上进行操作。对于 0xf287 ,十六进制 UTF-8 字节为 EF 8A 87

  2. 根据UTF8值创建定义: #define MY_USB_SYMBOL "\xEF\x8A\x87"

  3. 创建一个标签并设置文本。例如: 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的文件系统,并需要添加驱动程序。

范例:

1    lv_font_t * my_font;
2    my_font = lv_font_load(X/path/to/my_font.bin);
3
4    /*Use the font*/
5
6    /*Free the font if not required anymore*/
7    lv_font_free(my_font);

添加新的字体引擎

LVGL的字体界面设计得非常灵活。不需要使用LVGL的内部字体引擎,但可以添加自己的字体。例如,使用 FreeType 从TTF字体实时渲染字形,或使用外部闪存存储字体的位图,并在库需要它们时读取它们。

可以在 lv_freetype库 中找到使用FreeType的传统。

为此,需要创建一个自定义 lv_font_t 变量:

 1    /*Describe the properties of a font*/
 2    lv_font_t my_font;
 3    my_font.get_glyph_dsc = my_get_glyph_dsc_cb;        /*Set a callback to get info about gylphs*/
 4    my_font.get_glyph_bitmap = my_get_glyph_bitmap_cb;  /*Set a callback to get bitmap of a glyp*/
 5    my_font.line_height = height;                       /*The real line height where any text fits*/
 6    my_font.base_line = base_line;                      /*Base line measured from the top of line_height*/
 7    my_font.dsc = something_required;                   /*Store any implementation specific data here*/
 8    my_font.user_data = user_data;                      /*Optionally some extra user data*/
 9
10    ...
11
12    /* Get info about glyph of `unicode_letter` in `font` font.
13     * Store the result in `dsc_out`.
14     * The next letter (`unicode_letter_next`) might be used to calculate the width required by this glyph (kerning)
15     */
16    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)
17    {
18            /*Your code here*/
19
20            /* Store the result.
21             * For example ...
22             */
23            dsc_out->adv_w = 12;        /*Horizontal space required by the glyph in [px]*/
24            dsc_out->box_h = 8;         /*Height of the bitmap in [px]*/
25            dsc_out->box_w = 6;         /*Width of the bitmap in [px]*/
26            dsc_out->ofs_x = 0;         /*X offset of the bitmap in [pf]*/
27            dsc_out->ofs_y = 3;         /*Y offset of the bitmap measured from the as line*/
28            dsc_out->bpp   = 2;         /*Bits per pixel: 1/2/4/8*/
29
30            return true;                /*true: glyph found; false: glyph was not found*/
31    }
32
33    /* Get the bitmap of `unicode_letter` from `font`. */
34    const uint8_t * my_get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter)
35    {
36            /* Your code here */
37
38            /* The bitmap should be a continuous bitstream where
39             * each pixel is represented by `bpp` bits */
40
41            return bitmap;    /*Or NULL if not found*/
42    }

相关API

TODO