字体

1. 支持的字体

Solution 当前支持以下字体能力:

  1. 提供两种字体实现方式:点阵字体(bitmap)和 FreeType 字体。

  2. 点阵字体支持 LVGL 生成的 bitmap 格式。

  3. FreeType 字体当前仅支持 .ttf 格式。

  4. 支持同时使用多个 bitmap 字体和多个 FreeType 字体。

  5. 支持标准 Emoji。

  6. 支持为指定对象(obj)固定字体。

  7. 提供可免费使用的 tiny 压缩字体,字重为 55,支持 27000+ 简繁体汉字,占用空间约 1.06 MB。

  8. 提供可免费使用的印地语变形(shape)支持,包含以下语种:

语言

Language

印地语

Hindi

马拉地语

Marathi

梵语

Sanskrit

尼泊尔语

Nepali

迈蒂利语

Maithili

孔卡尼语

Konkani

多格拉语

Dogri

博多语

Bodo

  1. Solution V2.6.0 及以后版本可通过打开 PKG_USING_HARFBUZZ 宏支持以下已适配语种的变形(shape):

文字系统

已适配语种

Language

Devanagari

印地语、马拉地语、尼泊尔语

Hindi, Marathi, Nepali

Bengali

孟加拉语、阿萨姆语

Bengali, Assamese

Gurmukhi

旁遮普语

Punjabi

Gujarati

古吉拉特语

Gujarati

Oriya/Odia

奥里亚语

Odia

Tamil

泰米尔语

Tamil

Telugu

泰卢固语

Telugu

Kannada

卡纳达语

Kannada

Malayalam

马拉雅拉姆语

Malayalam

Sinhala

僧伽罗语

Sinhala

Thai

泰语

Thai

Lao

老挝语

Lao

Khmer

高棉语

Khmer

Myanmar

缅甸语

Burmese

Tibetan

藏语

Tibetan

Mongolian

蒙古语

Mongolian

Arabic

阿拉伯语、波斯语、乌尔都语

Arabic, Persian/Farsi, Urdu

Hebrew

希伯来语

Hebrew

Syriac

叙利亚语

Syriac

说明: 使用 Solution V2.6.0 及以后版本新增的语种变形能力时,需要使能 FreeType,并打开 PKG_USING_HARFBUZZ 宏;USE_HARFBUZZ_HINDI_SHAPER 为隐藏自动项,在依赖满足后会默认开启,无需用户单独打开。Code Size 需要增加 850KB。字体本身仍需包含对应语种的 glyph 以及 GSUB/GPOS 等 OpenType 数据。如果需要支持其他需要 shape 的语言,需由客户自行提供支持变形算法及对应 .ttf 的方案。

2. 字体放置目录

在 Solution 方案中,资源统一存放在 resource 目录下,字体文件需要放在 resource/fonts 目录中。

3. .ttf 字体的增删

  1. 新增字体:将新的 .ttf 文件放到具体产品工程的 resource/fonts/freetype 目录下,例如 solution/examples/watch/resource/fonts/freetype

  2. 调整顺序:编辑 ttf_order.txt,将新增字体加入文件并设置顺序。UI 显示文字时,会按照 ttf_order.txt 中的顺序遍历字体并查找字形。

  3. 删除字体:删除对应的 .ttf 文件即可。

4. .ttf 字体选择

可通过 Butterfli 工具的 UI 选择需要参与编译的字体。

⚠️ 注意

具体产品工程的 resource/fonts/freetype 目录(例如 solution/examples/watch/resource/fonts/freetype)下,除 _tiny55_full_tiny55_litehindi_ttf 外,其余 .ttf 字体仅用于功能展示。若客户需要商用,请务必确认字体版权。

5. .ttf 字号设置

5.1 默认字号

lvsf_font.h 中定义了默认字号,可通过修改对应宏进行调整。

5.2 自定义字号

如果项目需要使用不同字号,可按以下步骤配置:

  1. solution/framework/__template__/project 目录中复制子目录 __applicaiton_private__ 到对应的 HCPU 和 Simulator 目录。

  2. menuconfig 中使能 FT_SIZE_SELF_DEFINED

  3. 修改 __applicaiton_private__/ft_size_custom_reg.h 中的字号定义。

ft_size_custom_reg.h 示例:

/**
 * @brief  Register fonts through this interface.
 *         The font size must be arranged from small to large.
 *         Because font is searched from small to large.
 */
#ifdef FT_SIZE_SELF_DEFINED

typedef enum
{
    FONT_SMALL      = 16,
    FONT_NORMAL     = 20,
    FONT_SUBTITLE   = 24,
    FONT_TITLE      = 28,
    FONT_BIGL       = 36,
    FONT_HUGE       = 56,
    FONT_SUPER      = 72,
} FONT_SIZES;

#define LVSF_FREETYPE_FONT_REGISTER(freetype_font)                          \
    extern lv_font_freetype_lib_dsc_t CONCAT_2(freetype_font, _lib);        \
    SECTION_ITEM_REGISTER(FONT_SECTION_NAME, static const font_desc_t CONCAT_2(freetype_font, _reg_list)[]) =     \
    {                                                                       \
        LVSF_FONT_REGISTER(freetype_font, 10),                              \
        LVSF_FONT_REGISTER(freetype_font, 11),                              \
        LVSF_FONT_REGISTER(freetype_font, 12),                              \
        LVSF_FONT_REGISTER(freetype_font, 13),                              \
        LVSF_FONT_REGISTER(freetype_font, 14),                              \
        LVSF_FONT_REGISTER(freetype_font, 15),                              \
        LVSF_FONT_REGISTER(freetype_font, 16),                              \
        LVSF_FONT_REGISTER(freetype_font, 17),                              \
        LVSF_FONT_REGISTER(freetype_font, 18),                              \
        LVSF_FONT_REGISTER(freetype_font, 19),                              \
        LVSF_FONT_REGISTER(freetype_font, 20),                              \
        LVSF_FONT_REGISTER(freetype_font, 21),                              \
        LVSF_FONT_REGISTER(freetype_font, 22),                              \
        LVSF_FONT_REGISTER(freetype_font, 23),                              \
        LVSF_FONT_REGISTER(freetype_font, 24),                              \
        LVSF_FONT_REGISTER(freetype_font, 25),                              \
        LVSF_FONT_REGISTER(freetype_font, 26),                              \
        LVSF_FONT_REGISTER(freetype_font, 27),                              \
        LVSF_FONT_REGISTER(freetype_font, 28),                              \
        LVSF_FONT_REGISTER(freetype_font, 29),                              \
        LVSF_FONT_REGISTER(freetype_font, 30),                              \
        LVSF_FONT_REGISTER(freetype_font, 31),                              \
        LVSF_FONT_REGISTER(freetype_font, 32),                              \
        LVSF_FONT_REGISTER(freetype_font, 33),                              \
        LVSF_FONT_REGISTER(freetype_font, 34),                              \
        LVSF_FONT_REGISTER(freetype_font, 35),                              \
        LVSF_FONT_REGISTER(freetype_font, 36),                              \
        LVSF_FONT_REGISTER(freetype_font, 37),                              \
        LVSF_FONT_REGISTER(freetype_font, 38),                              \
        LVSF_FONT_REGISTER(freetype_font, 39),                              \
        LVSF_FONT_REGISTER(freetype_font, 40),                              \
        LVSF_FONT_REGISTER(freetype_font, 41),                              \
        LVSF_FONT_REGISTER(freetype_font, 42),                              \
        LVSF_FONT_REGISTER(freetype_font, 43),                              \
        LVSF_FONT_REGISTER(freetype_font, 44),                              \
        LVSF_FONT_REGISTER(freetype_font, 45),                              \
        LVSF_FONT_REGISTER(freetype_font, 46),                              \
        LVSF_FONT_REGISTER(freetype_font, 47),                              \
        LVSF_FONT_REGISTER(freetype_font, 48),                              \
        LVSF_FONT_REGISTER(freetype_font, 49),                              \
        LVSF_FONT_REGISTER(freetype_font, 50),                              \
        LVSF_FONT_REGISTER(freetype_font, 51),                              \
        LVSF_FONT_REGISTER(freetype_font, 52),                              \
        LVSF_FONT_REGISTER(freetype_font, 53),                              \
        LVSF_FONT_REGISTER(freetype_font, 54),                              \
        LVSF_FONT_REGISTER(freetype_font, 55),                              \
        LVSF_FONT_REGISTER(freetype_font, 56),                              \
        LVSF_FONT_REGISTER(freetype_font, 57),                              \
        LVSF_FONT_REGISTER(freetype_font, 58),                              \
        LVSF_FONT_REGISTER(freetype_font, 59),                              \
        LVSF_FONT_REGISTER(freetype_font, 60),                              \
    };

#endif

6. Emoji 字体的增删

  1. 新增 Emoji:将新增的 Emoji 图片放在具体产品工程的 resource/images_emoji/common/ezip 目录下,例如 solution/examples/watch/resource/images_emoji/common/ezip

    • 图片命名格式必须为 emoji_xxx.png

    • 其中 xxx 为 Emoji 的 Unicode 编码。

    • 例如,Unicode 为 1f46d 的 Emoji,应命名为 emoji_1f46d.png

  2. 删除 Emoji:删除对应图片即可。

7. 字体显示流程

为支持多语言,通常需要多个 .ttf 组合使用,才能覆盖全部语言字符。字体显示流程如下:

  1. 设置字体(.ttf)顺序,并注册字体链表 font_list

  2. 创建空的缓存链表 cache_list

  3. 按照文本中的每个 Unicode 逐个获取 bitmap。

    • 如果在 cache_list 中找到对应 Unicode 的 bitmap,则直接调用 lv_draw_letter 显示。

    • 如果未找到,则先存入 cache_list,再调用 lv_draw_letter 显示。

    • 如果存入时发现超出缓存容量,则会清除部分缓存后再继续写入。

  4. 显示速度取决于:

    • 该 Unicode 位于 font_list 中靠前还是靠后;

    • 该字形是否已经命中 cache_list

也就是说,如果 Unicode 对应字形位于前面的字体中,或者能够在缓存中直接命中,则显示速度更快;否则需要进入 FreeType 查找并渲染字形,速度会略慢。

8. 代码中使用 .ttf 字体

8.1 自动选择字体

接口:lv_ext_set_local_font(lv_obj_t *obj, uint16_t size, lv_color_t color)

lv_obj_t *calorie = lv_label_create(bg_img);
lv_ext_set_local_font(calorie, FONT_SUBTITLE, lv_color_make(255, 255, 255));
lv_label_set_text(calorie, app_get_str(key_calorie, "calorie"));

8.2 指定字体名称

接口:lv_ext_label_set_indicated_font(lv_obj_t *obj, uint16_t size, lv_color_t color, const char *font_name)

lv_obj_t *calorie_lab = lv_label_create(bg_img);
lv_ext_set_local_font(calorie_lab, FONT_SUBTITLE, lv_color_make(255, 255, 255));
lv_ext_label_set_indicated_font(calorie_lab, FONT_SUBTITLE, lv_color_make(255, 255, 255), "HarmonyOS_Sans_SC_Bold");

8.3 指定字体名称并设置粗体 / 斜体

说明: 以下 FreeType 样式接口从 Solution V2.6 之后的版本开始支持,需要使能 FreeType,并且必须选择 FREETYPE_NORMAL_FONT,否则不支持粗体 / 斜体效果。

8.3.1 接口区别与适用场景

以下四个接口都只影响传入的对象,不会改变全局字体配置。它们可以分为两类:

  1. 设置字体时同时设置效果lv_ext_label_set_indicated_font_with_stylelv_ext_label_set_indicated_font_with_transform

    • 内部会先为 label 设置指定 font_name、字号和颜色,再设置对应效果。

    • 适用于创建 label 时已经确定字体名称和显示效果的场景,例如标题文本固定使用指定字体并加粗,或者某个固定文案需要倾斜显示。

  2. 对已经设置字体的对象设置效果lv_ext_obj_set_freetype_stylelv_ext_obj_set_freetype_transform

    • 不负责设置字号和颜色,调用前需要对象已经设置 FreeType 字体。

    • 既可以在对象初始化创建时使用,也可以在运行过程中追加或更新效果。初始化创建时的调用顺序通常是:先调用 lv_ext_set_local_fontlv_ext_label_set_indicated_font 设置字体,再调用对象级接口设置效果。

    • 适用于希望将“设置字体”和“设置效果”拆开处理的场景,例如字体通过 lv_ext_set_local_font 自动选择,但仍希望对该对象加粗或倾斜;也适用于根据业务状态动态切换效果的场景,例如焦点态加粗、消息列表中特定内容倾斜显示。

同时,styletransform 的作用不同:

  1. lv_ext_label_set_indicated_font_with_stylelv_ext_obj_set_freetype_style 用于设置 FreeType 粗体 / 斜体样式。

  2. lv_ext_label_set_indicated_font_with_transformlv_ext_obj_set_freetype_transform 用于设置 FreeType 字体变换矩阵,可实现缩放、倾斜等效果。

例如,lv_ext_label_set_indicated_font_with_transformlv_ext_obj_set_freetype_style 的区别是:前者会设置指定字体并应用变换矩阵,主要用于创建时直接得到倾斜 / 缩放字体;后者只对已经设置字体的对象设置粗体 / 斜体,不会设置字体、字号和颜色,但也可以在初始化创建阶段紧跟在设置字体之后调用。lv_ext_obj_set_freetype_transformlv_ext_label_set_indicated_font_with_style 的区别是:前者只对已经设置字体的对象更新变换矩阵;后者会设置指定字体并应用粗体 / 斜体样式。

8.3.2 lv_ext_label_set_indicated_font_with_style

接口:lv_ext_label_set_indicated_font_with_style(lv_obj_t *obj, uint16_t size, lv_color_t color, const char *font_name, bool bold_enable, uint16_t bold_strength_26dot6, bool italic_enable)

  • 接口说明:在设置 label 指定字体、字号和颜色的同时,设置该 label 绑定的 FreeType 粗体 / 斜体样式。不同 label 使用同一基础字体时,可以分别设置不同样式。

  • 适用场景:创建文本对象时就确定需要使用指定字体并加粗 / 倾斜,例如标题、按钮重点文案、电子书章节标题等。

  • font_name:字体名称。

  • bold_enable:是否启用粗体。

  • bold_strength_26dot6:粗体强度,使用 FreeType 26.6 像素格式,32 表示 0.5 px。该接口中,当 bold_enabletrue 且该值小于 32 时,会按 32 处理。

  • italic_enable:是否启用斜体。

效果图:

示例:

以下例程用于创建一个标题 label,并在设置指定字体、字号和颜色的同时,将该标题显示为粗体。

lv_obj_t *title = lv_label_create(bg_img);
lv_ext_label_set_indicated_font_with_style(title, FONT_TITLE, LV_COLOR_WHITE,
        "HarmonyOS_Sans_SC_Bold", true, 32, false);
lv_label_set_text(title, "Bold title");

8.3.3 lv_ext_obj_set_freetype_style

接口:lv_ext_obj_set_freetype_style(lv_obj_t *obj, const char *font_name, bool bold_enable, uint16_t bold_strength_26dot6, bool italic_enable)

  • 接口说明:对已经设置 FreeType 字体的对象,单独设置对象绑定的粗体 / 斜体样式。调用前需要先为对象设置 FreeType 字体。

  • 适用场景:既可用于初始化创建阶段,也可用于运行过程中动态切换样式。初始化创建时,适合先通过 lv_ext_set_local_font 自动选择字体,或先通过 lv_ext_label_set_indicated_font 设置字体,再调用该接口设置粗体 / 斜体;运行过程中可用于选中态文字加粗、阅读器标题动态加粗、焦点切换时修改文字样式等。

  • font_name:需要匹配的字体名称。传入 NULL 或空字符串时,表示作用于该对象使用的所有 FreeType 字体;传入非空字体名称时,只作用于匹配的字体。

  • bold_enable:是否启用粗体。

  • bold_strength_26dot6:粗体强度,使用 FreeType 26.6 像素格式,16 表示 0.25 px32 表示 0.5 px。设置为 0 时使用默认粗体强度。

  • italic_enable:是否启用斜体。

示例:

以下例程用于先创建普通用户名 label,并在初始化创建阶段将该 label 设置为斜体显示。该方式不重新设置字号和颜色,只要求在调用前已经为对象设置 FreeType 字体。

lv_obj_t *name = lv_label_create(bg_img);
lv_ext_label_set_indicated_font(name, FONT_SUBTITLE, LV_COLOR_WHITE, "HarmonyOS_Sans_SC_Bold");
lv_label_set_text(name, "User name");

lv_ext_obj_set_freetype_style(name, "HarmonyOS_Sans_SC_Bold", false, 0, true);
lv_obj_invalidate(name);

8.4 指定字体名称并设置字体变换

说明: 以下 FreeType 变换接口从 Solution V2.6 之后的版本开始支持,需要使能 FreeType,并且必须选择 FREETYPE_NORMAL_FONT,否则不支持字体变换矩阵效果。

8.4.1 lv_ext_label_set_indicated_font_with_transform

接口:lv_ext_label_set_indicated_font_with_transform(lv_obj_t *obj, uint16_t size, lv_color_t color, const char *font_name, bool transform_enable, int32_t xx_16dot16, int32_t xy_16dot16, int32_t yx_16dot16, int32_t yy_16dot16)

  • 接口说明:在设置 label 指定字体、字号和颜色的同时,设置该 label 绑定的 FreeType 字体变换矩阵。可用于轻微拉伸、倾斜等效果。

  • 适用场景:创建文本对象时就确定需要使用指定字体并做矩阵变换,例如固定提示文案倾斜显示、特殊标题做轻微拉伸或斜切效果。

  • transform_enable:是否启用字体变换。

  • xx_16dot16xy_16dot16yx_16dot16yy_16dot16:FreeType 16.16 定点格式的矩阵参数,其中 0x10000 表示 1.0。矩阵计算方式为 x' = xx * x + xy * yy' = yx * x + yy * y

效果图:

示例:

以下例程用于创建一个内容 label,并在设置指定字体、字号和颜色的同时,通过变换矩阵让文本做轻微倾斜显示。

lv_obj_t *content = lv_label_create(bg_img);
lv_ext_label_set_indicated_font_with_transform(content, FONT_TITLE, LV_COLOR_WHITE,
        "HarmonyOS_Sans_SC_Bold", true,
        LV_FREETYPE_TRANSFORM_IDENTITY_16D16, 0x04000L,
        0, LV_FREETYPE_TRANSFORM_IDENTITY_16D16);
lv_label_set_text(content, "Transform text");

8.4.2 lv_ext_obj_set_freetype_transform

接口:lv_ext_obj_set_freetype_transform(lv_obj_t *obj, const char *font_name, bool enable, int32_t xx_16dot16, int32_t xy_16dot16, int32_t yx_16dot16, int32_t yy_16dot16)

  • 接口说明:对已经设置 FreeType 字体的对象,单独设置对象绑定的字体变换矩阵。调用前需要先为对象设置 FreeType 字体。

  • 适用场景:既可用于初始化创建阶段,也可用于运行过程中动态调整字体变换。初始化创建时,适合先通过 lv_ext_set_local_font 自动选择字体,或先通过 lv_ext_label_set_indicated_font 设置字体,再调用该接口设置变换矩阵;运行过程中可用于消息通知内容统一做倾斜处理、焦点态做轻微拉伸、特定语言或排版场景临时调整显示效果。

  • font_name:需要匹配的字体名称。传入 NULL 或空字符串时,表示作用于该对象使用的所有 FreeType 字体;传入非空字体名称时,只作用于匹配的字体。

  • enable:是否启用字体变换。

  • xx_16dot16xy_16dot16yx_16dot16yy_16dot16:FreeType 16.16 定点格式的矩阵参数,其中 0x10000 表示 1.0

示例:

以下例程用于先创建通知内容 label 并设置常规字体,然后在初始化创建阶段对该对象应用倾斜 / 拉伸矩阵。该方式适合在字体由 lv_ext_set_local_font 自动选择时,为当前对象单独追加字体变换效果。

lv_obj_t *notify_content = lv_label_create(bg_img);
lv_ext_set_local_font(notify_content, FONT_TITLE, LV_COLOR_WHITE);
lv_label_set_text(notify_content, "Message content");

lv_ext_obj_set_freetype_transform(notify_content, NULL, true,
        0x10CCDL, 0x04000L,
        0, LV_FREETYPE_TRANSFORM_IDENTITY_16D16);
lv_obj_invalidate(notify_content);

注意: 字体变换可能影响 glyph 的边界和排版效果,建议在产品中使用验证过的固定参数。

8.5 设置全局 FreeType 字体效果

除上述对象级接口外,也可以使用 lv_freetype_set_stylelv_freetype_set_style_transform 设置 FreeType 字体的全局规则。

对象级接口与全局接口的主要区别如下:

  1. lv_ext_label_set_indicated_font_with_stylelv_ext_obj_set_freetype_stylelv_ext_label_set_indicated_font_with_transformlv_ext_obj_set_freetype_transform 只影响传入的对象,适用于单个 label 或单个控件需要独立字体效果的场景。

  2. lv_freetype_set_stylelv_freetype_set_style_transform 会按字体名称配置全局规则,后续使用匹配字体渲染的对象都会受影响,适用于同一字体在某个页面、某种语言或某类产品配置中需要统一效果的场景。

  3. font_name 传入 NULL 或空字符串时,表示设置所有 FreeType 字体的默认规则;传入非空字体名称时,只作用于匹配的字体名称,并且指定字体名称的规则优先级高于默认规则。

  4. 调用全局接口后,受影响的 glyph 缓存会被清除,因此建议在页面初始化、语言切换、主题切换等低频场景中调用,避免在频繁刷新的流程中反复调用。

8.5.1 lv_freetype_set_style

接口:lv_freetype_set_style(bool bold_enable, uint16_t bold_strength_26dot6, bool italic_enable, const char *font_name)

  • 接口说明:设置 FreeType 字体的全局粗体 / 斜体规则。

  • 适用场景:需要让某个字体在全局或某个页面中统一加粗 / 倾斜,例如当前语言使用的字体整体偏细,需要统一加粗显示;或者某个主题中要求指定字体统一使用斜体效果。

  • bold_enable:是否启用粗体。

  • bold_strength_26dot6:粗体强度,使用 FreeType 26.6 像素格式,16 表示 0.25 px32 表示 0.5 px。设置为 0 时使用默认粗体强度。

  • italic_enable:是否启用斜体。

  • font_name:需要匹配的字体名称。传入 NULL 或空字符串时,表示设置所有 FreeType 字体的默认规则。

示例:

以下例程用于在进入某个页面时,将 HarmonyOS_Sans_SC_Bold 这个字体统一加粗显示。后续该页面中使用该字体创建的文本都会按该规则渲染。

lv_freetype_set_style(true, 32, false, "HarmonyOS_Sans_SC_Bold");

lv_obj_t *title = lv_label_create(bg_img);
lv_ext_label_set_indicated_font(title, FONT_TITLE, LV_COLOR_WHITE, "HarmonyOS_Sans_SC_Bold");
lv_label_set_text(title, "Global bold title");

如果需要恢复该字体的普通样式,可关闭粗体和斜体:

lv_freetype_set_style(false, 0, false, "HarmonyOS_Sans_SC_Bold");

8.5.2 lv_freetype_set_style_transform

接口:lv_freetype_set_style_transform(bool enable, int32_t xx_16dot16, int32_t xy_16dot16, int32_t yx_16dot16, int32_t yy_16dot16, const char *font_name)

  • 接口说明:设置 FreeType 字体的全局变换矩阵规则。

  • 适用场景:需要让某个字体统一做矩阵变换,例如某种语言的通知内容统一倾斜显示、指定字体整体做轻微横向拉伸,或者产品主题要求某个字体统一使用斜切效果。

  • enable:是否启用字体变换。设置为 false 时,会关闭变换并恢复为单位矩阵。

  • xx_16dot16xy_16dot16yx_16dot16yy_16dot16:FreeType 16.16 定点格式的矩阵参数,其中 0x10000 表示 1.0。矩阵计算方式为 x' = xx * x + xy * yy' = yx * x + yy * y

  • font_name:需要匹配的字体名称。传入 NULL 或空字符串时,表示设置所有 FreeType 字体的默认规则。

示例:

以下例程用于在进入通知页面时,对所有 FreeType 字体统一应用轻微倾斜 / 拉伸矩阵。后续页面中新创建或刷新显示的 FreeType 文本都会按该矩阵渲染。

lv_freetype_set_style_transform(true,
        0x10CCDL, 0x04000L,
        0, LV_FREETYPE_TRANSFORM_IDENTITY_16D16,
        NULL);

lv_obj_t *notify_content = lv_label_create(bg_img);
lv_ext_set_local_font(notify_content, FONT_TITLE, LV_COLOR_WHITE);
lv_label_set_text(notify_content, "Global transform text");

如果需要恢复默认变换,可关闭变换并传入单位矩阵:

lv_freetype_set_style_transform(false,
        LV_FREETYPE_TRANSFORM_IDENTITY_16D16, 0,
        0, LV_FREETYPE_TRANSFORM_IDENTITY_16D16,
        NULL);

注意: lv_freetype_set_stylelv_freetype_set_style_transform 适用于 FREETYPE_NORMAL_FONT 方式;字体效果会影响渲染缓存,建议在页面初始化或配置切换时统一设置。

9. 代码中重新设置字体顺序

以下接口只能在 GUI 线程中使用,不能跨线程调用。

9.1 lvsf_font_set_order(char **font_name, uint16_t font_num)

  • 接口说明:调整字体顺序,将 font_name 指定的字体移动到最前面。

  • font_name:字符串数组,表示需要前置的字体。

  • font_num:需要调整顺序的字体个数。

示例:

假设当前字体列表为 tiny5_fullhindiarabHarmonyOS_Sans_SC_Bold,需要将 arabhindi 调整到最前面,适用于语言切换时优化字体访问顺序。

char *font_name[32] = {"arab", "hindi"};
uint16_t font_num = 2;
lvsf_font_set_order(font_name, font_num);

调整后的结果为:arabhinditiny5_fullHarmonyOS_Sans_SC_Bold

9.2 lvsf_font_set_order_reverse(char **font_name, uint16_t font_num)

  • 接口说明:调整字体顺序,将 font_name 指定的字体移动到最后面。

示例:

假设当前字体列表为 tiny5_fullhindiarabHarmonyOS_Sans_SC_Bold,需要将 arab 调整到最后面。

char *font_name[32] = {"arab"};
uint16_t font_num = 1;
lvsf_font_set_order_reverse(font_name, font_num);

调整后的结果为:tiny5_fullhindiHarmonyOS_Sans_SC_Boldarab

9.3 lvsf_font_reset_order(void)

  • 接口说明:将字体顺序恢复为开机时的默认顺序。

10. 重新设置某个字体支持的字号

以下接口只能在 GUI 线程中使用,不能跨线程调用。

10.1 lvsf_set_font_size_by_name(char *font_name, int *size)

  • 接口说明:调整指定字体支持的字号。

  • 注意:字号必须按从小到大的顺序排列。

示例:

假设字体当前支持的字号为 162024283656,分别对应 FONT_SMALLFONT_NORMALFONT_SUBTITLEFONT_TITLEFONT_BIGLFONT_HUGE

char *font_name = "arab";
int size[] = {20, 22, 0}; /* 以 0 结尾 */
lvsf_set_font_size_by_name(font_name, size);

调整后的结果为:202224283656。即该字体的 FONT_SMALL 变为 20FONT_NORMAL 变为 22

10.2 lvsf_reset_font_size_by_name(char *font_name)

  • 接口说明:将指定字体的字号恢复为开机时的默认值。

11. 设置支持 bitmap(点阵字体)

  1. Solution 通过如下 menuconfig 配置使能 bitmap。

  1. 以 watch 产品为例,点阵字体生成的 .c 文件通常放在如下目录(其他产品目录类似)。

  1. 代码中调用 bitmap 的示例:lv_ext_set_local_bitmap_font

lv_obj_t *keybord = lv_keyboard_create(parent);
lv_obj_set_width(keybord, LV_HOR_RES_MAX);
lv_keyboard_set_mode(keybord, LV_KEYBOARD_MODE_TEXT_LOWER);
lv_keyboard_set_textarea(keybord, ta);
lv_obj_align_to(keybord, ta, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
#ifdef USING_BITMAP_FONT
    lv_ext_set_local_bitmap_font(keybord, LV_COLOR_BLACK, lv_font_montserrat_16);
#else
    lv_ext_set_local_font(keybord, FONT_NORMAL, lv_color_make(0xFF, 0x00, 0x00));
#endif
lv_obj_refr_size(keybord);

lv_obj_add_event_cb(ta, setting_bt_name_ta_event_cb, LV_EVENT_ALL, keybord);

注意:

  1. 在 Solution 中通过上述配置即可使用点阵字体,无需在 SDK 中额外配置 bitmap。

  2. 使用 lv_ext_set_local_bitmap_font 调用点阵字体(例如示例中的 lv_font_montserrat_16)时,需要确保 resource/fonts/bitmap 中存在对应字体定义。

12. 引用外置 .ttf 字体

除内置字体外,Solution 还支持使用外置字体,例如:

  • 通过蓝牙 / Wi-Fi 推送到文件系统中的字体;

  • 直接访问 U 盘 / TF 卡中的字体。

相关接口如下:

  1. int lvsf_font_load_ex(char *font_path, uint16_t *size)
    从指定路径 font_path 加载字体。可加载该目录下全部字体,也可以通过完整文件路径(含 .ttf 后缀)加载单个字体。加载后字体会插入字体链表,但默认处于未启用状态。加载完成后,可通过 lvsf_font_trav_ex 查询已加载的外置字体。

  2. int lvsf_font_set_enable(char *font_name, int enable)
    启用或禁用指定名称 font_name 的字体。启用后会占用内存,尤其在 NAND Flash / eMMC 方案中更明显,因此需控制加载数量,特别是大字体文件。

  3. void lvsf_font_unload_ex(char *font_path)
    从字体链表中卸载指定路径 font_path 下的全部字体,或通过完整文件路径卸载单个字体(含 .ttf 后缀)。

  4. char *lvsf_font_trav_ex(rt_list_t **list, int ex)
    遍历字体链表,获取所有已加载的外置字体信息。

13. UNKNOWN 字的显示

参照字体显示流程,当某个字符无法在当前 .ttf 中找到时,系统会显示 UNKNOWN 字。通常情况下,UNKNOWN 字显示为方块

在某些场景下,客户可能需要自定义 UNKNOWN 字的显示方式。例如:

  • 中文环境下显示为中文问号

  • 也可以显示为英文问号 ?

  • 或替换为其他字符

为此,Solution 提供了以下接口:lv_freetype_set_unknown_font_mode

/**
 * @brief Configure how missing glyphs are handled by the FreeType-backed font renderer.
 *
 * @param mode
 *        - 0: render a replacement glyph using @p unknown_font_unicode
 *        - 1: ignore missing glyphs (nothing will be drawn)
 * @param unknown_font_unicode Replacement Unicode code point used only when @p mode is 0.
 *
 * @note This API name contains a historical typo ("unkown"). Prefer
 *       `lv_freetype_set_unknown_font_mode()` for new code.
 */
void lv_freetype_set_unkown_font_mode(int mode, uint32_t unknown_font_unicode);

代码调用位置:sdk/middleware/lvgl/lvsf/lvsf_font.c 中的 ft_callback_reg

示例:

  1. 将 UNKNOWN 字显示为 (中文问号)

lv_freetype_set_unkown_font_mode(0, 0xFF1F); /* "?" U+FF1F (0xFF1F) */
  1. 将 UNKNOWN 字显示为 ?(英文问号)

lv_freetype_set_unkown_font_mode(0, 0x3F); /* '?' U+003F (0x3F) */

说明: 该功能仅在 Solution V2.5 及以上版本支持。如需在旧版本中支持,请联系 FAE 升级 PATCH。

14. 提升字体显示速度

使用 FreeType 进行字体显示时,通常需要先查找 glyph 再进行渲染。一个字符首次显示时,耗时通常为毫秒级。为提升显示速度,Solution 提供以下两种方法。

注意:

  1. Font_gen 工具不能从 tiny55_full.ttfhindi.ttf 中抽取静态字体。

  2. 如果需要使用 hindi.ttf(印地语),印地语显示仍需通过 hindi.ttf 实现,因此抽取出的字体风格(粗细)应与 hindi.ttf 保持一致。

14.1 使用 Font_genmulti_language_table.xlsx 抽取静态字体到一个 .ttf 文件

  • 工具位置:solution/tools/Font_gen/font_gen.exe

  • 使用示例:font_gen.exe -i multi_language_table.xlsx -i unicode 0x02-0xff HarmonyOS_Sans_SC_Bold.ttf arab.ttf

生成 static_font.ttf 后,可按以下方式使用:

  1. 放入具体产品工程的 resource/builtin/freetype/ 目录(如果工程使用该目录组织 builtin 字体资源)

    • 编译时会将 static_font.ttf 转换为 .c 文件并编译进代码。

    • 这种方式会增加一些内存占用,但字体显示速度更快。

  2. 放入具体产品工程的 resource/fonts/freetype 目录,例如 solution/examples/watch/resource/fonts/freetype

    • 将其作为普通 .ttf 字体参与方案。

    • 这种方式不会额外占用代码空间,但显示速度相比 builtin 字体略慢。

注意: 如果方案中仍需使用 tiny55_full.ttf,则该方法通常不适用。原因包括:

  • 抽取字体的风格通常与 tiny55_full.ttf 不一致;

  • 当代码中的静态文本发生变化时,作为文件存在的 .ttf 也需要同步升级。

14.2 使用 Font_genmulti_language_table.xlsx 抽取静态字体到 bitmap 文件

相比 static_font.ttf,bitmap 文件能更有效地解决 FreeType 字体渲染耗时较长的问题。

  • 使用前提:multi_language_table.xlsx 中需准确填写 Bitmap_fontsize 列,明确每行文字对应的显示字号。

  • 工具位置:solution/tools/Font_gen/font_gen.exe

  • 使用示例:font_gen.exe -i multi_language_table.xlsx -i unicode 0x02-0xff HarmonyOS_Sans_SC_Bold.ttf arab.ttf -ttf2bitmap 2

  • solution/framework/__template__/project 下的 __applicaiton_private__ 复制到工程 project 目录下(与 hcpu 目录同级)。

  • 将生成的静态字体 C 文件(文件名通常形如 static_font_xx.c,由工具按字号生成)复制到 project/__applicaiton_private__/ 目录下。

  • 所有静态字体显示统一使用 lv_ext_set_local_bitmap_font 接口。

说明: 使用该方法时,方案仍可保留 tiny55_full.ttf 作为动态字库,用于消息、电子书、实时生成信息等场景,从而实现静态字库与 tiny55_full.ttf 的混合使用,并允许静态文本与动态文本采用不同字体风格。

说明: 该功能仅在 Solution V2.5 及以上版本支持。