图像

图像可以是一个文件,也可以是一个存储位图本身及一些元数据的变量。

存储图像

您可以将图像存储在两个地方:

  • 作为变量存储在内部内存中(RAM 或 ROM)

  • 作为文件存储

变量

存储在变量中的图像主要由一个 lv_img_dsc_t 结构组成,该结构包含以下字段:

  • header

    • cf 颜色格式。参见下文

    • w 宽度(像素,<= 2048)

    • h 高度(像素,<= 2048)

    • always zero 必须始终为零的 3 位

    • reserved 保留供将来使用

  • data 指向存储图像本身的数组的指针

  • data_size data 的字节长度

这些通常以 C 文件的形式存储在项目中。它们像其他常量数据一样链接到生成的可执行文件中。

文件

要处理文件,您需要向 LVGL 添加一个存储 驱动器。简而言之,驱动器 是一组函数(openreadclose 等),它们在 LVGL 中注册以实现文件操作。 您可以添加一个标准文件系统(如 SD 卡上的 FAT32)的接口,或者创建一个简单的文件系统以从 SPI 闪存中读取数据。 无论哪种情况,驱动器 都只是一个用于读取和/或写入内存的抽象。 请参阅文件系统部分以了解更多信息。

存储为文件的图像不会链接到生成的可执行文件中,必须在绘制之前加载到 RAM 中。因此,它们不像编译时链接的图像那样节省资源。然而,它们更容易替换,而无需重新构建主程序。

颜色格式

支持多种内置颜色格式:

  • LV_IMG_CF_TRUE_COLOR 简单地存储 RGB 颜色(以 LVGL 配置的颜色深度)。

  • LV_IMG_CF_TRUE_COLOR_ALPHA 类似于 LV_IMG_CF_TRUE_COLOR,但每个像素还添加了一个 alpha(透明度)字节。

  • LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED 类似于 LV_IMG_CF_TRUE_COLOR,但如果像素具有 LV_COLOR_TRANSP 颜色(在 lv_conf.h 中设置),它将是透明的。

  • LV_IMG_CF_INDEXED_1/2/4/8BIT 使用一个包含 2、4、16 或 256 种颜色的调色板,并以 1、2、4 或 8 位存储每个像素。

  • LV_IMG_CF_ALPHA_1/2/4/8BIT 仅存储 Alpha 值,使用 1、2、4 或 8 位。 像素采用 style.img_recolor 的颜色和设置的不透明度。源图像必须是 alpha 通道。这对于类似字体的位图非常理想,其中整个图像是可以更改的一种颜色。

LV_IMG_CF_TRUE_COLOR 图像的字节按以下顺序存储。

对于 32 位颜色深度:

  • 字节 0: 蓝色

  • 字节 1: 绿色

  • 字节 2: 红色

  • 字节 3: Alpha

对于 16 位颜色深度:

  • 字节 0: 绿色低 3 位,蓝色 5 位

  • 字节 1: 红色 5 位,绿色高 3 位

  • 字节 2: Alpha 字节(仅适用于 LV_IMG_CF_TRUE_COLOR_ALPHA)

对于 8 位颜色深度:

  • 字节 0: 红色 3 位,绿色 3 位,蓝色 2 位

  • 字节 2: Alpha 字节(仅适用于 LV_IMG_CF_TRUE_COLOR_ALPHA)

您可以以 Raw 格式存储图像,以指示它未使用内置颜色格式之一进行编码,需要使用外部图像解码器来解码图像。

  • LV_IMG_CF_RAW 表示基本的原始图像(例如 PNG 或 JPG 图像)。

  • LV_IMG_CF_RAW_ALPHA 表示图像具有 alpha,并为每个像素添加一个 alpha 字节。

  • LV_IMG_CF_RAW_CHROMA_KEYED 表示图像是色度键控的,如上文 LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED 中所述。

添加和使用图像

您可以通过两种方式将图像添加到 LVGL:

  • 使用在线转换器

  • 手动创建图像

在线转换器

在线图像转换器可在此处找到:https://lvgl.io/tools/imageconverter

通过在线转换器将图像添加到 LVGL 非常简单。

  1. 首先需要选择一个 BMPPNGJPG 图像。

  2. 为图像命名,该名称将在 LVGL 中使用。

  3. 选择颜色格式

  4. 选择所需的图像类型。选择二进制将生成一个 .bin 文件,必须单独存储并使用文件支持读取。选择变量将生成一个标准的 C 文件,可以链接到您的项目中。

  5. 点击 Convert 按钮。转换完成后,浏览器会自动下载生成的文件。

在生成的 C 数组(变量)中,所有颜色深度(1、8、16 或 32)的位图都包含在 C 文件中,但只有与 lv_conf.h 中的 LV_COLOR_DEPTH 匹配的颜色深度会实际链接到生成的可执行文件中。

对于二进制文件,您需要指定所需的颜色格式:

  • RGB332 用于 8 位颜色深度

  • RGB565 用于 16 位颜色深度

  • RGB565 Swap 用于 16 位颜色深度(交换两个字节)

  • RGB888 用于 32 位颜色深度

手动创建图像

如果您在运行时生成图像,可以制作一个图像变量以使用 LVGL 显示它。例如:

uint8_t my_img_data[] = {0x00, 0x01, 0x02, ...};

static lv_img_dsc_t my_img_dsc = {
    .header.always_zero = 0,
    .header.w = 80,
    .header.h = 60,
    .data_size = 80 * 60 * LV_COLOR_DEPTH / 8,
    .header.cf = LV_IMG_CF_TRUE_COLOR,          /*设置颜色格式*/
    .data = my_img_data,
};

如果颜色格式是 LV_IMG_CF_TRUE_COLOR_ALPHA,您可以将 data_size 设置为 80 * 60 * LV_IMG_PX_SIZE_ALPHA_BYTE

另一种(可能更简单的)在运行时创建和显示图像的选项是使用画布对象。

使用图像

在 LVGL 中使用图像的最简单方法是使用 lv_img 对象显示它:

lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);

/*来自变量*/
lv_img_set_src(icon, &my_icon_dsc);

/*来自文件*/
lv_img_set_src(icon, "S:my_icon.bin");

如果图像是通过在线转换器转换的,您应该在要使用图像的文件中使用 LV_IMG_DECLARE(my_icon_dsc) 声明图像。

图像解码器

颜色格式部分所述,LVGL 支持几种内置图像格式。在许多情况下,这些格式已经足够。然而,LVGL 不直接支持通用图像格式,如 PNG 或 JPG。

要处理非内置图像格式,您需要使用外部库并通过图像解码器接口将它们附加到 LVGL。

图像解码器由 4 个回调组成:

  • info 获取有关图像的一些基本信息(宽度、高度和颜色格式)。

  • open 打开图像:存储解码后的图像或将其设置为 NULL 以指示图像可以逐行读取。

  • read 如果 open 未完全打开图像,此函数应从给定位置提供一些解码数据(最多 1 行)。

  • close 关闭已打开的图像,释放分配的资源。

您可以添加任意数量的图像解码器。当需要绘制图像时,库将尝试所有注册的图像解码器,直到找到一个可以打开图像的解码器,即一个知道该格式的解码器。

LV_IMG_CF_TRUE_COLOR_...LV_IMG_INDEXED_...LV_IMG_ALPHA_... 格式(本质上,所有非 RAW 格式)由内置解码器理解。

自定义图像格式

创建自定义图像的最简单方法是使用在线图像转换器并选择 RawRaw with alphaRaw with chroma-keyed 格式。它将获取您上传的二进制文件的每个字节,并将其写为图像“位图”。然后,您需要附加一个图像解码器来解析该位图并生成真实的、可渲染的位图。

header.cf 将分别为 LV_IMG_CF_RAWLV_IMG_CF_RAW_ALPHALV_IMG_CF_RAW_CHROMA_KEYED。您应根据需要选择正确的格式:完全不透明的图像、使用 alpha 通道或使用色度键。

解码后,raw 格式被库视为真彩色。换句话说,图像解码器必须根据颜色格式部分中描述的格式将raw图像解码为真彩色

如果要创建自定义图像,应使用 LV_IMG_CF_USER_ENCODED_0..7 颜色格式。然而,库只能以真彩色格式(或raw,但最终将是真彩色格式)绘制图像。 LV_IMG_CF_USER_ENCODED_... 格式不为库所知,因此应将其解码为颜色格式部分中已知的格式之一。 可以先将图像解码为非真彩色格式(例如:LV_IMG_INDEXED_4BITS),然后调用内置解码器函数将其转换为真彩色

对于用户编码格式,打开函数中的颜色格式(dsc->header.cf)应根据新格式进行更改。

注册图像解码器

以下是使 LVGL 支持 PNG 图像的示例。

首先,您需要创建一个新的图像解码器并设置一些函数以打开/关闭 PNG 文件。它应如下所示:

/*创建一个新的解码器并注册函数*/
lv_img_decoder_t * dec = lv_img_decoder_create();
lv_img_decoder_set_info_cb(dec, decoder_info);
lv_img_decoder_set_open_cb(dec, decoder_open);
lv_img_decoder_set_close_cb(dec, decoder_close);


/**
 * 获取有关 PNG 图像的信息
 * @param decoder 此函数所属的解码器指针
 * @param src 可以是文件名或指向 C 数组的指针
 * @param header 在此处存储信息
 * @return LV_RES_OK: 无错误; LV_RES_INV: 无法获取信息
 */
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
{
  /*检查解码器是否知道 `src` 的类型*/
  if(is_png(src) == false) return LV_RES_INV;

  /*读取 PNG 头并找到 `width` 和 `height` */
  ...

  header->cf = LV_IMG_CF_RAW_ALPHA;
  header->w = width;
  header->h = height;
}

/**
 * 打开 PNG 图像并返回解码后的图像
 * @param decoder 此函数所属的解码器指针
 * @param dsc 描述此解码会话的描述符指针
 * @return LV_RES_OK: 无错误; LV_RES_INV: 无法获取信息
 */
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{

  /*检查解码器是否知道 `src` 的类型*/
  if(is_png(src) == false) return LV_RES_INV;

  /*解码并存储图像。如果 `dsc->img_data` 为 `NULL`,将调用 `read_line` 函数逐行获取图像数据*/
  dsc->img_data = my_png_decoder(src);

  /*如果需要,改变颜色格式。对于 PNG,通常 'Raw' 就可以了*/
  dsc->header.cf = LV_IMG_CF_...

  /*如果需要,调用内置解码器函数。如果 `my_png_decoder` 以真彩色格式打开图像,则不需要。*/
  lv_res_t res = lv_img_decoder_built_in_open(decoder, dsc);

  return res;
}

/**
 * 从给定的 `x`、`y` 坐标开始解码 `len` 像素,并将它们存储在 `buf` 中。
 * 仅当“open”函数无法打开整个解码的像素数组时需要。(dsc->img_data == NULL)
 * @param decoder 与函数关联的解码器指针
 * @param dsc 解码器描述符指针
 * @param x 起始 x 坐标
 * @param y 起始 y 坐标
 * @param len 要解码的像素数
 * @param buf 存储解码像素的缓冲区
 * @return LV_RES_OK: 成功; LV_RES_INV: 失败
 */
lv_res_t decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
                                                  lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
   /*对于 PNG 通常不需要*/

   /*将 `len` 像素从 `x` 和 `y` 坐标以真彩色格式复制到 `buf` */

}

/**
 * 释放分配的资源
 * @param decoder 此函数所属的解码器指针
 * @param dsc 描述此解码会话的描述符指针
 */
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
  /*释放所有分配的数据*/

  /*如果使用了内置的 open/read_line,调用内置的 close 函数*/
  lv_img_decoder_built_in_close(decoder, dsc);

}

总结如下:

  • decoder_info 中,您应收集有关图像的一些基本信息并将其存储在 header 中。

  • decoder_open 中,您应尝试打开由 dsc->src 指向的图像源。其类型已在 dsc->src_type == LV_IMG_SRC_FILE/VARIABLE 中。 如果解码器不支持此格式/类型,则返回 LV_RES_INV。 但是,如果您可以打开图像,则应在 dsc->img_data 中设置指向解码后的真彩色图像的指针。 如果已知格式,但您不想解码整个图像(例如:没有足够的内存),请在打开函数中设置 dsc->img_data = NULL 并使用 read_line 获取像素数据。

  • decoder_close 中,您应释放所有分配的资源。

  • decoder_read 是可选的。解码整个图像需要额外的内存和一些计算开销。 但是,它可以在不解码整个图像的情况下解码图像的一行,您可以节省内存和时间。 要指示应使用行读取函数,请在打开函数中设置 dsc->img_data = NULL

手动使用图像解码器

如果您尝试绘制原始图像(即使用 lv_img 对象),LVGL 将自动使用注册的图像解码器,但您也可以手动使用它们。创建一个 lv_img_decoder_dsc_t 变量来描述解码会话并调用 lv_img_decoder_open()

color 参数仅用于 LV_IMG_CF_ALPHA_1/2/4/8BIT 图像,以指示图像的颜色。 frame_id 可用于打开的图像是动画时。


lv_res_t res;
lv_img_decoder_dsc_t dsc;
res = lv_img_decoder_open(&dsc, &my_img_dsc, color, frame_id);

if(res == LV_RES_OK) {
  /*对 `dsc->img_data` 执行操作*/
  lv_img_decoder_close(&dsc);
}

图像缓存

有时打开图像需要花费大量时间。 连续解码 PNG 图像或从较慢的外部存储器加载图像会效率低下并损害用户体验。

因此,LVGL 缓存了一定数量的图像。缓存意味着某些图像将保持打开状态,因此 LVGL 可以快速从 dsc->img_data 访问它们,而无需再次解码。

当然,缓存图像会占用更多的 RAM 来存储解码后的图像。LVGL 尽可能优化此过程(见下文),但您仍需要评估这对您的平台是否有益。如果您有一个从相对较快的存储介质解码小图像的深度嵌入式目标,图像缓存可能不值得。

缓存大小

缓存条目的数量可以通过 lv_conf.h 中的 LV_IMG_CACHE_DEF_SIZE 定义。默认值为 1,因此只有最近使用的图像将保持打开状态。

可以使用 lv_img_cache_set_size(entry_num) 在运行时更改缓存的大小。

图像的价值

当您使用的图像多于缓存条目时,LVGL 无法缓存所有图像。相反,库将关闭一个缓存的图像以释放空间。

为了决定关闭哪个图像,LVGL 使用之前对打开图像所需时间的测量。保存较慢打开图像的缓存条目被认为更有价值,并尽可能长时间保留在缓存中。

如果您想或需要覆盖 LVGL 的测量值,可以在解码器打开函数中手动设置打开时间dsc->time_to_open = time_ms,以给出更高或更低的值。(保持不变以让 LVGL 控制它。)

每个缓存条目都有一个*“生命”值。每次通过缓存打开图像时,所有条目的生命值都会减少,使它们变得更旧。 当使用缓存的图像时,其生命值会增加打开时间*值,使其更有活力。

如果缓存中没有更多空间,将关闭生命值最低的条目。

内存使用

请注意,缓存的图像可能会持续消耗内存。例如,如果缓存了三个 PNG 图像,它们在打开时会消耗内存。

因此,用户有责任确保同时缓存最大的图像时有足够的 RAM。

清理缓存

假设您已将 PNG 图像加载到 lv_img_dsc_t my_png 变量中,并在 lv_img 对象中使用它。如果图像已缓存,然后您更改了底层 PNG 文件,则需要通知 LVGL 再次缓存图像。否则,没有简单的方法可以检测到底层文件已更改,LVGL 仍将从缓存中绘制旧图像。

为此,请使用 lv_img_cache_invalidate_src(&my_png)。如果将 NULL 作为参数传递,则整个缓存将被清理。

API

图像缓冲区

Typedefs

typedef uint8_t lv_img_cf_t

Enums

Values:

enumerator LV_IMG_CF_UNKNOWN
enumerator LV_IMG_CF_RAW

Contains the file as it is. Needs custom decoder function

enumerator LV_IMG_CF_RAW_ALPHA

Contains the file as it is. The image has alpha. Needs custom decoder function

enumerator LV_IMG_CF_RAW_CHROMA_KEYED

Contains the file as it is. The image is chroma keyed. Needs custom decoder function

enumerator LV_IMG_CF_TRUE_COLOR

Color format and depth should match with LV_COLOR settings

enumerator LV_IMG_CF_TRUE_COLOR_ALPHA

Same as LV_IMG_CF_TRUE_COLOR but every pixel has an alpha byte

enumerator LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED

Same as LV_IMG_CF_TRUE_COLOR but LV_COLOR_TRANSP pixels will be transparent

enumerator LV_IMG_CF_INDEXED_1BIT

Can have 2 different colors in a palette (can't be chroma keyed)

enumerator LV_IMG_CF_INDEXED_2BIT

Can have 4 different colors in a palette (can't be chroma keyed)

enumerator LV_IMG_CF_INDEXED_4BIT

Can have 16 different colors in a palette (can't be chroma keyed)

enumerator LV_IMG_CF_INDEXED_8BIT

Can have 256 different colors in a palette (can't be chroma keyed)

enumerator LV_IMG_CF_ALPHA_1BIT

Can have one color and it can be drawn or not

enumerator LV_IMG_CF_ALPHA_2BIT

Can have one color but 4 different alpha value

enumerator LV_IMG_CF_ALPHA_4BIT

Can have one color but 16 different alpha value

enumerator LV_IMG_CF_ALPHA_8BIT

Can have one color but 256 different alpha value

enumerator LV_IMG_CF_RGB888
enumerator LV_IMG_CF_RGBA8888
enumerator LV_IMG_CF_RGBX8888
enumerator LV_IMG_CF_RGB565
enumerator LV_IMG_CF_RGBA5658
enumerator LV_IMG_CF_RGB565A8
enumerator LV_IMG_CF_RESERVED_15

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_16

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_17

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_18

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_19

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_20

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_21

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_22

Reserved for further use.

enumerator LV_IMG_CF_RESERVED_23

Reserved for further use.

enumerator LV_IMG_CF_USER_ENCODED_0

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_1

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_2

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_3

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_4

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_5

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_6

User holder encoding format.

enumerator LV_IMG_CF_USER_ENCODED_7

User holder encoding format.

Functions

lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)

Allocate an image buffer in RAM

Parameters
  • w -- width of image

  • h -- height of image

  • cf -- a color format (LV_IMG_CF_...)

Returns

an allocated image, or NULL on failure

lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t *dsc, lv_coord_t x, lv_coord_t y, lv_color_t color)

Get the color of an image's pixel

Parameters
  • dsc -- an image descriptor

  • x -- x coordinate of the point to get

  • y -- x coordinate of the point to get

  • color -- the color of the image. In case of LV_IMG_CF_ALPHA_1/2/4/8 this color is used. Not used in other cases.

  • safe -- true: check out of bounds

Returns

color of the point

lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t *dsc, lv_coord_t x, lv_coord_t y)

Get the alpha value of an image's pixel

Parameters
  • dsc -- pointer to an image descriptor

  • x -- x coordinate of the point to set

  • y -- x coordinate of the point to set

  • safe -- true: check out of bounds

Returns

alpha value of the point

void lv_img_buf_set_px_color(lv_img_dsc_t *dsc, lv_coord_t x, lv_coord_t y, lv_color_t c)

Set the color of a pixel of an image. The alpha channel won't be affected.

Parameters
  • dsc -- pointer to an image descriptor

  • x -- x coordinate of the point to set

  • y -- x coordinate of the point to set

  • c -- color of the point

  • safe -- true: check out of bounds

void lv_img_buf_set_px_alpha(lv_img_dsc_t *dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa)

Set the alpha value of a pixel of an image. The color won't be affected

Parameters
  • dsc -- pointer to an image descriptor

  • x -- x coordinate of the point to set

  • y -- x coordinate of the point to set

  • opa -- the desired opacity

  • safe -- true: check out of bounds

void lv_img_buf_set_palette(lv_img_dsc_t *dsc, uint8_t id, lv_color_t c)

Set the palette color of an indexed image. Valid only for LV_IMG_CF_INDEXED1/2/4/8

Parameters
  • dsc -- pointer to an image descriptor

  • id -- the palette color to set:

    • for LV_IMG_CF_INDEXED1: 0..1

    • for LV_IMG_CF_INDEXED2: 0..3

    • for LV_IMG_CF_INDEXED4: 0..15

    • for LV_IMG_CF_INDEXED8: 0..255

  • c -- the color to set

void lv_img_buf_free(lv_img_dsc_t *dsc)

Free an allocated image buffer

Parameters

dsc -- image buffer to free

uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)

Get the memory consumption of a raw bitmap, given color format and dimensions.

Parameters
  • w -- width

  • h -- height

  • cf -- color format

Returns

size in bytes

void _lv_img_buf_get_transformed_area(lv_area_t *res, lv_coord_t w, lv_coord_t h, int16_t angle, uint16_t zoom, const lv_point_t *pivot)

Get the area of a rectangle if its rotated and scaled

Parameters
  • res -- store the coordinates here

  • w -- width of the rectangle to transform

  • h -- height of the rectangle to transform

  • angle -- angle of rotation

  • zoom -- zoom, (256 no zoom)

  • pivot -- x,y pivot coordinates of rotation

struct lv_img_header_t
#include <lv_img_buf.h>

The first 8 bit is very important to distinguish the different source types. For more info see lv_img_get_src_type() in lv_img.c On big endian systems the order is reversed so cf and always_zero must be at the end of the struct.

Public Members

uint32_t h
uint32_t w
uint32_t reserved
uint32_t always_zero
uint32_t cf
struct lv_img_dsc_t
#include <lv_img_buf.h>

Image header it is compatible with the result from image converter utility

Public Members

lv_img_header_t header

A header describing the basics of the image

uint32_t data_size

Size of the image in bytes

const uint8_t *data

Pointer to the data of the image