feat(decoder): add image header cache (#5407)

This commit is contained in:
Benign X 2024-01-22 19:44:14 +08:00 committed by GitHub
parent 356f3ed018
commit d26eac8f3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 258 additions and 149 deletions

View File

@ -271,6 +271,10 @@
*If size is 0, the cache function is not enabled and the decoded mem will be released immediately after use.*/
#define LV_CACHE_DEF_SIZE 0
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2

12
Kconfig
View File

@ -269,6 +269,18 @@ menu "LVGL configuration"
save the continuous open/decode of images.
However the opened images might consume additional RAM.
config LV_IMAGE_HEADER_CACHE_DEF_CNT
int "Default image header cache count. 0 to disable caching."
default 0
depends on LV_USE_DRAW_SW
help
If only the built-in image formats are used there is no real advantage of caching.
(I.e. no new image decoder is added).
With complex image decoders (e.g. PNG or JPG) caching can
save the continuous getting header information of images.
However the records of opened images headers might consume additional RAM.
config LV_GRADIENT_MAX_STOPS
int "Number of stops allowed per gradient."
default 2

View File

@ -261,6 +261,10 @@
*will be dropped immediately after usage.*/
#define LV_CACHE_DEF_SIZE 0
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2

View File

@ -271,6 +271,10 @@
*If size is 0, the cache function is not enabled and the decoded mem will be released immediately after use.*/
#define LV_CACHE_DEF_SIZE 0
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2

View File

@ -101,6 +101,10 @@ typedef struct _lv_global_t {
lv_cache_t * img_cache;
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
lv_cache_t * img_header_cache;
#endif
lv_draw_global_info_t draw_info;
#if defined(LV_DRAW_SW_SHADOW_CACHE_SIZE) && LV_DRAW_SW_SHADOW_CACHE_SIZE > 0
lv_draw_sw_shadow_cache_t sw_shadow_cache;

View File

@ -18,6 +18,7 @@
*********************/
#define img_decoder_ll_p &(LV_GLOBAL_DEFAULT()->img_decoder_ll)
#define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache)
#define img_header_cache_p (LV_GLOBAL_DEFAULT()->img_header_cache)
/**********************
* TYPEDEFS
@ -29,6 +30,20 @@
static uint32_t img_width_to_stride(lv_image_header_t * header);
/**
* Get the header info of an image source, and return the a pointer to the decoder that can open it.
* @param src The image source (e.g. a filename or a pointer to a C array)
* @param header The header of the image
* @return The decoder that can open the image source or NULL if not found (or can't open it).
*/
static lv_image_decoder_t * image_decoder_get_info(const void * src, lv_image_header_t * header);
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
static lv_cache_compare_res_t image_decoder_header_cache_compare_cb(const lv_image_header_cache_data_t * lhs,
const lv_image_header_cache_data_t * rhs);
static void image_decoder_header_cache_free_cb(lv_image_header_cache_data_t * entry, void * user_data);
#endif
#if LV_CACHE_DEF_SIZE > 0
static lv_cache_compare_res_t image_decoder_cache_compare_cb(const lv_image_cache_data_t * lhs,
const lv_image_cache_data_t * rhs);
@ -62,6 +77,16 @@ void _lv_image_decoder_init(void)
.create_cb = NULL,
.free_cb = (lv_cache_free_cb_t)image_decoder_cache_free_cb,
});
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
img_header_cache_p = lv_cache_create(&lv_cache_class_lru_rb_count,
sizeof(lv_image_header_cache_data_t), LV_IMAGE_HEADER_CACHE_DEF_CNT, (lv_cache_ops_t) {
.compare_cb = (lv_cache_compare_cb_t)image_decoder_header_cache_compare_cb,
.create_cb = NULL,
.free_cb = (lv_cache_free_cb_t)image_decoder_header_cache_free_cb
});
#endif
}
@ -73,34 +98,19 @@ void _lv_image_decoder_deinit(void)
#if LV_CACHE_DEF_SIZE > 0
lv_cache_destroy(img_cache_p, NULL);
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
lv_cache_destroy(img_header_cache_p, NULL);
#endif
_lv_ll_clear(img_decoder_ll_p);
}
lv_result_t lv_image_decoder_get_info(const void * src, lv_image_header_t * header)
{
lv_memzero(header, sizeof(lv_image_header_t));
lv_image_decoder_t * decoder = image_decoder_get_info(src, header);
if(decoder == NULL) return LV_RESULT_INVALID;
if(src == NULL) return LV_RESULT_INVALID;
lv_image_src_t src_type = lv_image_src_get_type(src);
if(src_type == LV_IMAGE_SRC_VARIABLE) {
const lv_image_dsc_t * img_dsc = src;
if(img_dsc->data == NULL) return LV_RESULT_INVALID;
}
lv_result_t res = LV_RESULT_INVALID;
lv_image_decoder_t * decoder;
_LV_LL_READ(img_decoder_ll_p, decoder) {
if(decoder->info_cb) {
res = decoder->info_cb(decoder, src, header);
if(res == LV_RESULT_OK) {
if(header->stride == 0) header->stride = img_width_to_stride(header);
break;
}
}
}
return res;
return LV_RESULT_OK;
}
lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src, const lv_image_decoder_args_t * args)
@ -108,70 +118,38 @@ lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src
lv_memzero(dsc, sizeof(lv_image_decoder_dsc_t));
if(src == NULL) return LV_RESULT_INVALID;
lv_image_src_t src_type = lv_image_src_get_type(src);
if(src_type == LV_IMAGE_SRC_VARIABLE) {
const lv_image_dsc_t * img_dsc = src;
if(img_dsc->data == NULL) return LV_RESULT_INVALID;
}
dsc->src = src;
dsc->src_type = lv_image_src_get_type(src);
dsc->src_type = src_type;
#if LV_CACHE_DEF_SIZE > 0
dsc->cache = img_cache_p;
/*
* Check the cache first
* If the image is found in the cache, just return it.*/
if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK;
#endif
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
dsc->src = lv_strdup(src);
}
else {
dsc->src = src;
}
/*Find the decoder that can open the image source, and get the header info in the same time.*/
dsc->decoder = image_decoder_get_info(src, &dsc->header);
if(dsc->decoder == NULL) return LV_RESULT_INVALID;
lv_result_t res = LV_RESULT_INVALID;
/*Duplicate the source if it's a file*/
if(dsc->src_type == LV_IMAGE_SRC_FILE) dsc->src = lv_strdup(dsc->src);
lv_image_decoder_t * decoder;
static const lv_image_decoder_args_t def_args = {
/*Make a copy of args*/
dsc->args = args ? *args : (lv_image_decoder_args_t) {
.stride_align = LV_DRAW_BUF_STRIDE_ALIGN != 1,
.premultiply = false,
.no_cache = false,
.use_indexed = false,
};
/*Make a copy of args */
dsc->args = args ? *args : def_args;
_LV_LL_READ(img_decoder_ll_p, decoder) {
/*Info and Open callbacks are required*/
if(decoder->info_cb == NULL || decoder->open_cb == NULL) continue;
res = decoder->info_cb(decoder, src, &dsc->header);
if(res != LV_RESULT_OK) continue;
if(dsc->header.stride == 0) dsc->header.stride = img_width_to_stride(&dsc->header);
dsc->decoder = decoder;
#if LV_CACHE_DEF_SIZE > 0
dsc->cache = img_cache_p;
/*Check the cache first*/
if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK;
#endif
res = decoder->open_cb(decoder, dsc, args);
/*Opened successfully. It is a good decoder for this image source*/
if(res == LV_RESULT_OK) return res;
/*Prepare for the next loop*/
lv_memzero(&dsc->header, sizeof(lv_image_header_t));
dsc->error_msg = NULL;
dsc->decoded = NULL;
dsc->cache_entry = NULL;
dsc->user_data = NULL;
dsc->time_to_open = 0;
}
if(dsc->src_type == LV_IMAGE_SRC_FILE)
lv_free((void *)dsc->src);
/*
* We assume that if a decoder can get the info, it can open the image.
* If decoder open failed, free the source and return error.
* If decoder open succeed, add the image to cache if enabled.
* */
lv_result_t res = dsc->decoder->open_cb(dsc->decoder, dsc);
return res;
}
@ -321,6 +299,70 @@ lv_draw_buf_t * lv_image_decoder_post_process(lv_image_decoder_dsc_t * dsc, lv_d
return decoded;
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_image_decoder_t * image_decoder_get_info(const void * src, lv_image_header_t * header)
{
lv_memzero(header, sizeof(lv_image_header_t));
if(src == NULL) return NULL;
lv_image_src_t src_type = lv_image_src_get_type(src);
if(src_type == LV_IMAGE_SRC_VARIABLE) {
const lv_image_dsc_t * img_dsc = src;
if(img_dsc->data == NULL) return NULL;
}
lv_image_decoder_t * decoder;
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
lv_image_header_cache_data_t search_key;
search_key.src_type = src_type;
search_key.src = src;
lv_cache_entry_t * entry = lv_cache_acquire(img_header_cache_p, &search_key, NULL);
if(entry) {
lv_image_header_cache_data_t * cached_data = lv_cache_entry_get_data(entry);
*header = cached_data->header;
decoder = cached_data->decoder;
lv_cache_release(img_header_cache_p, entry, NULL);
return decoder;
}
#endif
_LV_LL_READ(img_decoder_ll_p, decoder) {
/*Info and Open callbacks are required*/
if(decoder->info_cb && decoder->open_cb) {
lv_result_t res = decoder->info_cb(decoder, src, header);
if(res == LV_RESULT_OK) {
if(header->stride == 0) header->stride = img_width_to_stride(header);
break;
}
}
}
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
if(decoder) {
if(src_type == LV_IMAGE_SRC_FILE) search_key.src = lv_strdup(src);
search_key.decoder = decoder;
search_key.header = *header;
entry = lv_cache_add(img_header_cache_p, &search_key, NULL);
if(entry == NULL) {
if(src_type == LV_IMAGE_SRC_FILE) lv_free((void *)search_key.src);
return NULL;
}
lv_cache_release(img_header_cache_p, entry, NULL);
}
#endif
return decoder;
}
static uint32_t img_width_to_stride(lv_image_header_t * header)
{
if(header->cf == LV_COLOR_FORMAT_RGB565A8) {
@ -331,26 +373,50 @@ static uint32_t img_width_to_stride(lv_image_header_t * header)
}
}
#if LV_CACHE_DEF_SIZE > 0 || LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
inline static lv_cache_compare_res_t image_decoder_common_compare(const void * lhs_src, lv_image_src_t lhs_src_type,
const void * rhs_src, lv_image_src_t rhs_src_type)
{
if(lhs_src_type == rhs_src_type) {
if(lhs_src_type == LV_IMAGE_SRC_FILE) {
int32_t cmp_res = lv_strcmp(lhs_src, rhs_src);
if(cmp_res != 0) {
return cmp_res > 0 ? 1 : -1;
}
}
else if(lhs_src_type == LV_IMAGE_SRC_VARIABLE) {
if(lhs_src != rhs_src) {
return lhs_src > rhs_src ? 1 : -1;
}
}
return 0;
}
return lhs_src_type > rhs_src_type ? 1 : -1;
}
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
static lv_cache_compare_res_t image_decoder_header_cache_compare_cb(
const lv_image_header_cache_data_t * lhs,
const lv_image_header_cache_data_t * rhs)
{
return image_decoder_common_compare(lhs->src, lhs->src_type, rhs->src, rhs->src_type);
}
static void image_decoder_header_cache_free_cb(lv_image_header_cache_data_t * entry, void * user_data)
{
LV_UNUSED(user_data); /*Unused*/
if(entry->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)entry->src);
}
#endif
#if LV_CACHE_DEF_SIZE > 0
static lv_cache_compare_res_t image_decoder_cache_compare_cb(
const lv_image_cache_data_t * lhs,
const lv_image_cache_data_t * rhs)
{
if(lhs->src_type == rhs->src_type) {
if(lhs->src_type == LV_IMAGE_SRC_FILE) {
int32_t cmp_res = lv_strcmp(lhs->src, rhs->src);
if(cmp_res != 0) {
return cmp_res > 0 ? 1 : -1;
}
}
else if(lhs->src_type == LV_IMAGE_SRC_VARIABLE) {
if(lhs->src != rhs->src) {
return lhs->src > rhs->src ? 1 : -1;
}
}
return 0;
}
return lhs->src_type > rhs->src_type ? 1 : -1;
return image_decoder_common_compare(lhs->src, lhs->src_type, rhs->src, rhs->src_type);
}
static void image_decoder_cache_free_cb(lv_image_cache_data_t * entry, void * user_data)

View File

@ -79,11 +79,8 @@ typedef lv_result_t (*lv_image_decoder_info_f_t)(lv_image_decoder_t * decoder, c
* Open an image for decoding. Prepare it as it is required to read it later
* @param decoder pointer to the decoder the function associated with
* @param dsc pointer to decoder descriptor. `src`, `color` are already initialized in it.
* @param args arguments of how to decode the image. see `lv_image_decoder_args_t`.
*/
typedef lv_result_t (*lv_image_decoder_open_f_t)(lv_image_decoder_t * decoder,
lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
typedef lv_result_t (*lv_image_decoder_open_f_t)(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
@ -128,6 +125,14 @@ typedef struct _lv_image_decoder_cache_data_t {
void * user_data;
} lv_image_cache_data_t;
typedef struct _lv_image_decoder_header_cache_data_t {
const void * src;
lv_image_src_t src_type;
lv_image_header_t header;
lv_image_decoder_t * decoder;
} lv_image_header_cache_data_t;
/**Describe an image decoding session. Stores data about the decoding*/
struct _lv_image_decoder_dsc_t {
/**The decoder which was able to open the image source*/

View File

@ -126,9 +126,9 @@ void lv_draw_sw_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc, c
lv_image_decoder_open(&decoder_dsc, dsc->img_src, NULL);
img_area.x1 = 0;
img_area.y1 = 0;
img_area.x2 = decoder_dsc.header.w - 1;
img_area.y2 = decoder_dsc.header.h - 1;
int32_t ofs = decoder_dsc.header.w / 2;
img_area.x2 = decoder_dsc.decoded->header.w - 1;
img_area.y2 = decoder_dsc.decoded->header.h - 1;
int32_t ofs = decoder_dsc.decoded->header.w / 2;
lv_area_move(&img_area, dsc->center.x - ofs, dsc->center.y - ofs);
blend_dsc.src_area = &img_area;
blend_dsc.src_buf = decoder_dsc.decoded->data;

View File

@ -305,7 +305,7 @@ static void _set_paint_fill_pattern(Tvg_Paint * obj, Tvg_Canvas * canvas, const
}
const uint8_t * src_buf = decoder_dsc.decoded->data;
const lv_image_header_t * header = &decoder_dsc.header;
const lv_image_header_t * header = &decoder_dsc.decoded->header;
lv_color_format_t cf = header->cf;
if(cf != LV_COLOR_FORMAT_ARGB8888) {

View File

@ -76,7 +76,7 @@ void lv_draw_vg_lite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t *
}
vg_lite_color_t color = 0;
if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(decoder_dsc.header.cf) || dsc->recolor_opa > LV_OPA_MIN) {
if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(decoder_dsc.decoded->header.cf) || dsc->recolor_opa > LV_OPA_MIN) {
/* alpha image and image recolor */
src_buf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
color = lv_vg_lite_color(dsc->recolor, LV_OPA_MIX2(dsc->opa, dsc->recolor_opa), true);

View File

@ -37,8 +37,7 @@ typedef struct {
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
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 void decoder_cache_free(lv_image_cache_data_t * cached_data, void * user_data);
static void image_try_self_pre_mul(lv_image_decoder_dsc_t * dsc);
@ -367,10 +366,14 @@ failed:
return LV_RESULT_INVALID;
}
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
/**
* Decode an image using the vg_lite gpu.
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(args); /*Unused*/
lv_result_t res = LV_RESULT_INVALID;

View File

@ -167,11 +167,15 @@ lv_result_t lv_bin_decoder_info(lv_image_decoder_t * decoder, const void * src,
return LV_RESULT_OK;
}
lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
/**
* Decode an image from a binary file
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
LV_UNUSED(args);
lv_fs_res_t res = LV_RESULT_INVALID;
bool use_directly = false; /*If the image is already decoded and can be used directly*/

View File

@ -50,8 +50,7 @@ lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod
* @param dsc pointer to decoder descriptor. `src`, `style` are already initialized in it.
* @return LV_RESULT_OK: the info is successfully stored in `header`; LV_RESULT_INVALID: unknown format or other error.
*/
lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
/**
* Close the pending decoding. Free resources etc.

View File

@ -32,8 +32,7 @@ typedef struct {
* STATIC PROTOTYPES
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_area_t * full_area, lv_area_t * decoded_area);
@ -136,15 +135,13 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src,
/**
* Open a BMP 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_IMAGE_DECODER_OPEN_FAIL` if failed
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
LV_UNUSED(args);
/*If it's a BMP file...*/
if(dsc->src_type == LV_IMAGE_SRC_FILE) {

View File

@ -67,8 +67,7 @@ struct lv_image_pixel_color_s {
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
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 * dec, lv_image_decoder_dsc_t * dsc);
static struct ffmpeg_context_s * ffmpeg_open_file(const char * path);
@ -270,11 +269,15 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src,
return LV_RESULT_INVALID;
}
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
/**
* Decode an image using ffmpeg library
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
LV_UNUSED(args);
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
const char * path = dsc->src;

View File

@ -33,8 +33,7 @@ typedef struct error_mgr_s {
* STATIC PROTOTYPES
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
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_jpeg_file(const char * filename);
static bool get_jpeg_size(const char * filename, uint32_t * width, uint32_t * height);
@ -141,15 +140,13 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src,
/**
* Open a JPEG 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_IMAGE_DECODER_OPEN_FAIL` if failed
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder); /*Unused*/
LV_UNUSED(args); /*Unused*/
/*If it's a JPEG file...*/
if(dsc->src_type == LV_IMAGE_SRC_FILE) {

View File

@ -24,8 +24,7 @@
* STATIC PROTOTYPES
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
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(const char * filename);
@ -117,15 +116,13 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src,
/**
* 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_IMAGE_DECODER_OPEN_FAIL` if failed
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder); /*Unused*/
LV_UNUSED(args); /*Unused*/
/*If it's a PNG file...*/
if(dsc->src_type == LV_IMAGE_SRC_FILE) {

View File

@ -25,8 +25,7 @@
* STATIC PROTOTYPES
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
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 * dec, lv_image_decoder_dsc_t * dsc);
static void convert_color_depth(uint8_t * img_p, uint32_t px_cnt);
static lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size);
@ -150,11 +149,9 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src,
* @param dsc decoded image descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
LV_UNUSED(args);
const uint8_t * png_data = NULL;
size_t png_data_size = 0;

View File

@ -27,8 +27,7 @@
* STATIC PROTOTYPES
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_area_t * full_area, lv_area_t * decoded_area);
@ -143,11 +142,15 @@ static size_t input_func(JDEC * jd, uint8_t * buff, size_t ndata)
return 0;
}
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
/**
* Decode a JPG image and return the decoded data.
* @param decoder pointer to the decoder
* @param dsc pointer to the decoder descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
*/
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
LV_UNUSED(args);
lv_fs_file_t * f = lv_malloc(sizeof(lv_fs_file_t));
if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
#if LV_USE_FS_MEMFS

View File

@ -771,6 +771,16 @@
#endif
#endif
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#ifndef LV_IMAGE_HEADER_CACHE_DEF_CNT
#ifdef CONFIG_LV_IMAGE_HEADER_CACHE_DEF_CNT
#define LV_IMAGE_HEADER_CACHE_DEF_CNT CONFIG_LV_IMAGE_HEADER_CACHE_DEF_CNT
#else
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
#endif
#endif
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#ifndef LV_GRADIENT_MAX_STOPS