// // Created by misaki on 2025/8/25. // #include "lvgl.h" #include "SD_MMC.h" #include "I2C_Driver.h" #include "ST77916.h" #include 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("sequence02m.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(); } }