When use image as background, how to let it draw one time?

When I use a 480X272 image as background, why the lvgl will use fill_normal to draw a 480X272 background, and then use map_fill to draw 480X272 image.

background = lv_img_create(lv_scr_act());
lv_img_set_src(background, &g_bg);
lv_obj_set_size(background, LV_HOR_RES, LV_VER_RES);

I don’t want to draw 480*272 background, because my image is the same as the screen.

@kisvegabor Can you tell me how to optimazition it?

What is the color format of the image? If it’s TRUE_COLOR_ALPHA LVGL assumes that the image might have transparent pixels so it can’t convert the area.

If it’s TRUE_COLOR LVGL should see the image as “top object”.

Can you send a photo about the UI?

Happy new year, @kisvegabor, I’m glad to get your reply.

I decode jpg file, and set data to the ‘lv_img_dsc_t’. The cf value is LV_IMG_CF_TRUE_COLOR:

        img_dst->header.w = result.pixel_x;
        img_dst->header.h = result.pixel_y;
        img_dst->data_size = img_dst->header.w*img_dst->header.h*2;
        img_dst->header.always_zero = 0;
        img_dst->header.cf = LV_IMG_CF_TRUE_COLOR;

Happy new year :slight_smile:

It’s strange. It seems you are using a quite old LVGL version. Exactly which one?

My code likes this, the version of LVGL is V8.3.3:

            lv_obj_t *background = NULL;

            background = lv_img_create(lv_scr_act());
            lv_img_set_src(background, &g_bg);
            lv_obj_set_size(background, LV_HOR_RES, LV_VER_RES);
            lv_obj_set_scrollbar_mode(background, LV_SCROLLBAR_MODE_OFF);
            lv_obj_add_style(background, &img_style, 0);

It’s a pretty recent version. What is in img_style?

The img_style is like this:

lv_style_init(&img_style);
lv_style_set_border_width(&img_style, 0);
lv_style_set_pad_all(&img_style, 0);

@kisvegabor I try it on the newest code with below code, also will use fill_normal to draw background first. you can try it to see the question.

git clone --recurse-submodules https://github.com/lvgl/lv_sim_visual_studio.git 

It seems good. I’d like to try it out but I need

  • the image
  • the display resolution
  • the exact LVGL commit your using

I directly use the image of the lv_demo_widgets, my code is below:

  1. change the display to 154X154:
@@ -38,8 +38,8 @@ bool single_display_mode_initialization()
     if (!lv_win32_init(
         GetModuleHandleW(NULL),
         SW_SHOW,
-        800,
-        480,
+        154,
+        154,
         LoadIconW(GetModuleHandleW(NULL), MAKEINTRESOURCE(IDI_LVGL))))
     {

  1. close LV_USE_PERF_MONITOR and LV_USE_MEM_MONITOR
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
 void lv_demo_widgets(void)
 {
+    lv_obj_t *g_close_label;
+#if 1
+    g_close_label;
+
+    LV_IMG_DECLARE(img_demo_widgets_avatar);
+    lv_obj_t * avatar = lv_img_create(lv_scr_act());
+    lv_obj_set_size(avatar, LV_HOR_RES, LV_VER_RES);
+    lv_img_set_src(avatar, &img_demo_widgets_avatar);
+#else
     if(LV_HOR_RES <= 320) disp_size = DISP_SMALL;
     else if(LV_HOR_RES < 720) disp_size = DISP_MEDIUM;
     else disp_size = DISP_LARGE;
@@ -194,6 +203,7 @@ void lv_demo_widgets(void)
     shop_create(t3);

     color_changer_create(tv);
+#endif
 }

Now I add below code in here, can resolve my question:

+static int _check_child_is_cover_parent(lv_obj_t * obj)
+{
+    lv_obj_t *child;
+    lv_opa_t child_opa;
+    lv_area_t *child_coords;
+
+    lv_opa_t parent_opa;
+    lv_area_t *parent_coords;
+    int ret = 0;
+    int child_cnt;
+    int i = 0;
+
+    do{
+        parent_opa = lv_obj_get_style_opa(obj, 0);
+        parent_coords = &(obj->coords);
+
+        if(parent_opa < LV_OPA_MAX)
+        {
+            break;
+        }
+
+        if(LV_VER_RES != lv_area_get_height(parent_coords)
+            || LV_HOR_RES != lv_area_get_width(parent_coords))
+        {
+            break;
+        }
+
+        child_cnt = lv_obj_get_child_cnt(obj);
+        for(i = 0; i < child_cnt; i++) {
+            child = obj->spec_attr->children[i];
+            child_opa = lv_obj_get_style_opa(child, 0);
+            child_coords = &(child->coords);
+
+            if(child_opa >= parent_opa
+                && child_coords->x1 <= parent_coords->x1
+                && child_coords->y1 <= parent_coords->y1
+                && child_coords->x2 >= parent_coords->x2
+                && child_coords->y2 >= parent_coords->y2)
+            {
+                ret = 1;
+                break;
+            }
+        }
+    }while(0);
+
+    return ret;
+}
+
 void lv_obj_redraw(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
 {
     const lv_area_t * clip_area_ori = draw_ctx->clip_area;
     lv_area_t clip_coords_for_obj;

     /*Truncate the clip area to `obj size + ext size` area*/
     lv_area_t obj_coords_ext;
     lv_obj_get_coords(obj, &obj_coords_ext);
@@ -140,12 +189,17 @@ void lv_obj_redraw(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
     /*If the object is visible on the current clip area OR has overflow visible draw it.
      *With overflow visible drawing should happen to apply the masks which might affect children */
     bool should_draw = com_clip_res || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE);
+
+    if(_check_child_is_cover_parent(obj))
+        should_draw = 0;
+
     if(should_draw) {
         draw_ctx->clip_area = &clip_coords_for_obj;

lv_refr_get_top_obj should find which the top most object from where the drawing should start. IF the image is screen sized than it should work well.

Note that img_demo_widgets_avatar has LV_IMG_CF_TRUE_COLOR_ALPHA color format, so LVGL assumes that it might have transparent pixels. therefore it can be a good “top object”.

I change the img_demo_widgets_avatar to another jpeg, and convert LV_IMG_CF_TRUE_COLOR on lvgl website, also fill_normal will draw first.

It’s easy to try on your demo, you will see what I say.

git clone --recurse-submodules https://github.com/lvgl/lv_sim_visual_studio.git 

I’m on Linux and a little bit hard to test on Windows.

Can you debug what happens in lv_refr_get_top_obj and why LVGL thinks the image is not a good top object?