Improve grayscale PNG rendering

Description

I have an embedded application that displays custom PNG images saved on an external flash memory.
For some images (like the one attached at the end) there are gray scaffolds visible in the background.

I believe this issue to be due to the fact that the display I’m using has a 16bit colour format, which is not enough for some images. I can’t increase the colour depth; is there some other way - preferably not requiring any modification of the original PNG - to obtain a more continuous result?

What MCU/Processor/Board and compiler are you using?

ESP32, custom board.

What LVGL version are you using?

v8.3

What do you want to achieve?

I’d like the image to be displayed more cleanly.

What have you tried so far?

Code to reproduce

The image is simply created and added to the screen. I’m using a color depth of 16 bits and the default STDIO driver and PNG decoder.

    lv_obj_t *img = lv_img_create(lv_scr_act());
    lv_img_set_src(img, "L:test.png");
    lv_obj_center(img);

Screenshot and/or video

This is the resulting image, with visible grey lines, especially in the upper part (screenshot from SDL simulated application):

16

This is the PNG image that is loaded on the device:

test

what is the color depth you have LVGL running in. This could be from the conversion to 16bit color. There are bits that get truncated and could be causing the resulting issue. If you look at the actual PNG make sure the areas with the gray bars are in fact black (0, 0, 0) or have an alpha value of 0.

Lets start with the simple stuff first and go from there

sorry I just saw that you said 16 bit color.

That is what is more than likely causing the problem.

I checked your images and the top one has a “black” of 8, 12, 8 and the gray bar is 16, 16, 16

on the bottom image the gray bar is 17, 17, 17 and the black background is 13. 13. 13

This is an issue with your PNG and not with LVGL

I changed the contrast on the original image and low and behold this is what is seen.

image

The background is a gradient and not a solid color.

and here is the image as seen in LVGL.

image

Thank you for the analysis, I’m quite lacking on the graphical part. I don’t think it’s possible, but I’m going to ask for clarity: is there any way to display the background gradient as more fluid on LVGL? Barring increasing the colour depth, of course.

You nailed the head on it. increasing the color depth is about all you can do without programmatically changing the data in the image buffer. It would be expensive to do programmatically.

If you have the ability to alter the image on a PC first you can remove the gradient background.

Maybe someone else might be able to chime in on this. IDK if LVGL has the ability to mask off an image based on the brightness of a color. If you can then you could have it set the alpha channel to 0 for all of the dark colors and place the image into an object that has the background set to black. This is what I would do on a PC.

On a PC is it literally 3 clicks of the mouse to do.

image

Now I know it doesn’t look like anything in the post. copy the image and paste it onto some kind of a paint program and then save it as a PNG file. Use the file in your code and see what it looks like.

Here it is with a corrected background. The gradient is removed.

test

Hi MM, and for detailed info RGB565 have only 555 gray levels clean without dither noise. 5 bit is 32 levels from black to white for full gradient. If you need only dark gradient = mission impossible. For big image no possible create smooth gradient. Same issue is with other colour gradients and too on RGB888.

If this is something that is dynamic, meaning the images being loaded from some kind of a data stream like over WiFi where there is no prior knowledge of what the image is and you have no control over the image that is being sent then the best thing is going to be to iterate over the data for the image and change the opacity to zero for any pixel that is below a specified threshold.