1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00

feat(libpng): add parsing variable to libpng (#6553)

Signed-off-by: lhdjply <lhdjply@126.com>
This commit is contained in:
Liu Yi 2024-07-30 03:55:15 +08:00 committed by GitHub
parent 210e4ba069
commit 1e36521018
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 1478 additions and 115 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
Open a PNG image from file
--------------------------
Open a PNG image from file and variable
---------------------------------------
.. lv_example:: libs/libpng/lv_example_libpng_1
:language: c

View File

@ -8,13 +8,18 @@
*/
void lv_example_libpng_1(void)
{
LV_IMAGE_DECLARE(img_png_demo);
lv_obj_t * img;
img = lv_image_create(lv_screen_active());
lv_image_set_src(img, &img_png_demo);
lv_obj_align(img, LV_ALIGN_LEFT_MID, 10, 0);
img = lv_image_create(lv_screen_active());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_image_set_src(img, "A:lvgl/examples/libs/libpng/png_demo.png");
lv_obj_center(img);
lv_obj_align(img, LV_ALIGN_RIGHT_MID, -10, 0);
}
#else

View File

@ -31,7 +31,7 @@
static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
static lv_draw_buf_t * decode_png_file(lv_image_decoder_dsc_t * dsc, const char * filename);
static lv_draw_buf_t * decode_png(lv_image_decoder_dsc_t * dsc);
/**********************
* STATIC VARIABLES
@ -85,22 +85,36 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_d
lv_image_src_t src_type = dsc->src_type; /*Get the source type*/
/*If it's a PNG file...*/
if(src_type == LV_IMAGE_SRC_FILE) {
/* Read the width and height from the file. They have a constant location:
* [16..19]: width
* [20..23]: height
*/
if(src_type == LV_IMAGE_SRC_FILE || src_type == LV_IMAGE_SRC_VARIABLE) {
uint32_t * size;
static const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
uint8_t buf[24];
uint32_t rn;
lv_fs_read(&dsc->file, buf, sizeof(buf), &rn);
if(rn != sizeof(buf)) return LV_RESULT_INVALID;
/*If it's a PNG file...*/
if(src_type == LV_IMAGE_SRC_FILE) {
/* Read the width and height from the file. They have a constant location:
* [16..19]: width
* [20..23]: height
*/
uint32_t rn;
lv_fs_read(&dsc->file, buf, sizeof(buf), &rn);
const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
if(memcmp(buf, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
if(rn != sizeof(buf)) return LV_RESULT_INVALID;
if(lv_memcmp(buf, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
size = (uint32_t *)&buf[16];
}
/*If it's a PNG file in a C array...*/
else {
const lv_image_dsc_t * img_dsc = dsc->src;
const uint32_t data_size = img_dsc->data_size;
size = ((uint32_t *)img_dsc->data) + 4;
if(data_size < sizeof(magic)) return LV_RESULT_INVALID;
if(lv_memcmp(img_dsc->data, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
}
uint32_t * size = (uint32_t *)&buf[16];
/*Save the data in the header*/
header->cf = LV_COLOR_FORMAT_ARGB8888;
/*The width and height are stored in Big endian format so convert them to little endian*/
@ -122,52 +136,47 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_d
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder); /*Unused*/
lv_draw_buf_t * decoded;
decoded = decode_png(dsc);
/*If it's a PNG file...*/
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
const char * fn = dsc->src;
lv_draw_buf_t * decoded = decode_png_file(dsc, fn);
if(decoded == NULL) {
return LV_RESULT_INVALID;
}
lv_draw_buf_t * adjusted = lv_image_decoder_post_process(dsc, decoded);
if(adjusted == NULL) {
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
return LV_RESULT_INVALID;
}
/*The adjusted draw buffer is newly allocated.*/
if(adjusted != decoded) {
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
decoded = adjusted;
}
dsc->decoded = decoded;
if(dsc->args.no_cache) return LV_RESULT_OK;
/*If the image cache is disabled, just return the decoded image*/
if(!lv_image_cache_is_enabled()) return LV_RESULT_OK;
/*Add the decoded image to the cache*/
lv_image_cache_data_t search_key;
search_key.src_type = dsc->src_type;
search_key.src = dsc->src;
search_key.slot.size = decoded->data_size;
lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL);
if(entry == NULL) {
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
return LV_RESULT_INVALID;
}
dsc->cache_entry = entry;
return LV_RESULT_OK; /*The image is fully decoded. Return with its pointer*/
if(decoded == NULL) {
return LV_RESULT_INVALID;
}
return LV_RESULT_INVALID; /*If not returned earlier then it failed*/
lv_draw_buf_t * adjusted = lv_image_decoder_post_process(dsc, decoded);
if(adjusted == NULL) {
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
return LV_RESULT_INVALID;
}
/*The adjusted draw buffer is newly allocated.*/
if(adjusted != decoded) {
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
decoded = adjusted;
}
dsc->decoded = decoded;
if(dsc->args.no_cache) return LV_RESULT_OK;
/*If the image cache is disabled, just return the decoded image*/
if(!lv_image_cache_is_enabled()) return LV_RESULT_OK;
/*Add the decoded image to the cache*/
lv_image_cache_data_t search_key;
search_key.src_type = dsc->src_type;
search_key.src = dsc->src;
search_key.slot.size = decoded->data_size;
lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL);
if(entry == NULL) {
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);
return LV_RESULT_INVALID;
}
dsc->cache_entry = entry;
return LV_RESULT_OK; /*The image is fully decoded. Return with its pointer*/
}
/**
@ -236,27 +245,41 @@ failed:
return data;
}
static lv_draw_buf_t * decode_png_file(lv_image_decoder_dsc_t * dsc, const char * filename)
static lv_draw_buf_t * decode_png(lv_image_decoder_dsc_t * dsc)
{
int ret;
uint8_t * png_data;
uint32_t png_data_size;
/*Prepare png_image*/
png_image image;
lv_memzero(&image, sizeof(image));
image.version = PNG_IMAGE_VERSION;
uint32_t data_size;
uint8_t * data = alloc_file(filename, &data_size);
if(data == NULL) {
LV_LOG_WARN("can't load file: %s", filename);
return NULL;
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
if(lv_strcmp(lv_fs_get_ext(dsc->src), "png") != 0) { /*Check the extension*/
return NULL;
}
png_data = alloc_file(dsc->src, &png_data_size);
if(png_data == NULL) {
LV_LOG_WARN("can't load file: %s", (const char *)dsc->src);
return NULL;
}
}
else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
const lv_image_dsc_t * img_dsc = dsc->src;
png_data = (uint8_t *)img_dsc->data;
png_data_size = img_dsc->data_size;
}
else
return NULL;
/*Ready to read file*/
ret = png_image_begin_read_from_memory(&image, data, data_size);
ret = png_image_begin_read_from_memory(&image, png_data, png_data_size);
if(!ret) {
LV_LOG_ERROR("png file: %s read failed: %d", filename, ret);
lv_free(data);
LV_LOG_ERROR("png read failed: %d", ret);
if(dsc->src_type == LV_IMAGE_SRC_FILE)
lv_free(png_data);
return NULL;
}
@ -274,8 +297,15 @@ static lv_draw_buf_t * decode_png_file(lv_image_decoder_dsc_t * dsc, const char
lv_draw_buf_t * decoded;
decoded = lv_draw_buf_create_user(image_cache_draw_buf_handlers, image.width, image.height, cf, LV_STRIDE_AUTO);
if(decoded == NULL) {
LV_LOG_ERROR("alloc PNG_IMAGE_SIZE(%" LV_PRIu32 ") failed: %s", (uint32_t)PNG_IMAGE_SIZE(image), filename);
lv_free(data);
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
LV_LOG_ERROR("alloc PNG_IMAGE_SIZE(%" LV_PRIu32 ") failed: %s", (uint32_t)PNG_IMAGE_SIZE(image),
(const char *)dsc->src);
lv_free(png_data);
}
else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE)
LV_LOG_ERROR("alloc PNG_IMAGE_SIZE(%" LV_PRIu32 ")", (uint32_t)PNG_IMAGE_SIZE(image));
return NULL;
}
@ -285,7 +315,8 @@ static lv_draw_buf_t * decode_png_file(lv_image_decoder_dsc_t * dsc, const char
/*Start decoding*/
ret = png_image_finish_read(&image, NULL, map, decoded->header.stride, palette);
png_image_free(&image);
lv_free(data);
if(dsc->src_type == LV_IMAGE_SRC_FILE)
lv_free(png_data);
if(!ret) {
LV_LOG_ERROR("png decode failed: %s", image.message);
lv_draw_buf_destroy_user(image_cache_draw_buf_handlers, decoded);

View File

@ -84,59 +84,43 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_d
{
LV_UNUSED(decoder); /*Unused*/
const void * src = dsc->src;
lv_image_src_t src_type = dsc->src_type; /*Get the source type*/
/*If it's a PNG file...*/
if(src_type == LV_IMAGE_SRC_FILE) {
const char * fn = src;
if(lv_strcmp(lv_fs_get_ext(fn), "png") == 0) { /*Check the extension*/
if(src_type == LV_IMAGE_SRC_FILE || src_type == LV_IMAGE_SRC_VARIABLE) {
uint32_t * size;
static const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
uint8_t buf[24];
/*If it's a PNG file...*/
if(src_type == LV_IMAGE_SRC_FILE) {
/* Read the width and height from the file. They have a constant location:
* [16..23]: width
* [24..27]: height
*/
uint32_t size[2];
* [16..19]: width
* [20..23]: height
*/
uint32_t rn;
lv_fs_read(&dsc->file, buf, sizeof(buf), &rn);
lv_fs_seek(&dsc->file, 16, LV_FS_SEEK_SET);
lv_fs_read(&dsc->file, &size, 8, &rn);
if(rn != sizeof(buf)) return LV_RESULT_INVALID;
if(rn != 8) return LV_RESULT_INVALID;
if(lv_memcmp(buf, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
/*Save the data in the header*/
header->cf = LV_COLOR_FORMAT_ARGB8888;
/*The width and height are stored in Big endian format so convert them to little endian*/
header->w = (int32_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
header->h = (int32_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
return LV_RESULT_OK;
size = (uint32_t *)&buf[16];
}
}
/*If it's a PNG file in a C array...*/
else if(src_type == LV_IMAGE_SRC_VARIABLE) {
const lv_image_dsc_t * img_dsc = src;
const uint32_t data_size = img_dsc->data_size;
const uint32_t * size = ((uint32_t *)img_dsc->data) + 4;
const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
if(data_size < sizeof(magic)) return LV_RESULT_INVALID;
if(lv_memcmp(magic, img_dsc->data, sizeof(magic))) return LV_RESULT_INVALID;
/*If it's a PNG file in a C array...*/
else {
const lv_image_dsc_t * img_dsc = dsc->src;
const uint32_t data_size = img_dsc->data_size;
size = ((uint32_t *)img_dsc->data) + 4;
if(data_size < sizeof(magic)) return LV_RESULT_INVALID;
if(lv_memcmp(img_dsc->data, magic, sizeof(magic)) != 0) return LV_RESULT_INVALID;
}
/*Save the data in the header*/
header->cf = LV_COLOR_FORMAT_ARGB8888;
if(img_dsc->header.w) {
header->w = img_dsc->header.w; /*Save the image width*/
}
else {
header->w = (int32_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
}
if(img_dsc->header.h) {
header->h = img_dsc->header.h; /*Save the color height*/
}
else {
header->h = (int32_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
}
/*The width and height are stored in Big endian format so convert them to little endian*/
header->w = (int32_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
header->h = (int32_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
return LV_RESULT_OK;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -19,10 +19,35 @@ static void create_images(void)
lv_obj_clean(lv_screen_active());
lv_obj_t * img;
lv_obj_t * label;
/* PNG array */
LV_IMAGE_DECLARE(test_img_lvgl_logo_png);
img = lv_image_create(lv_screen_active());
lv_image_set_src(img, &test_img_lvgl_logo_png);
lv_obj_align(img, LV_ALIGN_CENTER, -100, -20);
label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Array");
lv_obj_align(label, LV_ALIGN_CENTER, -100, 20);
/* 32 bit PNG file */
img = lv_image_create(lv_screen_active());
lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo.png");
lv_obj_center(img);
lv_obj_align(img, LV_ALIGN_CENTER, 100, -100);
label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "File (32 bit)");
lv_obj_align(label, LV_ALIGN_CENTER, 100, -60);
/* 8 bit palette PNG file */
img = lv_image_create(lv_screen_active());
lv_image_set_src(img, "A:src/test_assets/test_img_lvgl_logo_8bit_palette.png");
lv_obj_align(img, LV_ALIGN_CENTER, 100, 60);
label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "File (8 bit palette)");
lv_obj_align(label, LV_ALIGN_CENTER, 100, 100);
}
void test_libpng_1(void)