更多源码分析请访问:LVGL 源码分析大全
目录
- 1、概述
- 2、颜色格式详解
- 2.1、LV_IMG_CF_RAW_X
- 2.2、LV_IMG_CF_TRUE_COLOR_X
- 2.3、LV_IMG_CF_INDEXED_XBIT
- 2.4、LV_IMG_CF_ALPHA_XBIT
- 2.5、LV_IMG_CF_RGBX
- 3、送显函数(flush_cb)中的 lv_color_t
- 附录
- A、通过`lv_img_conv.js`生成的代码
- A.1 CF_ALPHA_X_BIT
- A.1.1 CF_ALPHA_1_BIT
- A.1.2 CF_ALPHA_2_BIT
- A.1.3 CF_ALPHA_4_BIT
- A.1.4 CF_ALPHA_8_BIT
- A.2 CF_INDEXED_X_BIT
- A.2.1 CF_INDEXED_1_BIT
- A.2.2 CF_INDEXED_2_BIT
- A.2.3 CF_INDEXED_4_BIT
- A.2.4 CF_INDEXED_8_BIT
- A.3 CF_RAW_X
- A.3.1 CF_RAW
- A.3.2 CF_RAW_ALPHA
- A.3.3 CF_RAW_CHROMA
- A.4 CF_TRUE_COLOR_X
- A.4.1 CF_TRUE_COLOR
- A.4.2 CF_TRUE_COLOR_ALPHA
- A.4.3 CF_TRUE_COLOR_CHROMA
- A.5 CF_RGB565A8
- B、lv_img_cf_t 的定义
1、概述
本章节从一个特殊的4x2的32位真彩色的长方形图片,通过工具 lv_img_conv.js生成不同的内置图片数据来入手,以更深入的了解LVGL中像素的处理思路和逻辑。
特殊的4x2的长方形图片是为了更方便我们理解像素的排布和处理逻辑,其原始数据被设置如下:
{0xFFAABBCC, 0xFFAA0000, 0xFF00BB00, 0xFF0000CC, 0x7F0000CC, 0x7F00BB00, 0x7FAA0000, 0x7FAABBCC}
小白提醒:
lv_img_conv.js
转换时,最好先将图片转换成png格式,因为使用bmp或者其它格式图片存在生成的数据丢失透明度的问题。
此案例中,我们转换了以下格式,在附录中,可以找到对应格式的数据截图:
CF_ALPHA_1_BIT
,CF_ALPHA_2_BIT
,CF_ALPHA_4_BIT
,CF_ALPHA_8_BIT
CF_INDEXED_1_BIT
,CF_INDEXED_2_BIT
,CF_INDEXED_4_BIT
,CF_INDEXED_8_BIT
CF_RAW
,CF_RAW_CHROMA
,CF_RAW_ALPHA
CF_TRUE_COLOR
,CF_TRUE_COLOR_ALPHA
,CF_TRUE_COLOR_CHROMA
CF_RGB565A8
生成的内置图片数据被定义为一个lv_img_dsc_t
结构体供其它地址使用,这个结构体定义如下:
/*** 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.*/
#if LV_BIG_ENDIAN_SYSTEM
typedef struct {uint32_t h : 11; /*Height of the image map*/uint32_t w : 11; /*Width of the image map*/uint32_t reserved : 2; /*Reserved to be used later*/uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like anon-printable character*/uint32_t cf : 5; /*Color format: See `lv_img_color_format_t`*/} lv_img_header_t;
#else
typedef struct {uint32_t cf : 5; /*Color format: See `lv_img_color_format_t`*/uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like anon-printable character*/uint32_t reserved : 2; /*Reserved to be used later*/uint32_t w : 11; /*Width of the image map*/uint32_t h : 11; /*Height of the image map*/
} lv_img_header_t;
#endif/** Image header it is compatible with* the result from image converter utility*/
typedef struct {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*/
} lv_img_dsc_t;
在lv_img_dsc_t
结构体,有一个颜色格式(Color format)字段(header.cf
),决定了对数据的处理逻辑,它被定义为lv_img_cf_t
的枚举类型。
而这个lv_img_cf_t
枚举分为了八类处理逻辑:
- LV_IMG_CF_UNKNOWN 未知,资源可能出错了;
- LV_IMG_CF_RAW_X 包含
LV_IMG_CF_RAW
,LV_IMG_CF_RAW_ALPHA
和LV_IMG_CF_RAW_CHROMA_KEYED
三种,表示此资源是一个原始数据资源,需要开发者先解码后才能使用; - LV_IMG_CF_TRUE_COLOR_X 包含
LV_IMG_CF_TRUE_COLOR
,LV_IMG_CF_TRUE_COLOR_ALPHA
和LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED
三种,表示此资源是一个解码后的数据,解码后的数据具体使用的那种格式,取决于LVGL的宏LV_COLOR_DEPTH
和LV_COLOR_16_SWAP
参数配置; - LV_IMG_CF_INDEXED_XBIT 包含
LV_IMG_CF_INDEXED_1BIT
,LV_IMG_CF_INDEXED_2BIT
,LV_IMG_CF_INDEXED_4BIT
和LV_IMG_CF_INDEXED_8BIT
四种,表示这是一个颜色表+索引值方式保存的图片资源,其中颜色表的大小由XBIT
决定(1BIT
表示2位,2BIT
表示4位,4BIT
表示16位,8BIT
表示256位); - LV_IMG_CF_ALPHA_XBIT 包含
LV_IMG_CF_ALPHA_1BIT
,LV_IMG_CF_ALPHA_2BIT
,LV_IMG_CF_ALPHA_4BIT
和LV_IMG_CF_ALPHA_8BIT
四种,表示这是一个透明色表资源(没有像素信息,只有像素点上透明色的值),其中透明色的大小由XBIT
决定(1BIT
表示1位,2BIT
表示2位,4BIT
表示4位,8BIT
表示8位); - LV_IMG_CF_RGBX 包含
LV_IMG_CF_RGB888
,LV_IMG_CF_RGBA8888
,LV_IMG_CF_RGBX8888
,LV_IMG_CF_RGB565
,LV_IMG_CF_RGBA5658
,LV_IMG_CF_RGB565A8
六种,这是实现在图片送显或者处理中的数据格式; - LV_IMG_CF_RESERVED_X 预留字段,官方没有给处理方案或者逻辑,如果使用,需要开发者自行处理;
- LV_IMG_CF_USER_ENCODED_X 开发者自定义加密数据处理,需要先解密再做其它处理;
2、颜色格式详解
2.1、LV_IMG_CF_RAW_X
此类颜色格式常用于保存原始的需要解码的图片资源,也可以用来保存JOSN
、音频
等需要内置的资源。它具体有三种LV_IMG_CF_RAW
, LV_IMG_CF_RAW_ALPHA
和LV_IMG_CF_RAW_CHROMA_KEYED
,这三种在LVGL里分别对应三种处理逻辑,如下表所示:
LV_IMG_CF_RAW | LV_IMG_CF_RAW_ALPHA | LV_IMG_CF_RAW_CHROMA_KEYED |
---|---|---|
1、表示lv_img_dsc_t 结构中的data字段保存的数据即为文件原始二进制数据 | 1、表示lv_img_dsc_t 结构中的data字段保存的数据即为文件原始二进制数据 | 1、表示lv_img_dsc_t 结构中的data字段保存的数据即为文件原始二进制数据 |
2、如果是图片,数据中没有透明色(即便有,应当丢弃) | 2、如果是图片,数据中包含透明色,应当使用此透明色进行图层混合 | 2、如果是图片,当像素为LV_COLOR_CHROMA_KEY 定义字段,应当将其像素点的透明色改为全透明色,否则为不透明 |
因此使用工具生成的LV_IMG_CF_RAW
, LV_IMG_CF_RAW_ALPHA
和LV_IMG_CF_RAW_CHROMA_KEYED
三种类型的文件,仅是.header.cf
字段上有差异,而其它的都是一样的数据;但在LVGL里的默认处理逻辑,却是不一样的。如下图所示:
小白提醒:
1、LV_IMG_CF_RAW_X 类型多为开发者自解析或操作资源,因此实际项目中到底有没有遵循这一约束,实际上是不可控的,这里讲的是LVGL框架上计划或推荐使用的处理逻辑。
2、LV_IMG_CF_RAW_CHROMA_KEYED 多用于扣图显示逻辑中,应用最多的,就是将绿色(0x00FF00)的像素点全部换成透明色,以显示下一个图层的内容(拍摄中的小绿人,或者绿色布,多用这种方法替换成其它背景的)。
2.2、LV_IMG_CF_TRUE_COLOR_X
此类颜色格式是完全解码后的数据(真彩色),但解码后的数据使用的是 BGRA888
还是 BGR565
取决于LV_COLOR_DEPTH
参数的配置。 仅对比生成的数据, LV_IMG_CF_TRUE_COLOR
与 LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED
生成的数据是一样的,而LV_IMG_CF_TRUE_COLOR_ALPHA
多了一个字节的透明色值。
实际的像素格式,列举如下:
LV_COLOR_DEPTH | LV_COLOR_16_SWAP | 数据格式 | LV_IMG_CF_TRUE_COLOR 示例 |
---|---|---|---|
32 | 无效 | BGRA888 (透明色全为0xFF) | |
16 | 1 | RGB565 | |
16 | 0 | BGR565 | |
8(或1) | 无效 | BGR332 |
LV_COLOR_DEPTH | LV_COLOR_16_SWAP | 数据格式 | LV_IMG_CF_TRUE_COLOR_ALPHA 示例 |
---|---|---|---|
32 | 无效 | BGRA888 (透明色为实际值) | |
16 | 1 | RGB565A8 | |
16 | 0 | BGR565A8 | |
8(或1) | 无效 | BGR332A8 |
小白提醒:
1、此种格式保存下来的图片资源占用空间是非常大的,唯一的好处是不用解码而可以直接使用;因此多用于对性能要求比较高的图片使用场景中(例如动画)
2.3、LV_IMG_CF_INDEXED_XBIT
此类颜色是颜色表+索引的方式保存的,多用于缩小图片资源的大小。LVGL在使用时,会先转换成 LV_IMG_CF_TRUE_COLOR_ALPHA
格式,因此在使用中,要考虑性能是否足够。
LV_IMG_CF_INDEXED_2_BIT
、LV_IMG_CF_INDEXED_4_BIT
和LV_IMG_CF_INDEXED_8_BIT
的颜色表是固定BGRA888格式,其颜色表长度分别2、4、16和256(不足的会用0x00000000来补全,如果颜色表超出会进行合并);
XBIT中的X代表索引占用的BIT位大小。
小白提醒
LV_IMG_CF_INDEXED_1_BIT 格式似乎与此说法不太符。因无项目使用此格式,未深入研究原因。
2.4、LV_IMG_CF_ALPHA_XBIT
此类型颜色格式仅保存了XBIT位的透明色值,多用于指定区域挖洞(挖洞后显示视频等)。
小白提醒
LV_IMG_CF_ALPHA_1_BIT 格式似乎与此说法不太符。因无项目使用此格式,未深入研究原因。
2.5、LV_IMG_CF_RGBX
LV_IMG_CF_RGBX 为具体实际的像素格式,但LVGL的格式定义与FFMPEG
等主流的常见像素格式定义方式不太一样,个人也不知道具体原因。具体数据格式对应表如下:
LVGL像素格式 | FFMPG像素格式 | 说明 |
---|---|---|
LV_IMG_CF_RGB888 | BGR888 | char buf[3]; #define B buf[0] #define G buf[1] #define R buf[2] |
LV_IMG_CF_RGBA8888 | BGRA8888 | char buf[4]; #define B buf[0] #define G buf[1] #define R buf[2] #define A buf[3] |
LV_IMG_CF_RGBX8888 | BGRX8888 | char buf[4]; #define B buf[0] #define G buf[1] #define R buf[2] 其中buf[3]为无效值 |
LV_IMG_CF_RGB565 | BGR565 | char buf[2]; #define B (buf[0] & 0x1F) #define G ((buf[0] & 0xE0) >> 3) | (buf[1] >> 5)) #define R (buf[1] & 0x1F) |
LV_IMG_CF_RGBA5658 | BGRA5658 | char buf[3]; #define B (buf[0] & 0x1F) #define G ((buf[0] & 0xE0) >> 3) | (buf[1] >> 5)) #define R (buf[1] & 0x1F) #define A buf[3] |
LV_IMG_CF_RGB565A8 | BGR565A8 | char buf[3]; #define B (buf[0] & 0x1F) #define G ((buf[0] & 0xE0) >> 3) | (buf[1] >> 5)) #define R (buf[1] & 0x1F) #define A buf[3] |
小白提醒
从表中看LV_IMG_CF_RGB565A8
与LV_IMG_CF_RGBA5658
似乎是一样的,实现是有区别的。LV_IMG_CF_RGBA5658
的数据排布是BGRABGRA...
的方式排布的,而LV_IMG_CF_RGB565A8
的数据排布却是BGRBGR...AA...
3、送显函数(flush_cb)中的 lv_color_t
送显函数中的 lv_color_t定义是由LV_COLOR_DEPTH
和LV_COLOR_16_SWAP
决定的。对应的具体格式如下表所示:
LV_COLOR_DEPTH | LV_COLOR_16_SWAP | 数据格式 | 说明 |
---|---|---|---|
32 | 无效 | BGRA888(LV_IMG_CF_RGBA8888) | 带透明度,多用于Linux上或者RGB/MIPI等带透明色的32位屏 |
16 | 1 | RGB565 | 多用于SPI屏 |
16 | 0 | BGR565(LV_IMG_CF_RGB565) | 多用于SPI屏 |
8 | 无效 | BGR332 | 没用过 |
1 | 无效 | BGR111 | 没用过 |
附录
A、通过lv_img_conv.js
生成的代码
A.1 CF_ALPHA_X_BIT
A.1.1 CF_ALPHA_1_BIT
A.1.2 CF_ALPHA_2_BIT
A.1.3 CF_ALPHA_4_BIT
A.1.4 CF_ALPHA_8_BIT
A.2 CF_INDEXED_X_BIT
A.2.1 CF_INDEXED_1_BIT
A.2.2 CF_INDEXED_2_BIT
A.2.3 CF_INDEXED_4_BIT
A.2.4 CF_INDEXED_8_BIT
A.3 CF_RAW_X
A.3.1 CF_RAW
A.3.2 CF_RAW_ALPHA
A.3.3 CF_RAW_CHROMA
A.4 CF_TRUE_COLOR_X
A.4.1 CF_TRUE_COLOR
A.4.2 CF_TRUE_COLOR_ALPHA
A.4.3 CF_TRUE_COLOR_CHROMA
A.5 CF_RGB565A8
B、lv_img_cf_t 的定义
lv_img_cf_t 定义在lvgl/src/draw/lv_img_buf.h
/*Image color format*/
enum {LV_IMG_CF_UNKNOWN = 0,LV_IMG_CF_RAW, /**< Contains the file as it is. Needs custom decoder function*/LV_IMG_CF_RAW_ALPHA, /**< Contains the file as it is. The image has alpha. Needs custom decoderfunction*/LV_IMG_CF_RAW_CHROMA_KEYED, /**< Contains the file as it is. The image is chroma keyed. Needscustom decoder function*/LV_IMG_CF_TRUE_COLOR, /**< Color format and depth should match with LV_COLOR settings*/LV_IMG_CF_TRUE_COLOR_ALPHA, /**< Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /**< Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixelswill be transparent*/LV_IMG_CF_INDEXED_1BIT, /**< Can have 2 different colors in a palette (can't be chroma keyed)*/LV_IMG_CF_INDEXED_2BIT, /**< Can have 4 different colors in a palette (can't be chroma keyed)*/LV_IMG_CF_INDEXED_4BIT, /**< Can have 16 different colors in a palette (can't be chroma keyed)*/LV_IMG_CF_INDEXED_8BIT, /**< Can have 256 different colors in a palette (can't be chroma keyed)*/LV_IMG_CF_ALPHA_1BIT, /**< Can have one color and it can be drawn or not*/LV_IMG_CF_ALPHA_2BIT, /**< Can have one color but 4 different alpha value*/LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/LV_IMG_CF_RGB888,LV_IMG_CF_RGBA8888,LV_IMG_CF_RGBX8888,LV_IMG_CF_RGB565,LV_IMG_CF_RGBA5658,LV_IMG_CF_RGB565A8,LV_IMG_CF_RESERVED_15, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_16, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_17, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_18, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_19, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_20, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_21, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_22, /**< Reserved for further use.*/LV_IMG_CF_RESERVED_23, /**< Reserved for further use.*/LV_IMG_CF_USER_ENCODED_0, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_1, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_2, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_3, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_4, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_5, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_6, /**< User holder encoding format.*/LV_IMG_CF_USER_ENCODED_7, /**< User holder encoding format.*/
};
typedef uint8_t lv_img_cf_t;