1. 完成了gif的显示测试(使用lvgl当中的gif解码器),测试通过

This commit is contained in:
Misaki
2025-08-26 10:07:46 +08:00
parent 7fa73d6183
commit f5df1d4739
9 changed files with 227 additions and 18 deletions
+178
View File
@@ -0,0 +1,178 @@
//
// Created by misaki on 2025/8/25.
//
#include "lvgl.h"
#include "SD_MMC.h"
#include "I2C_Driver.h"
#include "ST77916.h"
#include <esp_log.h>
static const char *tTAG = "GIF_TEST";
/* 把 GIF 完整读进 RAM,返回 malloc 得到的指针;用完 free */
static uint8_t *read_whole_file(const char *path, size_t *out_len)
{
ESP_LOGI(tTAG, "开始读取文件: %s", path);
FILE *fp = Open_File(path);
if (!fp) {
ESP_LOGE(tTAG, "Open_File 失败");
return NULL;
}
fseek(fp, 0, SEEK_END);
*out_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
ESP_LOGI(tTAG, "文件大小 %zu 字节", *out_len);
uint8_t *buf = malloc(*out_len);
if (!buf) {
ESP_LOGE(tTAG, "malloc 失败,需要 %zu 字节", *out_len);
fclose(fp);
return NULL;
}
size_t readed = fread(buf, 1, *out_len, fp);
fclose(fp);
if (readed != *out_len) {
ESP_LOGE(tTAG, "fread 只读了 %zu/%zu 字节", readed, *out_len);
free(buf);
return NULL;
}
/* 打印文件头 8 字节,确认是 GIF */
ESP_LOG_BUFFER_HEX_LEVEL(tTAG, buf, 8, ESP_LOG_INFO);
return buf;
}
uint8_t * get_gif_data(const char *filename, size_t *gif_len)
{
char full_path[64];
snprintf(full_path, sizeof(full_path), "/sdcard/%s", filename);
uint8_t *gif_data = read_whole_file(full_path, gif_len);
if (!gif_data) {
ESP_LOGE(tTAG, "读取 GIF 数据失败");
return NULL;
}
return gif_data;
}
/* 显示 GIF 并返回对象句柄,便于后续调试 */
static lv_obj_t *show_gif_from_sd(const char *filename)
{
size_t gif_len = 0;
char full_path[64];
snprintf(full_path, sizeof(full_path), "/sdcard/%s", filename);
ESP_LOGI(tTAG, "准备显示 GIF: %s", full_path);
uint8_t *gif_data = read_whole_file(full_path, &gif_len);
if (!gif_data) {
ESP_LOGE(tTAG, "读取 GIF 数据失败");
return NULL;
}
/* 确认 LVGL 版本支持内存指针 */
#if LV_VERSION_CHECK(8, 1, 0)
lv_obj_t *gif = lv_gif_create(lv_scr_act());
lv_gif_set_src(gif, gif_data); // 传内存指针
ESP_LOGI(tTAG, "GIF 对象创建成功,指针 %p", gif);
#else
lv_obj_t *gif = NULL;
ESP_LOGE(tTAG, "LVGL 版本过低或 GIF 解码器未启用");
#endif
if (gif) {
lv_obj_center(gif);
ESP_LOGI(tTAG, "GIF 已显示");
} else {
ESP_LOGE(tTAG, "GIF 对象创建失败");
}
/* 如内存紧张,可在这里 free(gif_data);
但注意:循环播放时需要保持 data 有效 */
return gif;
}
void gif_macro_check(void)
{
ESP_LOGI("GIF", "LV_USE_GIF=%d (必须是 1)", LV_USE_GIF);
ESP_LOGI("GIF", "LVGL_VERSION=%d.%d.%d",
LVGL_VERSION_MAJOR, LVGL_VERSION_MINOR, LVGL_VERSION_PATCH);
}
static bool get_gif_wh(const uint8_t *raw, uint32_t *w, uint32_t *h)
{
if (memcmp(raw, "GIF", 3) != 0) /* 简单校验 */
return false;
*w = raw[6] | (raw[7] << 8); /* 小端转主机字节序 */
*h = raw[8] | (raw[9] << 8);
ESP_LOGI("GIF", "GIF size: %ldx%ld", *w, *h);
return true;
}
void red_gif_test(void)
{
size_t gif_len = 0;
uint8_t *gif_data = get_gif_data("xwzy_m.gif", &gif_len);
ESP_LOGI("GIF", "GIF 文件大小 %zu 字节", gif_len);
if (!gif_data) return;
uint32_t w = 0, h = 0;
if (!get_gif_wh(gif_data, &w, &h)) {
ESP_LOGE("GIF", "非法 GIF 文件");
free(gif_data);
return;
}
lv_img_dsc_t gif_desc = {
.header.cf = LV_IMG_CF_RAW_CHROMA_KEYED,
.header.always_zero = 0,
.header.reserved = 0,
.header.w = (lv_coord_t)w,
.header.h = (lv_coord_t)h,
.data_size = gif_len,
.data = gif_data,
};
gif_macro_check();
lv_obj_t *gif = lv_gif_create(lv_scr_act());
lv_gif_set_src(gif, &gif_desc);
lv_obj_center(gif);
}
/* 带有完整日志的主测试函数 */
void gif_display_test(void)
{
ESP_LOGI(tTAG, "======== GIF 显示测试开始 ========");
/* 1. 初始化 SD 卡 */
ESP_LOGI(tTAG, "1. 初始化 SD 卡...");
SD_Init(); // 你的挂载函数
ESP_LOGI(tTAG, " SD 卡挂载完成");
/* 2. 初始化硬件 */
ESP_LOGI(tTAG, "2. 初始化硬件...");
I2C_Init();
LCD_Init();
LVGL_Init();
ESP_LOGI(tTAG, " 硬件初始化完成");
/* 3. 显示 GIF */
ESP_LOGI(tTAG, "3. 开始显示 GIF...");
red_gif_test();
/* 4. 主循环 */
while (1) {
vTaskDelay(pdMS_TO_TICKS(10));
lv_timer_handler();
}
}