Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(canvas): lv_canvas_set_px for indexed images #6226

Merged
merged 2 commits into from
May 21, 2024

Conversation

kisvegabor
Copy link
Member

Description of the feature or fix

fixes #6196

_LV_DRAW_BUF_STRIDE and _LV_DRAW_BUF_SIZE weren't working well for for indexed image.

  • _LV_DRAW_BUF_STRIDE gave 2 (instead of 3) for 10 px width and I1.
  • _LV_DRAW_BUF_SIZE wasn't considering the palette size.

Notes

@XuNeo
Copy link
Collaborator

XuNeo commented May 15, 2024

You can use the data pointer from lv_draw_buf_goto_xy directly, except there's a bug in it.

diff --git a/src/draw/lv_draw_buf.c b/src/draw/lv_draw_buf.c
index 10e65b2b5..adb4b7577 100644
--- a/src/draw/lv_draw_buf.c
+++ b/src/draw/lv_draw_buf.c
@@ -379,7 +379,7 @@ void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y)
 
     if(x == 0) return data;
 
-    return data + x * lv_color_format_get_size(buf->header.cf);
+    return data + x * lv_color_format_get_bpp(buf->header.cf) / 8;
 }
 
 lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride)

In this way, the patch can be simplified to below one.

I can push the update if you like it.

commit 08d915216a8048bac9e51d5b46ecf447858cebb6 (HEAD -> canvas)
Author: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
Date:   Tue May 14 12:30:01 2024 +0200

    fix(canvas): lv_canvas_set_px for indexed images
    
    fixes #6196
    
    Process indexed image in single case.
    
    Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>

diff --git a/src/widgets/canvas/lv_canvas.c b/src/widgets/canvas/lv_canvas.c
index 877f6bfa9..fc31c4425 100644
--- a/src/widgets/canvas/lv_canvas.c
+++ b/src/widgets/canvas/lv_canvas.c
@@ -107,20 +107,31 @@ void lv_canvas_set_px(lv_obj_t * obj, int32_t x, int32_t y, lv_color_t color, lv
     lv_draw_buf_t * draw_buf = canvas->draw_buf;
 
     lv_color_format_t cf = draw_buf->header.cf;
-    uint32_t stride = draw_buf->header.stride;
     uint8_t * data = lv_draw_buf_goto_xy(draw_buf, x, y);
 
     if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
-        /*Indexed image bpp could be less than 8, calculate again*/
-        uint8_t * buf = (uint8_t *)canvas->draw_buf->data;
-        buf += 8;
-        buf += y * stride;
-        buf += x >> 3;
-        uint32_t bit = 7 - (x & 0x7);
-        uint32_t c_int = color.blue;
-
-        *buf &= ~(1 << bit);
-        *buf |= c_int << bit;
+        uint8_t shift;
+        switch(cf) {
+            case LV_COLOR_FORMAT_I1:
+                shift = 7 - (x & 0x7);
+                break;
+            case LV_COLOR_FORMAT_I2:
+                shift = 6 - 2 * (x & 0x3);
+                break;
+            case LV_COLOR_FORMAT_I4:
+                shift = 4 - 4 * (x & 0x1);
+                break;
+            case LV_COLOR_FORMAT_I8:
+                /*Indexed8 format is a easy case, process and return.*/
+                *data = color.blue;
+            default:
+                return;
+        }
+
+        uint8_t bpp = lv_color_format_get_bpp(cf);
+        uint8_t mask = (1 << bpp) - 1;
+        uint8_t c_int = color.blue & mask;
+        *data = (*data & ~(mask << shift)) | c_int << shift;
     }
     else if(cf == LV_COLOR_FORMAT_L8) {
         *data = lv_color_luminance(color);

src/draw/lv_draw_buf.h Outdated Show resolved Hide resolved
src/draw/lv_draw_buf.h Outdated Show resolved Hide resolved
@liamHowatt
Copy link
Collaborator

liamHowatt commented May 15, 2024

Am I using it correctly? If so, I think there are still some issues. I8 looks good though. Maybe add this as a test case if you want.

image

static void canvas_set_px_indexed(void)
{
    LV_IMAGE_DECLARE(img_cogwheel_rgb);
    LV_ASSERT(((uintptr_t) img_cogwheel_rgb.data) % 4 == 0);
    LV_ASSERT(img_cogwheel_rgb.header.cf == LV_COLOR_FORMAT_XRGB8888);
    const uint32_t w = img_cogwheel_rgb.header.w;
    const uint32_t h = img_cogwheel_rgb.header.h;
    LV_LOG_USER("dims: %u %u", w, h);

    lv_color_format_t ims[] = {
        LV_COLOR_FORMAT_I1,
        LV_COLOR_FORMAT_I2,
        LV_COLOR_FORMAT_I4,
        LV_COLOR_FORMAT_I8,
        LV_COLOR_FORMAT_L8
    };
    int palette_sizes[] = {2, 4, 16, 256};
    for (int im=0; im<(sizeof(ims)/sizeof(*ims)); im++) {
        lv_obj_t * canv = lv_canvas_create(lv_screen_active());
        lv_canvas_set_draw_buf(canv, lv_draw_buf_create(w, h, ims[im], LV_STRIDE_AUTO));
        if(ims[im] != LV_COLOR_FORMAT_L8) {
            for(int pal_i=0; pal_i<palette_sizes[im]; pal_i++) {
                // lv_color_t col = lv_color_hsv_to_rgb(lv_map(pal_i, 0, palette_sizes[im]-1, 0, 359), 100, 100);
                // lv_color32_t col32 = {col.red, col.green, col.blue, 255};
                uint8_t grey = pal_i * 255 / (palette_sizes[im] - 1);
                lv_color32_t col32 = {grey, grey, grey, 255};
                lv_canvas_set_palette(canv, pal_i, col32);
            }
        }
        lv_canvas_fill_bg(canv, lv_color_black(), LV_OPA_COVER);
        lv_obj_set_x(canv, im * w);
        const uint8_t * src = img_cogwheel_rgb.data;
        for (int y = 0; y < h; y++) {
            for (int x = 0; x<w; x++) {
                uint32_t pixel = *((uint32_t *) src);
                lv_canvas_set_px(canv, x, y, lv_color_make((pixel >> 16) & 0xff, (pixel >> 8) & 0xff, (pixel >> 0) & 0xff), LV_OPA_COVER);
                src += 4;
            }
        }
    }
}

@liamHowatt
Copy link
Collaborator

In this way, the patch can be simplified to below one.

FYI I got a weird memory error with your patch, XuNeo

@XuNeo
Copy link
Collaborator

XuNeo commented May 16, 2024

That's because we used the blue channel of the color as lumaniance, which should be fixed.

There's tested Gabor added in lvgl/tests/src/test_cases/widgets/test_canvas.c.

I'll push the change directly.

@@ -111,6 +112,7 @@ void lv_canvas_set_px(lv_obj_t * obj, int32_t x, int32_t y, lv_color_t color, lv
 
     if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
         uint8_t shift;
+        uint8_t c_int = lv_color_luminance(color);
         switch(cf) {
             case LV_COLOR_FORMAT_I1:
                 shift = 7 - (x & 0x7);
@@ -130,8 +132,8 @@ void lv_canvas_set_px(lv_obj_t * obj, int32_t x, int32_t y, lv_color_t color, lv
 
         uint8_t bpp = lv_color_format_get_bpp(cf);
         uint8_t mask = (1 << bpp) - 1;
-        uint8_t c_int = color.blue & mask;
-        *data = (*data & ~(mask << shift)) | c_int << shift;
+        c_int >>= (8 - bpp);
+        *data = (*data & ~(mask << shift)) | (c_int << shift);
     }

@XuNeo
Copy link
Collaborator

XuNeo commented May 16, 2024

On a second though, we should not convert color to luminance for indexed image. The color value(color.blue) means the index value.

Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
@kisvegabor
Copy link
Member Author

@liamHowatt
With a little modification in your code it looks like this:
image

 for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
        	uint32_t pixel = *((uint32_t *) src);
        	if(ims[im] != LV_COLOR_FORMAT_L8) {
        		uint8_t idx = (pixel & 0xff) / (256 / palette_sizes[im]); /*Convert blue to an index*/
        		lv_canvas_set_px(canv, x, y, lv_color_make(0, 0, idx), LV_OPA_COVER);
        	} else {
        		lv_canvas_set_px(canv, x, y, lv_color_make((pixel >> 16) & 0xff, (pixel >> 8) & 0xff, (pixel >> 0) & 0xff), LV_OPA_COVER);
        	}
        	src += 4;
        }
}

@kisvegabor
Copy link
Member Author

I cannot approve it as I added the last commit, but it looks good to me!

@FASTSHIFT FASTSHIFT merged commit 25c469d into lvgl:master May 21, 2024
19 checks passed
@kisvegabor kisvegabor deleted the fix/canvas_set_px branch May 21, 2024 11:40
kisvegabor added a commit to kisvegabor/lvgl_upstream that referenced this pull request May 21, 2024
Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
Co-authored-by: Xu Xingliang <xuxingliang@xiaomi.com>
@liamHowatt
Copy link
Collaborator

Aha, I see how it works RE blue being the index.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incomplete implementation of lv_canvas_set_px() for indexed color format
4 participants