Displaying Images using MicroPython
Hi! I have been using LittlevGL for a project and it has been so easy to use, however I am having a bit of difficulty in displaying images on my device. I am using an ESP32 with ILI9341 display, and simply want to be able to display png images on the device. I tried following lv_binding_micropython/examples/example2.py and using it to display a QR code saved as a png, however when I do so I get the following on the display:
Clearly the QR code is somewhere in here, but I don’t quite understand what is going wrong. Also, I’m not sure if you can make out but the image comes out blue instead of just black and white for some reason. (I have attached my code below)
I also tried using the lvgl image converter to generate a binary and then use this as the data source of the image but couldn’t get this to work either.
What is the easiest way to display small png images on the device using lvgl? Thanks in advance for any help!
# init
import ustruct as struct
from lib.screen.display import Display
import lodepng as png
import lvgl as lv
lv.init()
lv.log_register_print_cb(lambda level, path, line, msg: print('%s(%d): %s' % (path, line, msg)))
disp = Display() # Handles setting up of display externally
# Parse PNG file header
# Taken from https://github.com/shibukawa/imagesize_py/blob/ffef30c1a4715c5acf90e8945ceb77f4a2ed2d45/imagesize.py#L63-L85
def get_png_info(decoder, src, header):
# Only handle variable image types
if lv.img.src_get_type(src) != lv.img.SRC.VARIABLE:
return lv.RES.INV
png_header = bytes(lv.img_dsc_t.cast(src).data.__dereference__(24))
if png_header.startswith(b'\211PNG\r\n\032\n') and png_header[12:16] == b'IHDR':
try:
width, height = struct.unpack(">LL", png_header[16:24])
except struct.error:
return lv.RES.INV
# Maybe this is for an older PNG version.
elif png_header.startswith(b'\211PNG\r\n\032\n'):
# Check to see if we have the right content type
try:
width, height = struct.unpack(">LL", png_header[8:16])
except struct.error:
return lv.RES.INV
else:
return lv.RES.INV
header.always_zero = 0
header.w = width
header.h = height
header.cf = lv.img.CF.TRUE_COLOR
print("width=%d, height=%d" % (header.w, header.h))
return lv.RES.OK
# Read and parse PNG file
def open_png(decoder, dsc):
img_dsc = lv.img_dsc_t.cast(dsc.src)
png_data = img_dsc.data
png_size = img_dsc.data_size
png_decoded = png.C_Pointer()
png_width = png.C_Pointer()
png_height = png.C_Pointer()
error = png.decode32(png_decoded, png_width, png_height, png_data, png_size)
if error:
return None # LV_IMG_DECODER_OPEN_FAIL
img_size = png_width.int_val * png_height.int_val * lv.color_t.SIZE
img_data = png_decoded.ptr_val
dsc.img_data = img_data
return lv.RES.OK
decoder = lv.img.decoder_create()
decoder.info_cb = get_png_info
decoder.open_cb = open_png
with open('image.png', 'rb') as f:
png_data = f.read()
png_img_dsc = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data})
scr = lv.obj()
img2 = lv.img(scr)
raw_dsc = lv.img_dsc_t()
get_png_info(None, png_img_dsc, raw_dsc.header)
dsc = lv.img_decoder_dsc_t({'src': png_img_dsc})
if open_png(None, dsc) == lv.RES.OK:
raw_dsc.data = dsc.img_data
raw_dsc.data_size = raw_dsc.header.w * raw_dsc.header.h * lv.color_t.SIZE
img2.set_src(raw_dsc)
lv.scr_load(scr)