ESP32开发学习 LVGL Littlevgl 解码显示JPG图片三种方式JPG_SJPG_C Array

最终运行效果,三张图,三种方式:jpg,sjpg,c_array

        LVGL开发中经常用到图片显示,LVGL官方有提供PNG,GIF,JPG等解码库,配合LVGL的虚拟文件系统可以实现控件直接加载调用解码库解码并显示,非常的方便。

        此篇文章就介绍如何移植LVGL官方的JPG解码库,通过三种方式来显示JPG图片。

1、文件系统加载JPG文件解码显示

      此方法占用RAM多,占用ROM少,解码速度慢

2、转换为SJPG文件通过解码文件系统加载显示

      sjpg 是一种基于“普通”JPG 的自定义格式,专为 lvgl 制作。sjpg 是“split-jpeg”,它是一捆带有 sjpg 标头的小 jpeg 片段。解码更快,体积更小,占用内存也小。要通过LVGL提供的python脚本来转换。

3、转换为数组加载显示

      将JPG解码,把其中的有效像素提取为C数组,以.c文件的方式存储在代码中。此方法解码速度最快,占用内存少,占用ROM最多。

本文开发环境:
Visual Studio Code V1.58.2

LVGL版本 V7.10.0

芯片平台:ESP32

IDF库版本:4.3.0

IDF TOOLS编译工具链版本:2.9

本文软件基于LVGL官方提供的ESP32工程lv_port_esp32修改而来

LVGL ESP32官方地址:https://github.com/lvgl/lv_port_esp32

开发板平台:HelloBug ESP32开发板

开发板购买链接:https://hellobug.taobao.com/

注意:在开始之前请确认上述开发环境,并确认你的源码必须已经移植并对接了LVGL的虚拟文件系统。没有实现的朋友参考我的另一篇文章:ESP32开发学习 LVGL Littlevgl 使用文件系统

一、移植LVGL_JPG/SJPG解码库

第一步就是先下载lvgl官方的JPG/SJPG解码库

git地址:https://github.com/lvgl/lv_lib_split_jpg

将下载好的的解码库解压至你的工程目录components文件夹中,目录结构如下: 

下载好的解码库中是没有CMakeLists.txt这个文件的,我们的工程是没办法调用这个库的,我们在lv_lib_split_jpg文件夹中创建一个,内容如下:

接着修改main文件夹中的CMakeLists.txt,idf_component_register中添加注册lv_lib_split_jpg解码组件,结果如下图:

 在main.c中添加lv_sjpg.h解码库头文件

 在main.c中lvgl初始化 文件系统初始化之后添加jpg解码库初始化

至此,解码库的移植就完成了,接下来就是调用解码了。

看以下三步前,请确保你的lvgl工程已经对接文件系统

二、解码显示JPG文件

直接调用SD卡里面的JPG解码显示,非常简单,三行代码就能实现,其中S:/image/test_jpg.jpg是你的SD卡中的图片路径(注意,图片不要太大,否则会内存分配失败

	//////////////////////////////////////////////////////////
	/////////创建一个IMG对象并加载SD卡中的jpg图片解码显示///////////
	//////////////////////////////////////////////////////////
	lv_obj_t * objpg =  lv_img_create(main_scr, NULL);				// 创建一个IMG对象 
	lv_img_set_src(objpg, "S:/image/test_jpg.jpg");					// 加载SD卡中的JPG图片
	lv_obj_align(objpg, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);			// 重新设置对齐

三、解码显示SJPG文件

SJPG占用内存小,是专门针对LVGL的,LVGL官方做了一个python脚本来转换格式,SJPG文件更小,但不能在电脑上打开查看。接下来讲解脚本使用方法和调用图片方法

1、安装python

LVGL官方提供的转换工具是一个python脚本,你的电脑上必须要有python环境,开发ESP32编译时也用到python脚本,也必须要安装python,所以这里安装方法不在详细说明,网上很多教程,我的博客ESP32开发环境搭建中也有Python安装的教程,需要注意的一点就是安装时要将Python添加到系统变量的一个选择勾选一下即可。其它全部默认

2、安装python PIL模块

图片转换需要用到Python的PIL模块,python默认安装是没有的,如果不安装,转换图片会提示没有PIL模块,具体安装解决办法请看我的另一篇文章:报错:ModuleNotFoundError: No module named ‘PIL‘解决方法

3、转换JPG到SJPG

接下来就是转换脚本的使用了,文章第一步时我们从LVGL git上下载了jpg解码库,转换脚本就在里面,在电脑上打开你的工程目录中components\lv_lib_split_jpg\scripts这个路径,里面有一个jpg_to_sjpg.py的python脚本。先下载张jpg图片,放在此文件夹中。

 复制此文件夹的目录,打开系统cmd窗口,在命令行进入脚本所在的路径。

 接下来输入命令来转换图片格式,命令:jpg_to_sjpg.py jpg_100.jpg

其中jpg_100.jpg是我刚才下载的图片,敲回车开始转换,转换非常快,不到0.1秒

 成功后查看这个目录中,生成了两个文件:jpg_100.sjpg     jpg_100.c,其中.c的文件是我们第四步要用到的,懂的同学看到.c就知道怎么用了,这里先不讲。

 4、调用SJPG解码显示

将上一步生成的.sjpg文件放到你的sd卡中,插入开发板。

然后编写代码调用它,非常简单,也是三行代码即可。

	//////////////////////////////////////////////////////////
	/////////创建一个IMG对象并加载SD卡中的sjpg图片解码显示//////////
	//////////////////////////////////////////////////////////
	lv_obj_t * obsjpg =  lv_img_create(main_scr, NULL);				// 创建一个IMG对象 
	lv_img_set_src(obsjpg, "S:/image/test_sjpg.sjpg");				// 加载SD卡中的SJPG图片
	lv_obj_align(obsjpg, NULL, LV_ALIGN_IN_TOP_LEFT, 200, 0);		// 重新设置对齐

四、解码显示C Array数组的JPG文件

经过第三步其实我们已经将JPG文件转换成了C语言数组,就是那个 jpg_100.c文件,接下来就简单了。将 jpg_100.c文件移动到工程目录下components\lv_examples\lv_examples\assets资源目录下,这里不要复制,要剪切,因为生成的.c文件也在工程目录里面,只是要移动一个位置,不然会有两个相同的文件。

接下来在main.c中定义引用:LV_IMG_DECLARE(jpg_100);

 在lvgl代码中同样的添加三行代码即可调用显示

	//////////////////////////////////////////////////////////
	/////////创建一个IMG对象并加载ROM中的jpg图片C Array数组显示/////
	//////////////////////////////////////////////////////////
	lv_obj_t * carrayjpg =  lv_img_create(main_scr, NULL);			// 创建一个IMG对象 
	lv_img_set_src(carrayjpg, &jpg_100);							// ROM中的jpg图片C Array数组显示
	lv_obj_align(carrayjpg, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 100);	// 重新设置对齐

最终运行效果

三张图,三种方式:jpg,sjpg,c_array

 

<think>我们正在讨论的是LVGL库中图片格式支持的问题。用户询问是否可以直接加载常见图片格式如JPG、JPEG、PNG和BMP。根据引用[2]中的信息,LVGLJPG的支持是有限的,它会消耗大量RAM,而且官方仅推荐在具有更多RAM的设备上使用。同时,LVGL提供的JPG解码器功能有限,无法进行缩放或旋转。此外,引用[1]中展示了如何通过转换工具将图片转换为C数组(lv_img_dsc_t结构)来加载图片。关键点:1.LVGL不能直接加载原始图片文件(如.jpg,.png等),必须通过转换工具预处理为C数组或二进制格式(.bin文件)才能使用。2.转换后的数据通过lv_image_set_src()函数加载,支持两种形式:-内存中的C数组(使用LV_IMG_DECLARE声明)-文件系统中的.bin文件(需要文件系统支持)3.对于GIF动画,引用[1]中显示可以使用lv_gif_create和lv_gif_set_src直接加载GIF文件(但注意这可能是特定于GIF的扩展,且同样需要转换?引用中显示直接使用路径,但实际GIF也需要转换吗?需要澄清。)引用[1]中的代码片段显示:-转换后的图片数据(如PNG/BMP等)被转换为C数组,然后封装在lv_img_dsc_t结构中。-对于GIF,示例中直接使用了路径("S:/images/1.gif"),这意味着LVGL可能内置了对GIF的支持(但注意:GIF文件同样需要符合LVGL的要求,可能是转换后的?或者LVGL内置了解码GIF的库?)但根据LVGL官方文档,通常图片(包括GIF)也需要通过转换工具转换成内部格式。然而,在v8.0以后,LVGL支持了真正的GIF解码(通过内置的GIF解码器)。因此,对于GIF,我们可以直接加载.gif文件,只要LVGL配置中启用了GIF支持(通过lv_conf.h中的LV_USE_GIF)。同理,对于PNG,LVGL也提供了内置解码器(需要启用LV_USE_PNG),但同样会消耗较多内存。对于BMP,内置解码器(LV_USE_BMP)同样需要启用。但请注意:内置解码器(JPG/PNG/BMP/GIF)通常需要更多的RAM和ROM(解码代码占用空间),因此在小资源设备上可能仍然推荐使用转换工具预处理为C数组或二进制格式。总结直接加载原始图片文件的可能性:-JPG:支持,但有限制(见引用[2]),需要启用LV_USE_SJPG(或LV_USE_JPG?注意引用[2]提到官方推荐设备有更多RAM时使用)。-PNG:需要启用LV_USE_PNG,并链接png解码库(如lodepng,LVGL内置了解码器)。-BMP:需要启用LV_USE_BMP,内置解码器支持。-GIF:需要启用LV_USE_GIF,内置解码器支持。但是,即使启用了这些内置解码器,直接加载原始图片文件也会带来运行时内存和性能的开销。因此,对于资源受限的嵌入式设备,官方推荐使用转换工具将图片转换为C数组或二进制格式(TrueColor或带Alpha的TrueColor,根据颜色深度设置)。如何直接加载常见图片格式(前提:启用对应的解码器并满足内存要求):1.在lv_conf.h中启用相应的宏:```c#defineLV_USE_PNG1#defineLV_USE_BMP1#defineLV_USE_SJPG1//用于JPG解码(支持splitJPG,即SJPG,可以逐行解码减少内存使用)#defineLV_USE_GIF1```2.确保相应的解码器代码被包含(如果是SJPG,还需要文件系统支持,因为SJPG允许分块读取;而JPG解码器需要整个文件在内存中)。3.然后,可以直接使用文件路径加载图片:```c//加载PNGlv_image_set_src(img,"S:/image.png");//加载BMPlv_image_set_src(img,"S:/image.bmp");//加载JPG(使用SJPG,即SplitJPG,以减少内存使用)lv_image_set_src(img,"S:/image.jpg");//加载GIFlv_image_set_src(img,"S:/image.gif");```但是,请注意JPG解码有两种模式:-普通JPG解码(LV_USE_JPG):需要将整个JPG文件加载到内存,并且解码需要整个图片的RAM(未压缩的尺寸)。这对于大图片来说内存消耗很大。-分割JPG(LV_USE_SJPG):允许逐行解码,因此不需要整个图片的RAM,但需要文件系统支持分块读取。内存使用更少,推荐使用。因此,对于JPG,建议使用分割JPG模式(SJPG)以节省内存。但无论哪种模式,都需要在lv_conf.h中启用相应的宏。另外,直接加载原始图片文件需要文件系统的支持(如FATFS等),并且路径前缀(如"S:")需要正确配置。如果不想使用文件系统,也可以将原始图片文件转换为C数组,然后通过内存加载。但此时,如果原始图片JPG/PNG等压缩格式,转换后的C数组是解压缩后的像素数据,所以体积会很大(例如,一个1024x768的RGB565图片需要1024*768*2=1.5MB的Flash空间)。而使用内置解码器,则只需要存储压缩后的图片数据(如JPG/PNG文件本身),可以节省Flash空间(但运行时需要解码,占用RAM)。因此,在资源有限的系统上,需要在Flash空间和RAM之间做权衡。回答用户的直接问题:-**支持的图片格式**:LVGL支持JPG(通过内置解码器,但内存使用高)、PNG(内置解码器,需要额外库)、BMP(内置解码器)和GIF(内置解码器),以及通过转换工具转换后的C数组或二进制格式(支持TrueColor,TrueColorwithAlpha,Indexed等)。-**如何直接加载**:在配置中启用对应的解码器宏,然后使用lv_image_set_src()并传入文件路径即可。但需要注意内存和Flash的限制。最后,强调转换工具预处理的方法仍然是官方推荐的标准方法,特别是在资源有限的设备上。根据以上分析,构建回答:</think> 在 LVGL 框架中,**不支持直接加载原始图像文件**(如 JPG、JPEG、PNG、BMP),但可通过以下方式使用这些图片格式: ### ⚙ LVGL 支持图片格式的处理方式 | **格式类型** | **支持程度** | **处理方式** | **内存开销** | |-------------|------------|-------------|------------| | **原始格式<br>(JPG/JPEG/PNG/BMP)** | 🔶 有限支持 | 需通过官方工具预处理为 C 数组或二进制文件 | 高 (解码时需完整未压缩内存) [^2] | | **转换后格式**<br>(`lv_img_dsc_t`结构) | ✅ 完全支持 | 使用在线工具转换为像素数据数组 | 中等 (存储原始像素数据) | | **嵌入式动画**<br>(GIF) | ✅ 直接支持 | 需启用 `LV_USE_GIF=1` 配置 | 高 (逐帧解码) [^1] | | **Symbol 图标**<br>(字体字符) | ✅ 原生支持 | 直接使用 `LV_SYMBOL_xxx` 常量 | 极低 | ### 🛠 直接使用 JPG/PNG/BMP 的解决方案 #### 1. **预处理转换流程**(推荐方法) ```mermaid graph LR A[JPG/PNG/BMP] --> B{在线转换工具} B --> C[[选择输出格式]] C -->|C数组| D[生成 lv_img_dsc_t 结构体] C -->|Binary| E[生成 .bin 文件] D --> F[代码加载: lv_image_set_src<img, &my_img>] E --> G[文件系统加载: lv_image_set_src<img, 'S:/img.bin'>] ``` #### 2. **关键代码实现** ```c /* 配置 lv_conf.h */ #define LV_USE_PNG 1 // 启用PNG解码 #define LV_USE_SJPG 1 // 启用分块JPG解码(省内存) #define LV_USE_BMP 1 // 启用BMP解码 #define LV_USE_GIF 1 // 启用GIF支持 /* 加载预处理后的图片 */ LV_IMG_DECLARE(converted_img); // 声明转换后的图像 lv_obj_t* img = lv_image_create(lv_scr_act()); lv_image_set_src(img, &converted_img); // 从内存加载 /* 直接加载文件系统图片 (需启用解码器) */ lv_image_set_src(img, "S:/images/photo.jpg"); // 自动调用JPG解码器[^2] ``` ### ⚠️ 重要限制 1. **内存消耗问题** JPG/PNG 解码需要完整未压缩图像的 RAM 空间,例如 800×480 的 RGB565 图片需: $$800 \times 480 \times 2\text{ bytes} = 768\text{ KB}$$ 建议使用分块解码 SJPG (`LV_USE_SJPG=1`)[^2] 2. **功能限制** 直接解码图片**无法旋转/缩放**,需在转换时预设尺寸: ```c // 转换工具配置输出参数 .header.w = 100, // 固定宽度 .header.h = 100, // 固定高度 .header.cf = LV_IMG_CF_TRUE_COLOR // 格式匹配色深 ``` 3. **系统要求** - 需文件系统支持 (FATFS/LittleFS) - 解码器增加 20-50KB Flash 占用 - 大尺寸图片建议预切割分块 ### 💡 最佳实践建议 1. **小图标/UI 元素**:使用工具转为 C 数组嵌入固件 2. **背景图等大图**: - 启用 SJPG 分块解码 - 通过转换工具降分辨率到实际显示尺寸 - 使用 `lv_img_cache_set_size(20)` 限制缓存帧数 3. **动态内容**: ```c // GIF动画专用接口 lv_obj_t* gif = lv_gif_create(parent); lv_gif_set_src(gif, "S:/anim.gif"); lv_gif_restart(gif); // 控制播放[^1] ``` > 📌 **资源链接**:LVGL 官方图片转换工具 > [https://lvgl.io/tools/imageconverter](https://lvgl.io/tools/imageconverter)
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值