From f47879b67ea1751e7c623db23968809840c3df01 Mon Sep 17 00:00:00 2001 From: Liam <30486941+liamHowatt@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:24:47 -0500 Subject: [PATCH] feat(demos): High Resolution Demo Improvements (#7566) --- demos/high_res/lv_demo_high_res.h | 18 ++++--- demos/high_res/lv_demo_high_res_app_about.c | 42 +++++---------- demos/high_res/lv_demo_high_res_private.h | 4 +- demos/high_res/lv_demo_high_res_util.c | 58 +++++++++++++++++++-- 4 files changed, 81 insertions(+), 41 deletions(-) diff --git a/demos/high_res/lv_demo_high_res.h b/demos/high_res/lv_demo_high_res.h index d60365773..7d2d289be 100644 --- a/demos/high_res/lv_demo_high_res.h +++ b/demos/high_res/lv_demo_high_res.h @@ -88,12 +88,15 @@ typedef void (*lv_demo_high_res_exit_cb_t)(lv_demo_high_res_api_t * api); * `LV_FS_DEFAULT_DRIVE_LETTER` set. The display size should be * 800x480, 1280x720, or 1920x1080. * @param assets_path Folder where the image assets are. - * If `NULL`, "lvgl/demos/high_res/assets/" will be used. + * If `NULL`, "lvgl/demos/high_res/assets" will be used. * @param logo_path A path to a logo to display in the bottom-left * of the home screen. If `NULL`, an LVGL logo is used. * @param slides_path Folder where the "About" app slideshow slides are. - * If `NULL`, "about_app_slides/" will be used. - * The images should be named like 1.png, 2.png, etc. + * If `NULL`, "about_app_slides" will be used. + * The images should be named like Slide1.png, Slide2.png, etc. + * They will be scaled to nine sixteenths the height of the + * display. I.e., a slide will not be scaled if it is + * 405 px high and the display is 720 px high. * @param exit_cb A callback function which will be called when the * "logout" button is clicked, or `NULL` to do nothing. * @return A struct with subjects to control the UI @@ -112,12 +115,15 @@ lv_demo_high_res_api_t * lv_demo_high_res(const char * assets_path, * `LV_FS_DEFAULT_DRIVE_LETTER` set. The display size should be * 800x480, 1280x720, or 1920x1080. * @param assets_path Folder where the image assets are. - * If `NULL`, "lvgl/demos/high_res/assets/" will be used. + * If `NULL`, "lvgl/demos/high_res/assets" will be used. * @param logo_path A path to a logo to display in the bottom-left * of the home screen. If `NULL`, an LVGL logo is used. * @param slides_path Folder where the "About" app slideshow slides are. - * If `NULL`, "about_app_slides/" will be used. - * The images should be named like 1.png, 2.png, etc. + * If `NULL`, "about_app_slides" will be used. + * The images should be named like Slide1.png, Slide2.png, etc. + * They will be scaled to nine sixteenths the height of the + * display. I.e., a slide will not be scaled if it is + * 405 px high and the display is 720 px high. */ void lv_demo_high_res_api_example(const char * assets_path, const char * logo_path, const char * slides_path); diff --git a/demos/high_res/lv_demo_high_res_app_about.c b/demos/high_res/lv_demo_high_res_app_about.c index 0fcbc9b08..b00a50764 100644 --- a/demos/high_res/lv_demo_high_res_app_about.c +++ b/demos/high_res/lv_demo_high_res_app_about.c @@ -34,7 +34,6 @@ static bool advance_slides(lv_obj_t * slide_deck); static void right_clicked_cb(lv_event_t * e); static void play_pause_timer_cb(lv_timer_t * t); static void play_pause_clicked_cb(lv_event_t * e); -static void slide_free_draw_buf_cb(lv_event_t * e); /********************** * STATIC VARIABLES @@ -99,18 +98,19 @@ void lv_demo_high_res_app_about(lv_obj_t * base_obj) /* slides */ - lv_fs_res_t res; - - lv_fs_dir_t dir; - res = lv_fs_dir_open(&dir, c->slides_path); - if(res != LV_FS_RES_OK) { + if(lv_array_is_empty(&c->about_slides_array)) { lv_obj_t * label = lv_label_create(bg_cont); - lv_label_set_text_fmt(label, "Couldn't open the '%s' folder to load the images", c->slides_path); + if(c->about_slides_dir_exists) { + lv_label_set_text_fmt(label, "Couldn't find images named Slide1.png, Slide2.png, etc. in the '%s' folder", + c->slides_path); + } + else { + lv_label_set_text_fmt(label, "Couldn't open the '%s' folder to load the images", c->slides_path); + } lv_obj_center(label); + lv_obj_add_style(label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0); return; } - res = lv_fs_dir_close(&dir); - LV_ASSERT(res == LV_FS_RES_OK); lv_obj_t * slides_cont = lv_obj_create(bg_cont); lv_obj_remove_style_all(slides_cont); @@ -148,21 +148,11 @@ void lv_demo_high_res_app_about(lv_obj_t * base_obj) lv_obj_t * slide; - char buf[256]; - for(int32_t i = 1; ; i++) { - lv_snprintf(buf, sizeof(buf), "%s/Slide%"PRId32".png", c->slides_path, i); - lv_fs_file_t file; - res = lv_fs_open(&file, buf, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) { - break; - } - res = lv_fs_close(&file); - LV_ASSERT(res == LV_FS_RES_OK); - + uint32_t about_slides_count = lv_array_size(&c->about_slides_array); + for(uint32_t i = 0; i < about_slides_count; i++) { + lv_image_dsc_t ** slide_src = lv_array_at(&c->about_slides_array, i); slide = lv_image_create(slide_deck); - lv_image_dsc_t * loaded_draw_buf = lv_demo_high_res_image_preload(buf, LV_COLOR_FORMAT_NATIVE); - lv_image_set_src(slide, loaded_draw_buf); - lv_obj_add_event_cb(slide, slide_free_draw_buf_cb, LV_EVENT_DELETE, loaded_draw_buf); + lv_image_set_src(slide, *slide_src); } slide = lv_obj_get_child(slide_deck, 0); @@ -292,10 +282,4 @@ static void play_pause_clicked_cb(lv_event_t * e) } } -static void slide_free_draw_buf_cb(lv_event_t * e) -{ - lv_image_dsc_t * loaded_draw_buf = lv_event_get_user_data(e); - lv_draw_buf_destroy((lv_draw_buf_t *)loaded_draw_buf); -} - #endif /*LV_USE_DEMO_HIGH_RES*/ diff --git a/demos/high_res/lv_demo_high_res_private.h b/demos/high_res/lv_demo_high_res_private.h index 4b6e4d8b5..fd4958bba 100644 --- a/demos/high_res/lv_demo_high_res_private.h +++ b/demos/high_res/lv_demo_high_res_private.h @@ -201,6 +201,8 @@ typedef struct { lv_subject_t top_margin_setting_subject; lv_demo_high_res_api_t api; lv_demo_high_res_subject_groups_t subject_groups; + lv_array_t about_slides_array; + bool about_slides_dir_exists; } lv_demo_high_res_ctx_t; LV_ATTRIBUTE_EXTERN_DATA extern const lv_demo_high_res_theme_t lv_demo_high_res_theme_light; @@ -231,7 +233,7 @@ lv_obj_t * lv_demo_high_res_simple_container_create(lv_obj_t * parent, bool vert void lv_demo_high_res_label_bind_temperature(lv_obj_t * label, lv_subject_t * subject, lv_demo_high_res_ctx_t * c); void lv_demo_high_res_theme_observer_image_src_cb(lv_observer_t * observer, lv_subject_t * subject); void lv_demo_high_res_theme_observer_obj_bg_image_src_cb(lv_observer_t * observer, lv_subject_t * subject); -lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_format_t cf); +lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_format_t cf, int32_t scale); /********************** * MACROS diff --git a/demos/high_res/lv_demo_high_res_util.c b/demos/high_res/lv_demo_high_res_util.c index aad7b41b8..0d9f39c21 100644 --- a/demos/high_res/lv_demo_high_res_util.c +++ b/demos/high_res/lv_demo_high_res_util.c @@ -260,7 +260,7 @@ lv_obj_t * lv_demo_high_res_base_obj_create(const char * assets_path, int chars = lv_snprintf(path_buf, sizeof(path_buf), "%s/img_lv_demo_high_res_%s_%s.png", assets_path, image_details[i].name, size_prefix); LV_ASSERT(chars < (int)sizeof(path_buf)); - c->imgs[i] = lv_demo_high_res_image_preload(path_buf, image_details[i].cf); + c->imgs[i] = lv_demo_high_res_image_preload(path_buf, image_details[i].cf, LV_SCALE_NONE); } for(uint32_t i = 0; i < STYLE_COLOR_COUNT; i++) { @@ -274,7 +274,7 @@ lv_obj_t * lv_demo_high_res_base_obj_create(const char * assets_path, } c->sz->init_fonts_cb(c->fonts); - lv_subject_init_pointer(&c->th, (void *)&lv_demo_high_res_theme_light); + lv_subject_init_pointer(&c->th, (void *)&lv_demo_high_res_theme_dark); c->th.user_data = c; lv_subject_add_observer(&c->th, theme_observer_cb, c); @@ -333,6 +333,43 @@ lv_obj_t * lv_demo_high_res_base_obj_create(const char * assets_path, lv_subject_init_group(&c->subject_groups.wifi.group, c->subject_groups.wifi.members, ARRAY_LEN(c->subject_groups.wifi.members)); + lv_array_init(&c->about_slides_array, 1, sizeof(lv_image_dsc_t *)); + lv_fs_dir_t dir; + lv_fs_res_t fs_res = lv_fs_dir_open(&dir, slides_path); + if(fs_res == LV_FS_RES_OK) { + fs_res = lv_fs_dir_close(&dir); + LV_ASSERT(fs_res == LV_FS_RES_OK); + + c->about_slides_dir_exists = true; + + for(int32_t i = 1; ; i++) { + char buf[256]; + lv_snprintf(buf, sizeof(buf), "%s/Slide%"LV_PRId32".png", slides_path, i); + lv_fs_file_t file; + fs_res = lv_fs_open(&file, buf, LV_FS_MODE_RD); + if(fs_res != LV_FS_RES_OK) { + break; + } + fs_res = lv_fs_close(&file); + LV_ASSERT(fs_res == LV_FS_RES_OK); + + lv_image_header_t header; + lv_result_t res = lv_image_decoder_get_info(buf, &header); + if(res == LV_RESULT_INVALID) { + LV_LOG_WARN("Couldn't read the header info of slide image"); + continue; + } + /* the ratio of a slide's height to the display's height will be 9:16 */ + int32_t scale = (9 * 256 * vres) / (16 * header.h); + + lv_image_dsc_t * loaded_draw_buf = lv_demo_high_res_image_preload(buf, LV_COLOR_FORMAT_NATIVE, scale); + if(loaded_draw_buf == NULL) continue; + lv_array_push_back(&c->about_slides_array, &loaded_draw_buf); + + if(scale != LV_SCALE_NONE) LV_LOG_INFO("A slide was scaled by %"LV_PRId32" (256 means 1:1)", scale); + } + } + return base_obj; } @@ -391,7 +428,7 @@ void lv_demo_high_res_theme_observer_obj_bg_image_src_cb(lv_observer_t * observe } } -lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_format_t cf) +lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_format_t cf, int32_t scale) { lv_image_header_t header; lv_result_t res = lv_image_decoder_get_info(src, &header); @@ -401,7 +438,9 @@ lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_forma } lv_draw_buf_t * dest; - dest = lv_draw_buf_create(header.w, header.h, cf, LV_STRIDE_AUTO); + int32_t dest_w = header.w * scale / 256; + int32_t dest_h = header.h * scale / 256; + dest = lv_draw_buf_create(dest_w, dest_h, cf, LV_STRIDE_AUTO); lv_obj_t * canvas = lv_canvas_create(lv_screen_active()); lv_canvas_set_draw_buf(canvas, dest); @@ -413,8 +452,10 @@ lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_forma lv_draw_image_dsc_t dsc; lv_draw_image_dsc_init(&dsc); dsc.src = src; + dsc.scale_x = scale; + dsc.scale_y = scale; - lv_area_t coords = {0, 0, LV_MIN(header.w, dest->header.w) - 1, LV_MIN(header.h, dest->header.h) - 1}; + lv_area_t coords = {0, 0, header.w - 1, header.h - 1}; lv_draw_image(&layer, &dsc, &coords); lv_canvas_finish_layer(canvas, &layer); @@ -545,6 +586,13 @@ static void free_ctx_event_cb(lv_event_t * e) lv_subject_deinit(&subjects[i]); } + uint32_t about_slides_count = lv_array_size(&c->about_slides_array); + for(uint32_t i = 0; i < about_slides_count; i++) { + lv_image_dsc_t ** slide = lv_array_at(&c->about_slides_array, i); + lv_draw_buf_destroy((lv_draw_buf_t *) *slide); + } + lv_array_deinit(&c->about_slides_array); + lv_free(c); lv_obj_set_user_data(base_obj, NULL);