LVGL- 颜色转换系统和相关宏的使用技巧

news/2025/3/19 20:43:14/

LVGL是一个可以适配不同颜色深度的gui,显示像素可以从1,8,16,32等都可以很好的支持。
其中有一个很关键的函数,转换r,g,b显示像素到对应的目标显示器的格式,使用这个函数来适配不同的目标设备。
在文件lv_color.h中有相关的定义,我简单的梳理说明分析一下,详细的大家可以参考该源文件:
该函数如下,采用了inline方式定义,编译时会展开和替代,加快执行速度。

static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
{return _LV_COLOR_MAKE_TYPE_HELPER LV_COLOR_MAKE(r, g, b);
}

关于颜色通用类型 lv_color_t的定义,它是如何去自动适配1,8,16,32等不同颜色深度的呢?看看如下定义:

typedef union {uint8_t full; /*must be declared first to set all bits of byte via initializer list*/union {uint8_t blue : 1;uint8_t green : 1;uint8_t red : 1;} ch;
} lv_color1_t;typedef union {struct {uint8_t blue : 2;uint8_t green : 3;uint8_t red : 3;} ch;uint8_t full;
} lv_color8_t;typedef union {struct {
#if LV_COLOR_16_SWAP == 0uint16_t blue : 5;uint16_t green : 6;uint16_t red : 5;
#elseuint16_t green_h : 3;uint16_t red : 5;uint16_t blue : 5;uint16_t green_l : 3;
#endif} ch;uint16_t full;
} lv_color16_t;typedef union {struct {uint8_t blue;uint8_t green;uint8_t red;uint8_t alpha;} ch;uint32_t full;
} lv_color32_t;typedef LV_CONCAT3(uint, LV_COLOR_SIZE, _t) lv_color_int_t;
typedef LV_CONCAT3(lv_color, LV_COLOR_DEPTH, _t) lv_color_t;

系统分别用lv_color1_t,lv_color8_t,lv_color16_t,lv_color32_t的union类型定义了不同的颜色深度,这也将是最终使用的变量类型。
然后通过下面两个宏的连接和转换,最终转换为上面的变量类型。

typedef LV_CONCAT3(uint, LV_COLOR_SIZE, _t) lv_color_int_t;
typedef LV_CONCAT3(lv_color, LV_COLOR_DEPTH, _t) lv_color_t;

这个宏定义了目标系统的颜色深度:

/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 32

其中两个重要的宏:

  1. _LV_COLOR_MAKE_TYPE_HELPER,定义如下:
#if _LV_COLOR_HAS_MODERN_CPP
/*Fix msvc compiler error C4576 inside C++ code*/
#define _LV_COLOR_MAKE_TYPE_HELPER lv_color_t
#else
#define _LV_COLOR_MAKE_TYPE_HELPER (lv_color_t)
#endif

为什么要用这个宏来定义呢?差异就在那一组括号,主要原因就是c和c++对类型转换的语法差异。避免出现编译时候出现错误:
warning :C4576 后跟初始值设定项列表的带圆括号类型是一个非标准的显式类型转换语法

  1. 另外一个宏:
#define LV_COLOR_MAKE(r8, g8, b8) LV_CONCAT(LV_COLOR_MAKE, LV_COLOR_DEPTH)(r8, g8, b8)
#define _LV_CONCAT(x, y) x ## y
#define LV_CONCAT(x, y) _LV_CONCAT(x, y)
//这里定义了一系列的32bit颜色操作宏
# define LV_COLOR_SET_R32(c, v) (c).ch.red = (uint8_t)((v) & 0xFF)
# define LV_COLOR_SET_G32(c, v) (c).ch.green = (uint8_t)((v) & 0xFF)
# define LV_COLOR_SET_B32(c, v) (c).ch.blue = (uint8_t)((v) & 0xFF)
# define LV_COLOR_SET_A32(c, v) (c).ch.alpha = (uint8_t)((v) & 0xFF)# define LV_COLOR_GET_R32(c) (c).ch.red
# define LV_COLOR_GET_G32(c) (c).ch.green
# define LV_COLOR_GET_B32(c) (c).ch.blue
# define LV_COLOR_GET_A32(c) (c).ch.alpha# define _LV_COLOR_ZERO_INITIALIZER32  {{0x00, 0x00, 0x00, 0x00}}
# define LV_COLOR_MAKE32(r8, g8, b8) {{b8, g8, r8, 0xff}} /*Fix 0xff alpha*/
//类似的也定义了很多其他颜色位数操作的宏
# define LV_COLOR_SET_R16(c, v) (c).ch.red = (uint8_t)((v) & 0x1FU)
#if LV_COLOR_16_SWAP == 0
# define LV_COLOR_SET_G16(c, v) (c).ch.green = (uint8_t)((v) & 0x3FU)
#else
# define LV_COLOR_SET_G16(c, v) {(c).ch.green_h = (uint8_t)(((v) >> 3) & 0x7); (c).ch.green_l = (uint8_t)((v) & 0x7);}
#endif
# define LV_COLOR_SET_B16(c, v) (c).ch.blue = (uint8_t)((v) & 0x1FU)
# define LV_COLOR_SET_A16(c, v) do {} while(0)# define LV_COLOR_GET_R16(c) (c).ch.red
#if LV_COLOR_16_SWAP == 0
# define LV_COLOR_GET_G16(c) (c).ch.green
#else
# define LV_COLOR_GET_G16(c) (((c).ch.green_h << 3) + (c).ch.green_l)
#endif
# define LV_COLOR_GET_B16(c) (c).ch.blue
# define LV_COLOR_GET_A16(c) 0xFF#if LV_COLOR_16_SWAP == 0
# define _LV_COLOR_ZERO_INITIALIZER16  {{0x00, 0x00, 0x00}}
# define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x3FU), (uint8_t)((r8 >> 3) & 0x1FU)}}
#else
# define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00, 0x00}}
# define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 3) & 0x1FU), (uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x7U)}}
#endif# define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 3) & 0x1FU), (uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x7U)}}

我们看完这几个宏的定义后,来逐步展开一下最开始的那个函数调用,看看最终是什么样子:

  return _LV_COLOR_MAKE_TYPE_HELPER LV_COLOR_MAKE(r, g, b);//第一步:_LV_COLOR_MAKE_TYPE_HELPER 替换后return lv_color_t LV_COLOR_MAKE(r, g, b);//第二步 LV_COLOR_MAKE宏被替换后return lv_color_t LV_CONCAT(LV_COLOR_MAKE, LV_COLOR_DEPTH)(r8, g8, b8);//第三步 LV_CONCAT宏被替换后,假如此时LV_COLOR_DEPTH等于32return lv_color_t LV_COLOR_MAKE32((r8, g8, b8);//第四步 LV_COLOR_MAKE32宏被替换return lv_color_t {{b8, g8, r8, 0xff}};/*第五步 调用lv_color_make被替换,比如:bg_color = lv_color_make(0xf1, 0xf2, 0xf3);根据目标系统的大小端不同,最终会被替换为如下之一的赋值调用*/bg_color = 0xFFF1F2F3;//或者bg_color = 0xF3F2F1FF;
;

看完这一系列“眼花缭乱”的转换,替换后,你也许在嘀咕,简单的赋值不是更好吗,搞得这么“花里胡哨”的,有必要吗?
我可以很负责人的告诉你,很有必要。为什么?
因为lvgl是一个通用的可以适配不同颜色深度像素的gui系统,要做到最大化,最简单的兼容这些系统,让用户无感,对应用代码不产生影响,具有最大的移植性,这是非常必要的。系统编译的时候就可以自动根据配置信息来选择合适的目标颜色系统,完成对应的操作。


http://www.ppmy.cn/news/71689.html

相关文章

如何使用Sentinel做流量控制?此文将附代码详细介绍Sentinel几种限流模式

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章将详细介绍Sentinel的两种限流模式&#xff0c;由于篇幅原因&#xff0c;后续文章将详细介绍Sentinel的其他三种。 如果文章有什么需要改进的地方还请大佬不吝赐教…

Centos7连接外网的相关配置与实现yum本地与网络配置(yum配置不使用wget)

目录 一、背景 二、实现连接外网的相关配置 1&#xff09;查看物理机的IP相关信息 2&#xff09;配置物理机指定IP 3&#xff09;根据物理机配置虚拟机网卡 4&#xff09;进入虚拟机&#xff0c;配置网卡 三、yum配置 1&#xff09;切换到yum软件仓库配置文件目录中 2…

18130 繁忙的公路

Description 在一条笔直的大道&#xff08;单方向行车道&#xff09;上&#xff0c;汽车川流不息。道路从起点到终点&#xff0c;等距离的标记了1到N&#xff0c; 即起点是1&#xff0c;然后分别是2、3、4.....&#xff0c;终点是N。每一个标记处&#xff0c;安装了智能探头&a…

dbForge Studio for SQL Server Crack

dbForge Studio for SQL Server Crack 增加了对源代码管理中的数据操作语言(DML)触发器排序的支持。 添加了对不使用EXEC/EXECUTE关键字调用过程/函数的语法支持。 在语法检查中添加了对EXEC命令的支持。 dbForge Studio for SQL Server是一个IDE&#xff0c;用于SQL Server中的…

云计算多租户安全

目录 ​编辑必要的安全措施 概念 多租户如何运作 云计算中多租户有什么好处?

[mybatis]resultMap配置

<resultMap id"brandResultMap" type"brand"><!--id&#xff1a;完成主键字段的映射column&#xff1a;表的列名property&#xff1a;实体类的属性名result&#xff1a;完成一般字段的映射column&#xff1a;表的列名property&#xff1a;实体类的…

微信小程序入门04-后端脚手架搭建

我们上一篇已经介绍了权限系统的库表搭建&#xff0c;光有表还是不够的&#xff0c;我们还需要有一个后台系统和数据库进行交互。搭建后台的时候既需要选择使用什么语言&#xff0c;也需要选择框架。 框架分为前端框架和后端框架。在第一篇微信开发者工具搭建的时候我们其实前…

一个人的工作表现体现在哪些方面?

工作表现专业技能性格职业态度。 大多数时候&#xff0c;作为员工&#xff0c;我们可能只关注了自己的专业能力&#xff0c;但是换个角度&#xff0c;以领导的视角来看&#xff0c;一般会从这三个方面来对一个员工进行评估&#xff0c;即专业技能&#xff0c;性格和职业态度。 …