LVGL add support for PNG images

This commit is contained in:
Stephan Hadinger 2021-05-21 13:49:47 +02:00
parent 80189bf6f8
commit c642e716ce
13 changed files with 8901 additions and 25 deletions

View File

@ -0,0 +1,50 @@
# PNG decoder for LVGL
Allow the use of PNG images in LVGL. This implementation uses [lodepng](https://github.com/lvandeve/lodepng) library.
## Get started
- Download or clone this repository
- [Download from GitHub](https://github.com/littlevgl/lv_lib_lodepng/archive/master.zip)
- Clone: `git clone https://github.com/littlevgl/lv_lib_png.git`
- Include the library: `#include "lv_lib_png/lv_png.h"`
- Initalize the decocer with `lv_png_init()`
- Test with the following code:
```c
LV_IMG_DECLARE(png_decoder_test);
lv_obj_t * img = lv_img_create(lv_scr_act(), NULL);
lv_img_set_src(img, &png_decoder_test);
```
## Use PNG images from file
By deafult `lodepng` uses C file IO API (e.g. `fopen`) and images can be opened like this:
```c
lv_img_set_src(img, "./lv_lib_lodepng/png_decoder_test.png");
```
If you want to make `lodepng` to use LVGL's file system API add `#define LV_PNG_USE_LV_FILESYSTEM 1` to the end of your`lv_conf.h`.
In this case you need to [register a driver](https://docs.lvgl.io/latest/en/html/overview/file-system.html) fo LVGL. The following functions are required:
- `open_cb()`
- `read_cb()`
- `close_cb()`
- `size_cb()`
After that fiels can be opened like this:
```c
lv_img_set_src(img, "P:lv_lib_lodepng/png_decoder_test.png");
```
Note that the path of the file might be different.
## Use PNG images from flash
To store a PNG image in flash it needs to be converted to C array with [Online Image converter](https://lvgl.io/tools/imageconverter). Choose `Raw with alpha` Color format and `C array` Output format. Copy the result C array to your project and use it like this:
```c
LV_IMG_DECLARE(my_test_img);
lv_obj_t * img = lv_img_create(lv_scr_act(), NULL);
lv_img_set_src(img, &my_test_img);
```
## Learn more
To learn more about the PNG decoder itself read [this blog post](https://blog.littlevgl.com/2018-10-05/png_converter)
To learn more about the Image decoder interface of LittlevGL read the realevant part of the [documentation](https://docs.littlevgl.com/en/html/overview/image.html#image-decoder).

View File

@ -0,0 +1,21 @@
{
"name":"lv_lib_png",
"description":"Allow the use of PNG images in LVGL. This implementation uses lodepng library.",
"keywords":"lvgl, png",
"license": "MIT License",
"repository": {
"type": "git",
"url": "https://github.com/lvgl/lv_lib_png"
},
"frameworks": "arduino",
"platforms": "espressif32",
"build": {
"flags": [ "-DLV_PNG_USE_LV_FILESYSTEM=1",
"-DLODEPNG_NO_COMPILE_ALLOCATORS",
"-DLODEPNG_NO_COMPILE_ERROR_TEXT",
"-DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS",
"-DLV_LVGL_H_INCLUDE_SIMPLE",
"-I$PROJECT_DIR/include",
"-includetasmota_options.h" ]
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,267 @@
/**
* @file lv_png.c
*
*/
/*********************
* INCLUDES
*********************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include <lvgl.h>
#else
#include <lvgl/lvgl.h>
#endif
#include "lv_png.h"
#include "lodepng.h"
#include <stdlib.h>
#if LV_MEM_CUSTOM != 0
#include LV_MEM_CUSTOM_INCLUDE
#endif
#include <stdio.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t decoder_info(struct _lv_img_decoder * decoder, const void * src, lv_img_header_t * header);
static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
static void convert_color_depth(uint8_t * img, uint32_t px_cnt);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register the PNG decoder functions in LittlevGL
*/
void lv_png_init(void)
{
lv_img_decoder_t * dec = lv_img_decoder_create();
lv_img_decoder_set_info_cb(dec, decoder_info);
lv_img_decoder_set_open_cb(dec, decoder_open);
lv_img_decoder_set_close_cb(dec, decoder_close);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Get info about a PNG image
* @param src can be file name or pointer to a C array
* @param header store the info here
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
*/
static lv_res_t decoder_info(struct _lv_img_decoder * decoder, const void * src, lv_img_header_t * header)
{
(void) decoder; /*Unused*/
lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
/*If it's a PNG file...*/
if(src_type == LV_IMG_SRC_FILE) {
const char * fn = src;
if(!strcmp(&fn[strlen(fn) - 3], "png")) { /*Check the extension*/
/* Read the width and height from the file. They have a constant location:
* [16..23]: width
* [24..27]: height
*/
uint32_t size[2];
#if LV_PNG_USE_LV_FILESYSTEM
lv_fs_file_t f;
lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) return -1;
lv_fs_seek(&f, 16);
uint32_t rn;
lv_fs_read(&f, &size, 8, &rn);
if(rn != 8) return LV_RES_INV;
lv_fs_close(&f);
#else
FILE* file;
file = fopen(fn, "rb" );
if(!file) return LV_RES_INV;
fseek(file, 16, SEEK_SET);
size_t rn = fread(size, 1 , 8, file);
fclose(file);
if(rn != 8) return LV_RES_INV;
#endif
/*Save the data in the header*/
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW_ALPHA;
/*The width and height are stored in Big endian format so convert them to little endian*/
header->w = (lv_coord_t) ((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
header->h = (lv_coord_t) ((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
return LV_RES_OK;
}
}
/*If it's a PNG file in a C array...*/
else if(src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = src;
header->always_zero = 0;
header->cf = img_dsc->header.cf; /*Save the color format*/
header->w = img_dsc->header.w; /*Save the color width*/
header->h = img_dsc->header.h; /*Save the color height*/
return LV_RES_OK;
}
return LV_RES_INV; /*If didn't succeeded earlier then it's an error*/
}
/**
* Open a PNG image and return the decided image
* @param src can be file name or pointer to a C array
* @param style style of the image object (unused now but certain formats might use it)
* @return pointer to the decoded image or `LV_IMG_DECODER_OPEN_FAIL` if failed
*/
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
(void) decoder; /*Unused*/
uint32_t error; /*For the return values of PNG decoder functions*/
uint8_t * img_data = NULL;
/*If it's a PNG file...*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
const char * fn = dsc->src;
if(!strcmp(&fn[strlen(fn) - 3], "png")) { /*Check the extension*/
/*Load the PNG file into buffer. It's still compressed (not decoded)*/
unsigned char * png_data; /*Pointer to the loaded data. Same as the original file just loaded into the RAM*/
size_t png_data_size; /*Size of `png_data` in bytes*/
error = lodepng_load_file(&png_data, &png_data_size, fn); /*Load the file*/
if(error) {
#ifdef LODEPNG_COMPILE_ERROR_TEXT
LV_LOG_ERROR("lv_png error %u: %s\n", error, lodepng_error_text(error));
#else
LV_LOG_ERROR("lv_png error %u\n", error);
#endif
return LV_RES_INV;
}
/*Decode the PNG image*/
uint32_t png_width; /*Will be the width of the decoded image*/
uint32_t png_height; /*Will be the width of the decoded image*/
/*Decode the loaded image in ARGB8888 */
error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size);
LV_MEM_CUSTOM_FREE(png_data); /*Free the loaded file*/
if(error) {
#ifdef LODEPNG_COMPILE_ERROR_TEXT
LV_LOG_ERROR("lv_png error %u: %s\n", error, lodepng_error_text(error));
#else
LV_LOG_ERROR("lv_png error %u\n", error);
#endif
return LV_RES_INV;
}
/*Convert the image to the system's color depth*/
convert_color_depth(img_data, png_width * png_height);
dsc->img_data = img_data;
return LV_RES_OK; /*The image is fully decoded. Return with its pointer*/
}
}
/*If it's a PNG file in a C array...*/
else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = dsc->src;
uint32_t png_width; /*No used, just required by he decoder*/
uint32_t png_height; /*No used, just required by he decoder*/
/*Decode the image in ARGB8888 */
error = lodepng_decode32(&img_data, &png_width, &png_height, img_dsc->data, img_dsc->data_size);
if(error) {
return LV_RES_INV;
}
/*Convert the image to the system's color depth*/
convert_color_depth(img_data, png_width * png_height);
dsc->img_data = img_data;
return LV_RES_OK; /*Return with its pointer*/
}
return LV_RES_INV; /*If not returned earlier then it failed*/
}
/**
* Free the allocated resources
*/
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
(void) decoder; /*Unused*/
if(dsc->img_data) LV_MEM_CUSTOM_FREE((uint8_t *)dsc->img_data);
}
/**
* If the display is not in 32 bit format (ARGB888) then covert the image to the current color depth
* @param img the ARGB888 image
* @param px_cnt number of pixels in `img`
*/
static void convert_color_depth(uint8_t * img, uint32_t px_cnt)
{
#if LV_COLOR_DEPTH == 32
lv_color32_t * img_argb = (lv_color32_t*)img;
lv_color_t c;
lv_color_t * img_c = (lv_color_t *) img;
uint32_t i;
for(i = 0; i < px_cnt; i++) {
c = LV_COLOR_MAKE(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
img_c[i].ch.red = c.ch.blue;
img_c[i].ch.blue = c.ch.red;
}
#elif LV_COLOR_DEPTH == 16
lv_color32_t * img_argb = (lv_color32_t*)img;
lv_color_t c;
uint32_t i;
for(i = 0; i < px_cnt; i++) {
c = LV_COLOR_MAKE(img_argb[i].ch.blue, img_argb[i].ch.green, img_argb[i].ch.red);
img[i*3 + 2] = img_argb[i].ch.alpha;
img[i*3 + 1] = c.full >> 8;
img[i*3 + 0] = c.full & 0xFF;
}
#ifdef LV_MEM_CUSTOM_REALLOC
LV_MEM_CUSTOM_REALLOC(img, px_cnt * 3); /*Shrink the buffer*/
#else
realloc(img, px_cnt * 3); /*Shrink the buffer*/
#endif
#elif LV_COLOR_DEPTH == 8
lv_color32_t * img_argb = (lv_color32_t*)img;
lv_color_t c;
uint32_t i;
for(i = 0; i < px_cnt; i++) {
c = LV_COLOR_MAKE(img_argb[i].red, img_argb[i].green, img_argb[i].blue);
img[i*3 + 1] = img_argb[i].alpha;
img[i*3 + 0] = c.full
}
#if LV_MEM_CUSTOM_REALLOC
LV_MEM_CUSTOM_REALLOC(img, px_cnt * 2); /*Shrink the buffer*/
#else
realloc(img, px_cnt * 2); /*Shrink the buffer*/
#endif
#endif
}

View File

@ -0,0 +1,43 @@
/**
* @file lv_png.h
*
*/
#ifndef LV_PNG_H
#define LV_PNG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Register the PNG decoder functions in LittlevGL
*/
void lv_png_init(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_PNG_H*/

View File

@ -19,7 +19,7 @@ const lvbe_call_c_t lv_img_func[] = {
{ "get_offset_x", (void*) &lv_img_get_offset_x, "i", "(lv_obj)" },
{ "get_offset_y", (void*) &lv_img_get_offset_y, "i", "(lv_obj)" },
{ "get_pivot", (void*) &lv_img_get_pivot, "", "(lv_obj)(lv_point)" },
{ "get_src", (void*) &lv_img_get_src, "i", "(lv_obj)" },
{ "get_src", (void*) &lv_img_get_src, ".", "(lv_obj)" },
{ "get_zoom", (void*) &lv_img_get_zoom, "i", "(lv_obj)" },
{ "set_angle", (void*) &lv_img_set_angle, "", "(lv_obj)i" },
{ "set_antialias", (void*) &lv_img_set_antialias, "", "(lv_obj)b" },
@ -27,7 +27,7 @@ const lvbe_call_c_t lv_img_func[] = {
{ "set_offset_x", (void*) &lv_img_set_offset_x, "", "(lv_obj)i" },
{ "set_offset_y", (void*) &lv_img_set_offset_y, "", "(lv_obj)i" },
{ "set_pivot", (void*) &lv_img_set_pivot, "", "(lv_obj)ii" },
{ "set_src", (void*) &lv_img_set_src, "", "(lv_obj)i" },
{ "set_src", (void*) &lv_img_set_src, "", "(lv_obj)." },
{ "set_tasmota_logo", (void*) &lv_img_set_tasmota_logo, "", "(lv_obj)" },
{ "set_zoom", (void*) &lv_img_set_zoom, "", "(lv_obj)i" },
};
@ -82,7 +82,7 @@ const lvbe_call_c_t lv_style_func[] = {
{ "set_pad_right", (void*) &lv_style_set_pad_right, "", "(lv_style)ii" },
{ "set_pad_top", (void*) &lv_style_set_pad_top, "", "(lv_style)ii" },
{ "set_pattern_blend_mode", (void*) &lv_style_set_pattern_blend_mode, "", "(lv_style)ii" },
{ "set_pattern_image", (void*) &lv_style_set_pattern_image, "", "(lv_style)ii" },
{ "set_pattern_image", (void*) &lv_style_set_pattern_image, "", "(lv_style)i." },
{ "set_pattern_opa", (void*) &lv_style_set_pattern_opa, "", "(lv_style)ii" },
{ "set_pattern_recolor", (void*) &lv_style_set_pattern_recolor, "", "(lv_style)i(lv_color)" },
{ "set_pattern_recolor_opa", (void*) &lv_style_set_pattern_recolor_opa, "", "(lv_style)ii" },
@ -179,7 +179,7 @@ const lvbe_call_c_t lv_obj_func[] = {
{ "align_mid_y", (void*) &lv_obj_align_mid_y, "", "(lv_obj)(lv_obj)ii" },
{ "align_x", (void*) &lv_obj_align_x, "", "(lv_obj)(lv_obj)ii" },
{ "align_y", (void*) &lv_obj_align_y, "", "(lv_obj)(lv_obj)ii" },
{ "allocate_ext_attr", (void*) &lv_obj_allocate_ext_attr, "i", "(lv_obj)i" },
{ "allocate_ext_attr", (void*) &lv_obj_allocate_ext_attr, ".", "(lv_obj)i" },
{ "area_is_visible", (void*) &lv_obj_area_is_visible, "b", "(lv_obj)(lv_area)" },
{ "clean", (void*) &lv_obj_clean, "", "(lv_obj)" },
{ "clean_style_list", (void*) &lv_obj_clean_style_list, "", "(lv_obj)i" },
@ -206,7 +206,7 @@ const lvbe_call_c_t lv_obj_func[] = {
{ "get_drag_parent", (void*) &lv_obj_get_drag_parent, "b", "(lv_obj)" },
{ "get_drag_throw", (void*) &lv_obj_get_drag_throw, "b", "(lv_obj)" },
{ "get_draw_rect_ext_pad_size", (void*) &lv_obj_get_draw_rect_ext_pad_size, "i", "(lv_obj)i" },
{ "get_ext_attr", (void*) &lv_obj_get_ext_attr, "i", "(lv_obj)" },
{ "get_ext_attr", (void*) &lv_obj_get_ext_attr, ".", "(lv_obj)" },
{ "get_ext_click_pad_bottom", (void*) &lv_obj_get_ext_click_pad_bottom, "i", "(lv_obj)" },
{ "get_ext_click_pad_left", (void*) &lv_obj_get_ext_click_pad_left, "i", "(lv_obj)" },
{ "get_ext_click_pad_right", (void*) &lv_obj_get_ext_click_pad_right, "i", "(lv_obj)" },
@ -215,7 +215,7 @@ const lvbe_call_c_t lv_obj_func[] = {
{ "get_focus_parent", (void*) &lv_obj_get_focus_parent, "b", "(lv_obj)" },
{ "get_focused_obj", (void*) &lv_obj_get_focused_obj, "lv_obj", "(lv_obj)" },
{ "get_gesture_parent", (void*) &lv_obj_get_gesture_parent, "b", "(lv_obj)" },
{ "get_group", (void*) &lv_obj_get_group, "i", "(lv_obj)" },
{ "get_group", (void*) &lv_obj_get_group, ".", "(lv_obj)" },
{ "get_height", (void*) &lv_obj_get_height, "i", "(lv_obj)" },
{ "get_height_fit", (void*) &lv_obj_get_height_fit, "i", "(lv_obj)" },
{ "get_height_grid", (void*) &lv_obj_get_height_grid, "i", "(lv_obj)ii" },
@ -269,7 +269,7 @@ const lvbe_call_c_t lv_obj_func[] = {
{ "get_style_pad_right", (void*) &lv_obj_get_style_pad_right, "i", "(lv_obj)i" },
{ "get_style_pad_top", (void*) &lv_obj_get_style_pad_top, "i", "(lv_obj)i" },
{ "get_style_pattern_blend_mode", (void*) &lv_obj_get_style_pattern_blend_mode, "i", "(lv_obj)i" },
{ "get_style_pattern_image", (void*) &lv_obj_get_style_pattern_image, "i", "(lv_obj)i" },
{ "get_style_pattern_image", (void*) &lv_obj_get_style_pattern_image, ".", "(lv_obj)i" },
{ "get_style_pattern_opa", (void*) &lv_obj_get_style_pattern_opa, "i", "(lv_obj)i" },
{ "get_style_pattern_recolor", (void*) &lv_obj_get_style_pattern_recolor, "lv_color", "(lv_obj)i" },
{ "get_style_pattern_recolor_opa", (void*) &lv_obj_get_style_pattern_recolor_opa, "i", "(lv_obj)i" },
@ -411,7 +411,7 @@ const lvbe_call_c_t lv_obj_func[] = {
{ "set_style_local_pad_right", (void*) &lv_obj_set_style_local_pad_right, "", "(lv_obj)iii" },
{ "set_style_local_pad_top", (void*) &lv_obj_set_style_local_pad_top, "", "(lv_obj)iii" },
{ "set_style_local_pattern_blend_mode", (void*) &lv_obj_set_style_local_pattern_blend_mode, "", "(lv_obj)iii" },
{ "set_style_local_pattern_image", (void*) &lv_obj_set_style_local_pattern_image, "", "(lv_obj)iii" },
{ "set_style_local_pattern_image", (void*) &lv_obj_set_style_local_pattern_image, "", "(lv_obj)ii." },
{ "set_style_local_pattern_opa", (void*) &lv_obj_set_style_local_pattern_opa, "", "(lv_obj)iii" },
{ "set_style_local_pattern_recolor", (void*) &lv_obj_set_style_local_pattern_recolor, "", "(lv_obj)ii(lv_color)" },
{ "set_style_local_pattern_recolor_opa", (void*) &lv_obj_set_style_local_pattern_recolor_opa, "", "(lv_obj)iii" },
@ -574,17 +574,17 @@ const lvbe_call_c_t lv_calendar_func[] = {
const lvbe_call_c_t lv_canvas_func[] = {
{ "blur_hor", (void*) &lv_canvas_blur_hor, "", "(lv_obj)(lv_area)i" },
{ "blur_ver", (void*) &lv_canvas_blur_ver, "", "(lv_obj)(lv_area)i" },
{ "copy_buf", (void*) &lv_canvas_copy_buf, "", "(lv_obj)iiiii" },
{ "copy_buf", (void*) &lv_canvas_copy_buf, "", "(lv_obj).iiii" },
{ "create", (void*) &lv_canvas_create, "+lv_canvas", "(lv_obj)(lv_obj)" },
{ "draw_arc", (void*) &lv_canvas_draw_arc, "", "(lv_obj)iiiii(lv_draw_line_dsc)" },
{ "draw_img", (void*) &lv_canvas_draw_img, "", "(lv_obj)iii(lv_draw_img_dsc)" },
{ "draw_img", (void*) &lv_canvas_draw_img, "", "(lv_obj)ii.(lv_draw_img_dsc)" },
{ "draw_line", (void*) &lv_canvas_draw_line, "", "(lv_obj)ii(lv_draw_line_dsc)" },
{ "draw_polygon", (void*) &lv_canvas_draw_polygon, "", "(lv_obj)ii(lv_draw_rect_dsc)" },
{ "draw_rect", (void*) &lv_canvas_draw_rect, "", "(lv_obj)iiii(lv_draw_rect_dsc)" },
{ "draw_text", (void*) &lv_canvas_draw_text, "", "(lv_obj)iii(lv_draw_label_dsc)si" },
{ "fill_bg", (void*) &lv_canvas_fill_bg, "", "(lv_obj)(lv_color)i" },
{ "get_px", (void*) &lv_canvas_get_px, "lv_color", "(lv_obj)ii" },
{ "set_buffer", (void*) &lv_canvas_set_buffer, "", "(lv_obj)iii(lv_img_cf)" },
{ "set_buffer", (void*) &lv_canvas_set_buffer, "", "(lv_obj).ii(lv_img_cf)" },
{ "set_palette", (void*) &lv_canvas_set_palette, "", "(lv_obj)i(lv_color)" },
{ "set_px", (void*) &lv_canvas_set_px, "", "(lv_obj)ii(lv_color)" },
{ "transform", (void*) &lv_canvas_transform, "", "(lv_obj)(lv_img_dsc)iiiiiib" },
@ -714,7 +714,7 @@ const lvbe_call_c_t lv_gauge_func[] = {
{ "get_max_value", (void*) &lv_gauge_get_max_value, "i", "(lv_obj)" },
{ "get_min_value", (void*) &lv_gauge_get_min_value, "i", "(lv_obj)" },
{ "get_needle_count", (void*) &lv_gauge_get_needle_count, "i", "(lv_obj)" },
{ "get_needle_img", (void*) &lv_gauge_get_needle_img, "i", "(lv_obj)" },
{ "get_needle_img", (void*) &lv_gauge_get_needle_img, ".", "(lv_obj)" },
{ "get_needle_img_pivot_x", (void*) &lv_gauge_get_needle_img_pivot_x, "i", "(lv_obj)" },
{ "get_needle_img_pivot_y", (void*) &lv_gauge_get_needle_img_pivot_y, "i", "(lv_obj)" },
{ "get_scale_angle", (void*) &lv_gauge_get_scale_angle, "i", "(lv_obj)" },
@ -723,7 +723,7 @@ const lvbe_call_c_t lv_gauge_func[] = {
{ "set_critical_value", (void*) &lv_gauge_set_critical_value, "", "(lv_obj)i" },
{ "set_formatter_cb", (void*) &lv_gauge_set_formatter_cb, "", "(lv_obj)&4" },
{ "set_needle_count", (void*) &lv_gauge_set_needle_count, "", "(lv_obj)i(lv_color)" },
{ "set_needle_img", (void*) &lv_gauge_set_needle_img, "", "(lv_obj)iii" },
{ "set_needle_img", (void*) &lv_gauge_set_needle_img, "", "(lv_obj).ii" },
{ "set_range", (void*) &lv_gauge_set_range, "", "(lv_obj)ii" },
{ "set_scale", (void*) &lv_gauge_set_scale, "", "(lv_obj)iii" },
{ "set_value", (void*) &lv_gauge_set_value, "", "(lv_obj)ii" },
@ -732,10 +732,10 @@ const lvbe_call_c_t lv_gauge_func[] = {
/* `lv_imgbtn` methods */
const lvbe_call_c_t lv_imgbtn_func[] = {
{ "create", (void*) &lv_imgbtn_create, "+lv_imgbtn", "(lv_obj)(lv_obj)" },
{ "get_src", (void*) &lv_imgbtn_get_src, "i", "(lv_obj)i" },
{ "get_src", (void*) &lv_imgbtn_get_src, ".", "(lv_obj)i" },
{ "get_state", (void*) &lv_imgbtn_get_state, "i", "(lv_obj)" },
{ "set_checkable", (void*) &lv_imgbtn_set_checkable, "", "(lv_obj)b" },
{ "set_src", (void*) &lv_imgbtn_set_src, "", "(lv_obj)ii" },
{ "set_src", (void*) &lv_imgbtn_set_src, "", "(lv_obj)i." },
{ "set_state", (void*) &lv_imgbtn_set_state, "", "(lv_obj)i" },
{ "toggle", (void*) &lv_imgbtn_toggle, "", "(lv_obj)" },
};
@ -821,7 +821,7 @@ const lvbe_call_c_t lv_linemeter_func[] = {
/* `lv_list` methods */
const lvbe_call_c_t lv_list_func[] = {
{ "add_btn", (void*) &lv_list_add_btn, "lv_obj", "(lv_obj)is" },
{ "add_btn", (void*) &lv_list_add_btn, "lv_obj", "(lv_obj).s" },
{ "clean", (void*) &lv_list_clean, "", "(lv_obj)" },
{ "create", (void*) &lv_list_create, "+lv_list", "(lv_obj)(lv_obj)" },
{ "down", (void*) &lv_list_down, "", "(lv_obj)" },
@ -871,7 +871,7 @@ const lvbe_call_c_t lv_msgbox_func[] = {
const lvbe_call_c_t lv_objmask_func[] = {
{ "create", (void*) &lv_objmask_create, "+lv_objmask", "(lv_obj)(lv_obj)" },
{ "remove_mask", (void*) &lv_objmask_remove_mask, "", "(lv_obj)(lv_objmask_mask)" },
{ "update_mask", (void*) &lv_objmask_update_mask, "", "(lv_obj)(lv_objmask_mask)i" },
{ "update_mask", (void*) &lv_objmask_update_mask, "", "(lv_obj)(lv_objmask_mask)." },
};
/* `lv_page` methods */
@ -966,7 +966,7 @@ const lvbe_call_c_t lv_spinbox_func[] = {
/* `lv_spinner` methods */
const lvbe_call_c_t lv_spinner_func[] = {
{ "anim_cb", (void*) &lv_spinner_anim_cb, "", "ii" },
{ "anim_cb", (void*) &lv_spinner_anim_cb, "", ".i" },
{ "create", (void*) &lv_spinner_create, "+lv_spinner", "(lv_obj)(lv_obj)" },
{ "get_arc_length", (void*) &lv_spinner_get_arc_length, "i", "(lv_obj)" },
{ "get_dir", (void*) &lv_spinner_get_dir, "i", "(lv_obj)" },
@ -1091,8 +1091,8 @@ const lvbe_call_c_t lv_tileview_func[] = {
/* `lv_win` methods */
const lvbe_call_c_t lv_win_func[] = {
{ "add_btn_left", (void*) &lv_win_add_btn_left, "lv_obj", "(lv_obj)i" },
{ "add_btn_right", (void*) &lv_win_add_btn_right, "lv_obj", "(lv_obj)i" },
{ "add_btn_left", (void*) &lv_win_add_btn_left, "lv_obj", "(lv_obj)." },
{ "add_btn_right", (void*) &lv_win_add_btn_right, "lv_obj", "(lv_obj)." },
{ "clean", (void*) &lv_win_clean, "", "(lv_obj)" },
{ "close_event_cb", (void*) &lv_win_close_event_cb, "", "(lv_obj)(lv_event)" },
{ "create", (void*) &lv_win_create, "+lv_win", "(lv_obj)(lv_obj)" },

View File

@ -109,6 +109,7 @@ typedef int16_t lv_coord_t;
# define LV_MEM_CUSTOM_INCLUDE <tasmota_lv_stdlib.h> /*Header for the dynamic memory function*/
# define LV_MEM_CUSTOM_ALLOC lvbe_malloc /*Wrapper to malloc*/ /* PSRAM support */
# define LV_MEM_CUSTOM_FREE lvbe_free /*Wrapper to free*/
# define LV_MEM_CUSTOM_REALLOC lvbe_realloc /*Wrapper to realloc*/
#endif /*LV_MEM_CUSTOM*/
/* Use the standard memcpy and memset instead of LVGL's own functions.
@ -328,7 +329,7 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
*===============*/
/*1: Enable the log module*/
#define LV_USE_LOG 0
#define LV_USE_LOG 1
#if LV_USE_LOG
/* How important log should be added:
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
@ -337,7 +338,7 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
* LV_LOG_LEVEL_NONE Do not log anything
*/
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
# define LV_LOG_LEVEL LV_LOG_LEVEL_ERROR
/* 1: Print the log with 'printf';
* 0: user need to register a callback with `lv_log_register_print_cb`*/

View File

@ -20,4 +20,5 @@
// replacement for <stdlib.h> used for PSRAM malloc in LVGL
extern void *lvbe_malloc(size_t size);
extern void lvbe_free(void *ptr);
extern void lvbe_free(void *ptr);
extern void *lvbe_realloc(void *ptr, size_t size);

View File

@ -931,6 +931,7 @@
//#define USE_LVGL // LVGL Engine, requires Berry, takes 440k of Flash
#define USE_LVGL_PSRAM // Allocate LVGL memory in PSRAM if PSRAM is connected - this might be slightly slower but leaves main memory intact
#define USE_LVGL_MAX_SLEEP 10 // max sleep in ms when LVGL is enabled, more than 10ms will make display less responsive
#define USE_LVGL_PNG_DECODER // include a PNG image decoder from file system
//#define USE_LVGL_FREETYPE // Use the FreeType renderer to display fonts using native TTF files in file system (+75k flash)
// WARNING this feature needs to increase the stack size to 32KB, for which there is no easy way right now
#define LV_USE_FT_CACHE_MANAGER 1 // define whether glyphs are cached by FreeType library

View File

@ -426,6 +426,7 @@ extern "C" {
if ((return_type == nullptr) || (strlen(return_type) == 0)) { be_return_nil(vm); } // does not return
else if (strlen(return_type) == 1) {
switch (return_type[0]) {
case '.': // fallback next
case 'i': be_pushint(vm, ret); break;
case 'b': be_pushbool(vm, ret); break;
case 's': be_pushstring(vm, (const char*) ret); break;

View File

@ -32,6 +32,10 @@
#include "Adafruit_LvGL_Glue.h"
#ifdef USE_LVGL_PNG_DECODER
#include "lv_png.h"
#endif // USE_LVGL_PNG_DECODER
Adafruit_LvGL_Glue * glue;
// **************************************************
@ -338,6 +342,14 @@ extern "C" {
void lvbe_free(void *ptr) {
free(ptr);
}
#ifdef USE_LVGL_PNG_DECODER
// for PNG decoder, use same allocators as LVGL
void* lodepng_malloc(size_t size) { return lvbe_malloc(size); }
void* lodepng_realloc(void* ptr, size_t new_size) { return lvbe_realloc(ptr, new_size); }
void lodepng_free(void* ptr) { lvbe_free(ptr); }
#endif // USE_LVGL_PNG_DECODER
}
/************************************************************
@ -429,6 +441,9 @@ void start_lvgl(const char * uconfig) {
USE_LVGL_FREETYPE_MAX_SIZES,
psramFound() ? USE_LVGL_FREETYPE_MAX_BYTES_PSRAM : USE_LVGL_FREETYPE_MAX_BYTES);
#endif
#ifdef USE_LVGL_PNG_DECODER
lv_png_init();
#endif // USE_LVGL_PNG_DECODER
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_LVGL "LVGL initialized"));
}

View File

@ -33,8 +33,8 @@ return_types = {
"int16_t": "i",
"uint32_t": "i",
"int32_t": "i",
"void *": "i",
"const void *": "i",
"void *": ".",
"const void *": ".",
"char *": "s",
"const char *": "s",
"lv_obj_user_data_t": "i",