本笔记以我示例项目中的 obj/myexample.c 系列函数作为核心代码示例进行讲解

配置好跨平台规则的项目链接:跨平台 LVGL 项目模板

1. 图像

从 C 数组加载 (有限图像场景)

这种方法适合图标、背景图等固定不变的图像资源。它将图片数据直接编译进程序中,运行效率高,但不灵活。

核心步骤:

  1. 转换

    使用 LVGL 官方的 在线图像转换工具 将你的图片转换为一个 C 语言源文件。

    这个 C 文件中会包含一个 lv_img_dsc_t 类型的数组,存储了图像的所有像素数据

    按照下图选项来输出适合 v8 版本的图片

    注意:如果图片里带有透明图层,颜色格式需要选择CF_TRUE_COLOR_ALPHA而不是CF_TRUE_COLOR,只有保存了ALPHA通道信息才能正常显示透明部分

    img

  2. 编译

    将生成的 .c 文件添加到你的项目 CMake 中,并确保它能被编译链接

    image-20250917095314642

  3. 使用

    在代码中通过 LV_IMG_DECLARE 声明该图像资源,然后使用 lv_img_set_src 将其设置给一个图像对象

代码示例
以下代码演示了如何显示一个已经通过工具转换好的,名为 abc 的图像。

1
2
3
4
5
6
7
8
9
// obj/myexample.c
void demo_sjpg_from_array( ) {
// 声明图片数据所在的数组名称
// 这个宏会引用在 abc.c 文件中定义的图像数组变量
LV_IMG_DECLARE(abc);
lv_obj_t* img = lv_img_create(lv_scr_act()); // 创建一个图像对象
lv_img_set_src(img, &abc); // 将图像资源设置给对象
lv_obj_center(img); // 图片居中显示
}

image-20250917094907524


从文件系统加载 (不限图像场景)

当需要显示不固定的图片(如照片、网络下载的图片)时,就需要使用此方法。它要求 LVGL 能够访问设备的文件系统。

核心步骤:

  1. 配置 lv_conf.h
    • 开启文件系统支持:将 LV_USE_FS_STDIO 或其他文件系统接口设置为 1
    • 定义 “盘符”:设置 LV_FS_STDIO_LETTER 为一个大写字母,例如 'A'。此后,所有文件路径都必须以 A:/ 开头。
  2. 放置文件:将图片文件(如 small_image.sjpg)放置到你的设备文件系统的某个路径下(如 /mnt/nfs/)。
  3. 使用:在代码中,使用 lv_img_set_src 并传入 盘符 + 绝对路径 格式的字符串。

代码示例
以下代码演示了如何从设备的 /mnt/nfs/ 目录下加载并显示 small_image.sjpg 图片。

1
2
3
4
5
6
7
8
9
void demo_sjpg_from_file( ) {
lv_obj_t* img = lv_img_create(lv_scr_act()); // 创建一个图像对象

// 设置图像源为文件路径
// "A:" 是在 lv_conf.h 中定义的盘符
// "/mnt/nfs/small_image.sjpg" 是图片在设备上的实际路径
lv_img_set_src(img, "A:/mnt/nfs/small_image.sjpg");
lv_obj_center(img); // 将图片居中显示
}

安装 PNG 解码库 (依赖 zlib)

PNG 库依赖 zlib 库,因此需要先编译安装 zlib,再编译安装 libpng。以下教程针对交叉编译环境,提供了避免常见陷阱的详细步骤。

1. 安装 zlib 压缩库

  • Ubuntu/Linux

    用一句命令即可直接安装

    1
    sudo apt install zlib1g-dev
  • 开发板 / 其他平台
    需手动下载、交叉编译并链接:

    进入 zlib 源码目录进行配置和编译。

    关键提示: 为了避免后续在链接动态库时出现 recompile with -fPIC 的错误,我们必须在编译静态库时就生成“位置无关代码”(Position-Independent Code)。

    推荐的编译命令 (生成静态库 .a):

    1
    2
    3
    4
    5
    6
    7
    8
    # 指定交叉编译器
    export CC=arm-linux-gcc

    # 使用 CMAKE_POSITION_INDEPENDENT_CODE=ON 来添加 -fPIC 标志
    cmake -B build -D CMAKE_BUILD_TYPE=Release -D CMAKE_POSITION_INDEPENDENT_CODE=ON

    # 编译
    cmake --build build -j12

    编译完成后,会在 build 目录下生成 libz.a 文件。

2. 安装 libpng 库

  • Ubuntu/Linux

    用一句命令即可直接安装

    1
    sudo apt install libpng-dev
  • 开发板 / 其他平台
    需手动下载、交叉编译并链接:

    进入 libpng 源码目录进行配置和编译。

    关键提示: 在交叉编译时,libpng 的构建系统无法自动找到我们刚刚编译好的 zlib。我们必须通过 CMake 参数明确地告诉它 zlib 的头文件和库文件在哪里。

    推荐的编译命令 (生成静态库 .a):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 指定交叉编译器
    export CC=arm-linux-gcc

    # 运行 cmake,并用 -D 参数明确指定 zlib 的路径
    # 注意:请将 <path/to> 替换为你的实际路径,不要使用 '~'
    cmake -B build \
    -D CMAKE_BUILD_TYPE=Release \
    -D BUILD_SHARED_LIBS=OFF \
    -D ZLIB_INCLUDE_DIR=<path/to>/zlib-1.3.1 \
    -D ZLIB_LIBRARY=<path/to>/zlib-1.3.1/build/libz.a \
    -D CMAKE_C_FLAGS="-I<path/to>/zlib-1.3.1/build"

    # 编译
    cmake --build build -j12

    参数详解:

    • -D ZLIB_INCLUDE_DIR: 指向 zlib 的源码根目录,用于找到 zlib.h
    • -D ZLIB_LIBRARY: 明确指向编译生成的 libz.a 静态库文件。
    • -D CMAKE_C_FLAGS="-I...": 额外添加一个头文件搜索路径,指向 zlib 的构建目录,用于找到编译时生成的 zconf.h

    编译完成后,会在 build 目录下生成 libpng16.a 文件。

  • CMake 工程链接 PNG 与 ZLIB

    在链接时,必须同时链接 libpng 和 zlib。由于我们编译的是静态库,CMake 中也应配置为链接静态库。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    if(CMAKE_CROSSCOMPILING)
    # ARM 平台
    set(TARGET_PLATFORM "arm")

    # --- 为 FreeType 添加 (静态库示例) ---
    add_library(freetype_local STATIC IMPORTED GLOBAL)
    set_target_properties(freetype_local PROPERTIES
    IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/libs/freetype/lib/arm/libfreetype.a"
    )

    # --- 为 PNG 添加 (静态库) ---
    add_library(png_local STATIC IMPORTED GLOBAL)
    set_target_properties(png_local PROPERTIES
    # 假设你已将编译好的 libpng16.a 复制到此路径
    IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/libs/png/lib/arm/libpng16.a"
    )

    # --- 为 ZLIB 添加 (静态库) ---
    add_library(zlib_local STATIC IMPORTED GLOBAL)
    set_target_properties(zlib_local PROPERTIES
    # 假设你已将编译好的 libz.a 复制到此路径
    IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlib/lib/arm/libz.a"
    )

    # --- 将所有库加入列表 (注意链接顺序) ---
    set(PLATFORM_LIBS pthread freetype_local png_local zlib_local m)

    elseif(UNIX AND NOT APPLE)
    # Linux PC 平台
    set(TARGET_PLATFORM "pc")
    find_package(SDL2 REQUIRED)
    find_package(Threads REQUIRED)
    find_package(Freetype REQUIRED)

    # --- 查找 PNG 和 ZLIB ---
    find_package(PNG REQUIRED)
    find_package(ZLIB REQUIRED)

    # --- 将所有库加入列表 (使用现代CMake目标) ---
    set(PLATFORM_LIBS SDL2::SDL2 Threads::Threads Freetype::Freetype PNG::PNG ZLIB::ZLIB m)

    endif()
    • 使用方法和之前一样,如果还是不行,用下面的函数调试:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      static void debug_load_image(const char* path_to_test)
      {
      LV_LOG_USER("--- 开始终极调试: %s ---", path_to_test);

      // 步骤 1: 检查 LVGL 文件系统驱动是否就绪
      if (!lv_fs_is_ready('A')) {
      LV_LOG_ERROR("错误: LVGL 文件系统驱动 'A' 未就绪!");
      return;
      }
      LV_LOG_USER("调试信息: LVGL 文件系统驱动 'A' 已就绪。");

      // 步骤 2: 尝试用 LVGL 的 API 打开文件
      lv_fs_file_t f;
      lv_fs_res_t res = lv_fs_open(&f, path_to_test, LV_FS_MODE_RD);

      if (res != LV_FS_RES_OK) {
      LV_LOG_ERROR("错误: LVGL lv_fs_open 失败! 错误码: %d", res);
      } else {
      LV_LOG_USER("调试成功: LVGL lv_fs_open 成功!");
      lv_fs_close(&f);
      }

      // 步骤 3: 作为对比,尝试用标准 C 的 API 打开同一个文件
      FILE* std_f = fopen(path_to_test, "rb");
      if (std_f == NULL) {
      LV_LOG_ERROR("错误: 标准 C fopen 失败!");
      } else {
      LV_LOG_USER("调试成功: 标准 C fopen 成功!");
      fclose(std_f);
      }

      LV_LOG_USER("--- 终极调试结束 ---");
      }

      可以开启 lv_conf.h 里面的这个选项来缓存图片,使 cpu 占用降低:

      1
      #define LV_IMG_CACHE_DEF_SIZE   2

2. 字体

LVGL 内置字体对中文支持不佳,推荐使用外部字体。最灵活、支持最全面的方式是集成 FreeType 字体库

使用 FreeType 加载外部字体(不限汉字场景)

此方法支持动态加载标准字体文件(如 .ttf),可直接显示任意汉字,无需预先转换

1. 配置与编译

  • 开启 LVGL FreeType 支持
    lv_conf.h 中设置:

    1
    #define LV_USE_FREETYPE 1

    image-20250917102811310

  • 安装 FreeType 库

    • Ubuntu/Linux

      用一句命令即可直接安装

      1
      sudo apt install libfreetype6-dev
    • 开发板 / 其他平台
      需手动下载、交叉编译并链接:

      将源码下载下来放到项目根目录

      进入 freetype 源码目录命令行,进行以下配置和编译操作

      编译为动态库:

      1
      2
      3
      4
      5
      6
      # 指定交叉编译器
      export CC=arm-linux-gcc
      cmake -B build -D BUILD_SHARED_LIBS=true -D CMAKE_BUILD_TYPE=Release

      #编译
      cmake --build build -j12

      或者编译为静态库:

      1
      2
      3
      4
      5
      6
      # 指定交叉编译器
      export CC=arm-linux-gcc
      cmake -B build -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Release

      # 编译
      cmake --build build -j12
  • CMake 工程链接 FreeType

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    if(CMAKE_CROSSCOMPILING)
    # ARM 平台
    set(TARGET_PLATFORM "arm")
    add_library(freetype_local SHARED IMPORTED GLOBAL)
    set_target_properties(freetype_local PROPERTIES
    # ARM 平台需要指定库程序路径
    IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/libs/freetype/lib/arm/libfreetype.so"
    )
    set(PLATFORM_LIBS pthread freetype_local m)

    elseif(UNIX AND NOT APPLE)
    # Linux PC 平台
    set(TARGET_PLATFORM "pc")
    find_package(SDL2 REQUIRED)
    find_package(Threads REQUIRED)
    # 直接去系统库里面找
    set(PLATFORM_LIBS SDL2::SDL2 Threads::Threads freetype m)

    endif()

2. 准备字体文件

将所需 .ttf 文件(如 MiSans.ttf)放到设备文件系统中,保证程序运行时可访问。

3. 使用方法

代码初始化 FreeType 字体 → 创建样式 → 应用到控件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void demo_freetype_text(void) {
// 1. 初始化字体信息
static lv_ft_info_t info;
// 确保字体文件在相对编译出的程序路径下
info.name = "./MiSans.ttf";
info.weight = 24;
info.style = FT_FONT_STYLE_NORMAL;
info.mem = NULL;

if (!lv_ft_font_init(&info)) { // 初始化字体
LV_LOG_ERROR("FreeType 初始化失败.");
return;
}

// 2. 创建一个样式来使用这个字体
static lv_style_t style;
lv_style_init(&style);
// 将刚刚初始化好的字体设置到样式中
lv_style_set_text_font(&style, info.font);
lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);

// 3. 创建标签并应用样式
lv_obj_t* label = lv_label_create(lv_scr_act());
lv_obj_add_style(label, &style, 0); // 应用前面设置的style样式
// 以后显示中文时像上面一样引用这个样式即可
lv_label_set_text(label, "你好, LVGL\nI'm a font created with FreeType");
lv_obj_center(label);
}

加载的 TTF 字体可正常显示中文和英文