lvgl / lv_lib_png

PNG decoder for LVGL
MIT License
66 stars 26 forks source link

image with alpha channel is broken #25

Open glory-man opened 2 years ago

glory-man commented 2 years ago

I used such image - 4 rectangles filled with almost the same color but different alpha value bitmap

After it drawed on the screen it looks strange - with lines, although rectangles at the source image has solid filled alpha-channel IMG_20211102_173710

kisvegabor commented 2 years ago

If you use lvgl v8 can you try lvgl master? The PNG lib was merged there:

https://docs.lvgl.io/master/libs/png.html

glory-man commented 2 years ago

If you use lvgl v8 can you try lvgl master? The PNG lib was merged there:

https://docs.lvgl.io/master/libs/png.html

I use lvgl v7.6.1 and code from lv_png v7 branch

glory-man commented 2 years ago

One more moment. For example, I use png from this issue. This picture have white car on a black background with blur under the car body car_noalpha Alpha channel car_alpha If we bring the channels together, then the image on a white background should give a car with a shadow under it. Something like this expectation But on the screen I see car and dark shaddow where alpha value has large value IMG_20211105_180916

I use lvgl-settings given in this discussion. Could the LV_COLOR_DEPTH=16 have any effect on this?

kisvegabor commented 2 years ago

I suggest taking a look at this function: https://github.com/lvgl/lv_lib_png/blob/master/lv_png.c#L214 Maybe the color channels are mixed here :slightly_frowning_face:

glory-man commented 2 years ago

I suggest taking a look at this function: https://github.com/lvgl/lv_lib_png/blob/master/lv_png.c#L214 Maybe the color channels are mixed here 🙁 I tried with such pic - 64x64 px, 4 rectangles - with color 0x00FF00, but different alpha value - 0xFF, 0xBF, 0x80, 0x40 test1

I see following images on the screen

IMG_20211111_131709 IMG_20211111_131715

Img_data variable data-dump before call convert_color_depth(img_data, png_width * png_height); img_data_before_convert.txt

and after img_data_after_convert.txt

It seems like colors converted correctly. But drawed image contains stripes. So it seems lvgl-image-draw worked incorrectly with img_data received from decoder -> lvgl itself issue.

kisvegabor commented 2 years ago

Hmm, I'd be very surprised if LVGL had a bug in simply displaying and image.

Can you reproduce in a simulator? If so please send me the commit hash of LVGL your are using and a short codsnippet to be sure we are doing the very same thing.

glory-man commented 2 years ago

Hmm, I'd be very surprised if LVGL had a bug in simply displaying and image.

Can you reproduce in a simulator? If so please send me the commit hash of LVGL your are using and a short codsnippet to be sure we are doing the very same thing.

I tried to debug how img_draw worked with my image. lv_draw_map() called from lv_img_draw_core() blended img data with background piece by piece. In my case with image is 64x64, blended area calculated as 11px height and 64px width. After that called _lv_blend_map() where there is lines

    {
        int32_t mask_w = lv_area_get_width(&draw_area);
        int32_t i;
        for(i = 0; i < mask_w; i++)  mask[i] = mask[i] > 128 ? LV_OPA_COVER : LV_OPA_TRANSP;
    }

which resets first line of mask buffer to 0/255 (as if this line should be completely transparent for the top half of the image where alpha channel < 128, or opaque for bottom half where alpha > 128). So after blending (in my case with map_normal() ) I see first line transparent/opaque (background/map color - clearly visible on a red background), next 10 lines normal (as it should be in image). The same happens for the next part of the image.

So in case of big picture (like in this post) image will be blended line by line and alpha channel values will be LV_OPA_COVER or LV_OPA_TRANSP.

kisvegabor commented 2 years ago

Wow, it's really a bug if antialiasing is disabled. I've merged https://github.com/lvgl/lvgl/pull/2803 where I fixed it in this commit.

But not that with antialiasing enabled you can't draw ARGB images because the alpha channel will be rounded to 0 or 255.

glory-man commented 2 years ago

Wow, it's really a bug if antialiasing is disabled. I've merged lvgl/lvgl#2803 where I fixed it in this commit.

Now, in latest commit, if antialiazing is disabled alpha channel will be rounded for full blended area, and as a result for whole drawn image. And if png-image have alpha-channel those values will be ignored. Am I understand correctly ?

kisvegabor commented 2 years ago

Not ignored but there won't be semi-transparent pixels. Only 0% or 100% alpha.

Note that even with antialising=0 ARGB images could be drawn correctly as they have nothing to do with antialiasing. But antialiasing is handled here because all drawing ends up in the to blend function and it's convenient to handle it here.

Just out of curiosity, why do you need antialaising=0?

glory-man commented 2 years ago

Just out of curiosity, why do you need antialaising=0?

This option disabled by default in zephyr-config. But I didn't think it could be such important. I thought that anti-aliasing should help remove the distortion artifacts on the edges, but I ran into the PNG image losing its alpha channel on output, or drawed as broken.

glory-man commented 2 years ago

Note that even with antialising=0 ARGB images could be drawn correctly as they have nothing to do with antialiasing. But antialiasing is handled here because all drawing ends up in the to blend function and it's convenient to handle it here.

By the way, in my example, the PNG image is presented in ARGB (after lodepng_decode32() decoding, a 32-bit array was obtained), but since the LV_COLOR_DEPTH is set to 16 decoder_open() converted it to 3-byte (16bit color + aplha) array, and after that image blended.