diff --git a/src/draw/lv_image_decoder.c b/src/draw/lv_image_decoder.c index 17297084e..5dacaf946 100644 --- a/src/draw/lv_image_decoder.c +++ b/src/draw/lv_image_decoder.c @@ -154,6 +154,7 @@ lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src dsc->error_msg = NULL; dsc->img_data = NULL; + dsc->decoded = NULL; dsc->cache_entry = NULL; dsc->user_data = NULL; dsc->time_to_open = 0; diff --git a/src/draw/lv_image_decoder.h b/src/draw/lv_image_decoder.h index 7db6f2509..329c6e395 100644 --- a/src/draw/lv_image_decoder.h +++ b/src/draw/lv_image_decoder.h @@ -16,7 +16,7 @@ extern "C" { #include "../lv_conf_internal.h" #include -#include "lv_image_buf.h" +#include "lv_draw_buf.h" #include "../misc/lv_fs.h" #include "../misc/lv_types.h" #include "../misc/lv_area.h" @@ -136,6 +136,8 @@ typedef struct _lv_image_decoder_dsc_t { * MUST be set in `open` function*/ const uint8_t * img_data; + const lv_draw_buf_t * decoded; /*A draw buffer to described decoded image.*/ + const lv_color32_t * palette; uint32_t palette_size; @@ -158,6 +160,14 @@ typedef struct _lv_image_decoder_dsc_t { * GLOBAL PROTOTYPES **********************/ +/** + * @todo remove it when all decoder migrates to new draw buf interface. + */ +static inline const void * _lv_image_decoder_get_data(const lv_image_decoder_dsc_t * dsc) +{ + return dsc->decoded ? dsc->decoded->data : dsc->img_data; +} + /** * Initialize the image decoder module */ diff --git a/src/draw/sw/lv_draw_sw_arc.c b/src/draw/sw/lv_draw_sw_arc.c index dd9050d48..3e0d4a50a 100644 --- a/src/draw/sw/lv_draw_sw_arc.c +++ b/src/draw/sw/lv_draw_sw_arc.c @@ -131,7 +131,7 @@ void lv_draw_sw_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc, c int32_t ofs = decoder_dsc.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.img_data; + blend_dsc.src_buf = _lv_image_decoder_get_data(&decoder_dsc); blend_dsc.src_color_format = decoder_dsc.header.cf; blend_dsc.src_stride = decoder_dsc.header.stride; } diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c index b5f5029d9..bfd762bec 100644 --- a/src/draw/sw/lv_draw_sw_img.c +++ b/src/draw/sw/lv_draw_sw_img.c @@ -253,7 +253,7 @@ static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_ sup.palette_size = decoder_dsc->palette_size; /*The whole image is available, just draw it*/ - if(decoder_dsc->img_data) { + if(decoder_dsc->decoded || decoder_dsc->img_data) { img_draw_core(draw_unit, draw_dsc, decoder_dsc, &sup, img_area, clipped_img_area); } /*Draw in smaller pieces*/ @@ -298,7 +298,13 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t uint32_t img_stride = header->stride; lv_color_format_t cf = header->cf; - cf = LV_COLOR_FORMAT_IS_INDEXED(cf) ? LV_COLOR_FORMAT_ARGB8888 : cf, + cf = LV_COLOR_FORMAT_IS_INDEXED(cf) ? LV_COLOR_FORMAT_ARGB8888 : cf; + + if(decoder_dsc->decoded) { + src_buf = decoder_dsc->decoded->data; + img_stride = decoder_dsc->decoded->header.stride; + cf = decoder_dsc->decoded->header.cf; + } lv_memzero(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t)); blend_dsc.opa = draw_dsc->opa; diff --git a/src/draw/sw/lv_draw_sw_vector.c b/src/draw/sw/lv_draw_sw_vector.c index 62fee11e9..06f0a0a43 100644 --- a/src/draw/sw/lv_draw_sw_vector.c +++ b/src/draw/sw/lv_draw_sw_vector.c @@ -297,13 +297,13 @@ static void _set_paint_fill_pattern(Tvg_Paint * obj, Tvg_Canvas * canvas, const return; } - if(!decoder_dsc.img_data) { + if(!decoder_dsc.decoded && !decoder_dsc.img_data) { lv_image_decoder_close(&decoder_dsc); LV_LOG_ERROR("Image not ready"); return; } - const uint8_t * src_buf = decoder_dsc.img_data; + const uint8_t * src_buf = _lv_image_decoder_get_data(&decoder_dsc); const lv_image_header_t * header = &decoder_dsc.header; lv_color_format_t cf = header->cf; diff --git a/src/libs/bin_decoder/lv_bin_decoder.c b/src/libs/bin_decoder/lv_bin_decoder.c index 324a64a2d..b265144af 100644 --- a/src/libs/bin_decoder/lv_bin_decoder.c +++ b/src/libs/bin_decoder/lv_bin_decoder.c @@ -37,10 +37,12 @@ typedef struct _lv_image_compressed_t { typedef struct { lv_fs_file_t * f; lv_color32_t * palette; - uint8_t * img_data; lv_opa_t * opa; - uint8_t * decompressed; lv_image_compressed_t compressed; + lv_draw_buf_t * decoded; /*A draw buf to store decoded image*/ + lv_draw_buf_t * decompressed; /*Decompressed data could be used directly, thus must also be draw buf*/ + lv_draw_buf_t c_array; /*An C-array image that need to be converted to a draw buf*/ + lv_draw_buf_t * decoded_partial; /*A draw buf for decoded image via get_area_cb*/ } decoder_data_t; /********************** @@ -258,7 +260,35 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d else { /*In case of uncompressed formats the image stored in the ROM/RAM. *So simply give its pointer*/ - dsc->img_data = ((lv_image_dsc_t *)dsc->src)->data; + + decoder_data_t * decoder_data = get_decoder_data(dsc); + lv_draw_buf_t * decoded = &decoder_data->c_array; + dsc->decoded = decoded; + lv_draw_buf_from_image(decoded, image); + + if(decoded->header.stride == 0) { + /*Use the auto calculated value from decoder_info callback*/ + decoded->header.stride = dsc->header.stride; + } + + /** + * @todo need to convert c-array image stride if not match + * + * lv_draw_buf_create(); //create new draw buf that meets requirement + * lv_draw_buf_copy(); //copy from c-array image to new draw buf + */ + uint32_t stride_expect = lv_draw_buf_width_to_stride(dsc->header.w, dsc->header.cf); + if(dsc->header.stride != stride_expect) { + LV_LOG_WARN("Stride mismatch"); +#if 0 + /** + * @fixme ignore for now + */ + free_decoder_data(dsc); + return LV_RESULT_INVALID; +#endif + } + res = LV_RESULT_OK; } } @@ -268,7 +298,7 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d return res; } - if(dsc->img_data == NULL) return LV_RESULT_OK; + if(dsc->decoded == NULL) return LV_RESULT_OK; /*Need to read via get_area_cb*/ /*Add it to cache*/ t = lv_tick_elaps(t); @@ -281,7 +311,7 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d } cache->weight = t; - cache->data = dsc->img_data; + cache->data = dsc->decoded; cache->invalidate_cb = cache_invalidate_cb; if(dsc->src_type == LV_IMAGE_SRC_FILE) { cache->src = lv_strdup(dsc->src); @@ -293,7 +323,7 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d } cache->user_data = dsc->user_data; /*Need to free data on cache invalidate instead of decoder_close*/ - dsc->img_data = lv_cache_get_data(cache); /*@note: Must get from cache to increase reference count.*/ + dsc->decoded = lv_cache_get_data(cache); /*@note: Must get from cache to increase reference count.*/ dsc->cache_entry = cache; lv_cache_unlock(); @@ -309,9 +339,22 @@ void lv_bin_decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * { LV_UNUSED(decoder); /*Unused*/ - lv_cache_lock(); - lv_cache_release(dsc->cache_entry); - lv_cache_unlock(); + decoder_data_t * decoder_data = dsc->user_data; + if(decoder_data && decoder_data->decoded_partial) { + lv_draw_buf_destroy(decoder_data->decoded_partial); + decoder_data->decoded_partial = NULL; + } + + if(dsc->cache_entry) { + /*Decoded data is in cache, release it from cache's callback*/ + lv_cache_lock(); + lv_cache_release(dsc->cache_entry); + lv_cache_unlock(); + } + else { + /*Data not in cache, free the memory manually*/ + free_decoder_data(dsc); + } } lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, @@ -335,32 +378,47 @@ lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod lv_result_t res = LV_RESULT_INVALID; decoder_data_t * decoder_data = dsc->user_data; + if(decoder_data == NULL) { + LV_LOG_ERROR("Unexpected null decoder data"); + return LV_RESULT_INVALID; + } + lv_fs_file_t * f = decoder_data->f; uint32_t bpp = lv_color_format_get_bpp(cf); int32_t w_px = lv_area_get_width(full_area); uint8_t * img_data = NULL; - uint32_t offset = sizeof(lv_image_header_t); /*All image starts with image header*/ + lv_draw_buf_t * decoded = NULL; + uint32_t offset = 0; /*We only support read line by line for now*/ if(decoded_area->y1 == LV_COORD_MIN) { /*Indexed image is converted to ARGB888*/ uint32_t len = LV_COLOR_FORMAT_IS_INDEXED(cf) ? sizeof(lv_color32_t) * 8 : bpp; + lv_color_format_t cf_decoded = LV_COLOR_FORMAT_IS_INDEXED(cf) ? LV_COLOR_FORMAT_ARGB8888 : cf; + len = (len * w_px) / 8; - img_data = lv_draw_buf_malloc(len, cf); - LV_ASSERT_NULL(img_data); - if(img_data == NULL) - return LV_RESULT_INVALID; + decoded = decoder_data->decoded_partial; + if(decoded && decoded->header.w == w_px) { + /*Use existing one directly*/ + } + else { + decoded = lv_draw_buf_create(w_px, 1, cf_decoded, 0); + if(decoded == NULL) + return LV_RESULT_INVALID; + } *decoded_area = *full_area; decoded_area->y2 = decoded_area->y1; - decoder_data->img_data = img_data; /*Free on decoder close*/ + decoder_data->decoded_partial = decoded; /*Free on decoder close*/ } else { decoded_area->y1++; decoded_area->y2++; - img_data = decoder_data->img_data; + decoded = decoder_data->decoded_partial; /*Already alloced*/ } + img_data = decoded->data; /*Get the buffer to operate on*/ + if(decoded_area->y1 > full_area->y2) { return LV_RESULT_INVALID; } @@ -369,10 +427,12 @@ lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod int32_t x_fraction = decoded_area->x1 % (8 / bpp); uint32_t len = (w_px * bpp + 7) / 8 + 1; /*10px for 1bpp may across 3bytes*/ uint8_t * buf = NULL; + offset += dsc->palette_size * 4; /*Skip palette*/ offset += decoded_area->y1 * dsc->header.stride; offset += decoded_area->x1 * bpp / 8; /*Move to x1*/ if(dsc->src_type == LV_IMAGE_SRC_FILE) { + offset += sizeof(lv_image_header_t); /*File image starts with image header*/ buf = lv_malloc(len); LV_ASSERT_NULL(buf); if(buf == NULL) @@ -393,7 +453,7 @@ lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod if(dsc->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)buf); - dsc->img_data = img_data; /*Return decoded image*/ + dsc->decoded = decoded; /*Return decoded image*/ return LV_RESULT_OK; } @@ -407,7 +467,7 @@ lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod return LV_RESULT_INVALID; } - dsc->img_data = img_data; /*Return decoded image*/ + dsc->decoded = decoded; /*Return decoded image*/ return LV_RESULT_OK; } @@ -431,7 +491,7 @@ lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod return LV_RESULT_INVALID; } - dsc->img_data = img_data; /*Return decoded image*/ + dsc->decoded = decoded; /*Return decoded image*/ return LV_RESULT_OK; } @@ -468,8 +528,8 @@ static void free_decoder_data(lv_image_decoder_dsc_t * dsc) lv_free(decoder_data->f); } - lv_draw_buf_free(decoder_data->img_data); - lv_draw_buf_free(decoder_data->decompressed); + if(decoder_data->decoded) lv_draw_buf_destroy(decoder_data->decoded); + if(decoder_data->decompressed) lv_draw_buf_destroy(decoder_data->decompressed); lv_free(decoder_data->palette); lv_free(decoder_data); dsc->user_data = NULL; @@ -487,11 +547,12 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder uint32_t palette_len = sizeof(lv_color32_t) * LV_COLOR_INDEXED_PALETTE_SIZE(cf); const lv_color32_t * palette; const uint8_t * indexed_data = NULL; + lv_draw_buf_t * draw_buf_indexed = NULL; uint32_t stride = dsc->header.stride; bool is_compressed = dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED; if(is_compressed) { - uint8_t * data = decoder_data->decompressed; + uint8_t * data = decoder_data->decompressed->data; palette = (lv_color32_t *)data; indexed_data = data + palette_len; } @@ -512,13 +573,14 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder } #if LV_BIN_DECODER_RAM_LOAD - indexed_data = lv_draw_buf_malloc(stride * dsc->header.h, cf); - LV_ASSERT_MALLOC(indexed_data); - if(indexed_data == NULL) { + draw_buf_indexed = lv_draw_buf_create(dsc->header.w, dsc->header.h, cf, dsc->header.stride); + if(draw_buf_indexed == NULL) { LV_LOG_ERROR("Draw buffer alloc failed"); goto exit_with_buf; } + indexed_data = draw_buf_indexed->data; + uint32_t data_len = 0; if(lv_fs_seek(f, 0, LV_FS_SEEK_END) != LV_FS_RES_OK || lv_fs_tell(f, &data_len) != LV_FS_RES_OK) { @@ -549,13 +611,16 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder #if LV_BIN_DECODER_RAM_LOAD /*Convert to ARGB8888, since sw renderer cannot render it directly even it's in RAM*/ - stride = lv_draw_buf_width_to_stride(dsc->header.w, LV_COLOR_FORMAT_ARGB8888); - uint8_t * img_data = lv_draw_buf_malloc(stride * dsc->header.h, cf); - if(img_data == NULL) { + lv_draw_buf_t * decoded = lv_draw_buf_create(dsc->header.w, dsc->header.h, LV_COLOR_FORMAT_ARGB8888, + 0); + if(decoded == NULL) { LV_LOG_ERROR("No memory for indexed image"); goto exit_with_buf; } + stride = decoded->header.stride; + uint8_t * img_data = decoded->data; + const uint8_t * in = indexed_data; uint8_t * out = img_data; for(uint32_t y = 0; y < dsc->header.h; y++) { @@ -564,13 +629,11 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder out += stride; } - dsc->header.stride = stride; - dsc->header.cf = LV_COLOR_FORMAT_ARGB8888; - dsc->img_data = img_data; - decoder_data->img_data = img_data; /*Free when decoder closes*/ + dsc->decoded = decoded; + decoder_data->decoded = decoded; /*Free when decoder closes*/ if(dsc->src_type == LV_IMAGE_SRC_FILE && !is_compressed) { decoder_data->palette = (void *)palette; /*Free decoder data on close*/ - lv_draw_buf_free((void *)indexed_data); + lv_draw_buf_destroy(draw_buf_indexed); } return LV_RESULT_OK; @@ -583,6 +646,7 @@ exit_with_buf: #else LV_UNUSED(stride); LV_UNUSED(indexed_data); + LV_UNUSED(draw_buf_indexed); /*It needs to be read by get_area_cb later*/ return LV_RESULT_OK; #endif @@ -602,13 +666,14 @@ static lv_result_t decode_rgb(lv_image_decoder_t * decoder, lv_image_decoder_dsc len += (dsc->header.stride / 2) * dsc->header.h; /*A8 mask*/ } - uint8_t * img_data = lv_draw_buf_malloc(len, cf); - LV_ASSERT_MALLOC(img_data); - if(img_data == NULL) { + lv_draw_buf_t * decoded = lv_draw_buf_create(dsc->header.w, dsc->header.h, cf, dsc->header.stride); + if(decoded == NULL) { LV_LOG_ERROR("No memory for rgb file read"); return LV_RESULT_INVALID; } + uint8_t * img_data = decoded->data; + uint32_t rn; res = fs_read_file_at(f, sizeof(lv_image_header_t), img_data, len, &rn); if(res != LV_FS_RES_OK || rn != len) { @@ -617,8 +682,8 @@ static lv_result_t decode_rgb(lv_image_decoder_t * decoder, lv_image_decoder_dsc return LV_RESULT_INVALID; } - dsc->img_data = img_data; - decoder_data->img_data = img_data; /*Free when decoder closes*/ + dsc->decoded = decoded; + decoder_data->decoded = decoded; /*Free when decoder closes*/ return LV_RESULT_OK; } #endif @@ -633,24 +698,26 @@ static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_deco uint32_t w = (dsc->header.stride * 8) / bpp; uint32_t buf_stride = (w * 8 + 7) >> 3; /*stride for img_data*/ uint32_t buf_len = w * dsc->header.h; /*always decode to A8 format*/ - uint8_t * img_data = lv_draw_buf_malloc(buf_len, dsc->header.cf); + lv_draw_buf_t * decoded; uint32_t file_len = (uint32_t)dsc->header.stride * dsc->header.h; - LV_ASSERT_MALLOC(img_data); - if(img_data == NULL) { + decoded = lv_draw_buf_create(w, dsc->header.h, LV_COLOR_FORMAT_A8, buf_stride); + if(decoded == NULL) { LV_LOG_ERROR("Out of memory"); return LV_RESULT_INVALID; } + uint8_t * img_data = decoded->data; + if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { /*Copy from image data*/ - lv_memcpy(img_data, decoder_data->decompressed, file_len); + lv_memcpy(img_data, decoder_data->decompressed->data, file_len); } else if(dsc->src_type == LV_IMAGE_SRC_FILE) { res = fs_read_file_at(decoder_data->f, sizeof(lv_image_header_t), img_data, file_len, &rn); if(res != LV_FS_RES_OK || rn != file_len) { LV_LOG_WARN("Read header failed: %d", res); - lv_draw_buf_free(img_data); + lv_draw_buf_destroy(decoded); return LV_RESULT_INVALID; } } @@ -691,10 +758,8 @@ static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_deco } } - decoder_data->img_data = img_data; - dsc->img_data = img_data; - dsc->header.stride = buf_stride; - dsc->header.cf = LV_COLOR_FORMAT_A8; + decoder_data->decoded = decoded; + dsc->decoded = decoded; return LV_RESULT_OK; } @@ -796,7 +861,7 @@ static lv_result_t decode_compressed(lv_image_decoder_t * decoder, lv_image_deco } else { /*The decompressed data is the original image data.*/ - dsc->img_data = decoder_data->decompressed; + dsc->decoded = decoder_data->decompressed; res = LV_RESULT_OK; } @@ -877,17 +942,25 @@ static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image return LV_RESULT_INVALID; } - uint8_t * decompressed; + uint8_t * img_data; uint32_t input_len = compressed->compressed_size; uint32_t out_len = compressed->decompressed_size; - /*Note, stride must match.*/ - decompressed = lv_draw_buf_malloc(out_len, dsc->header.cf); + lv_draw_buf_t * decompressed = lv_draw_buf_create(dsc->header.w, dsc->header.h, dsc->header.cf, + dsc->header.stride); if(decompressed == NULL) { LV_LOG_WARN("No memory for decompressed image, input: %" LV_PRIu32 ", output: %" LV_PRIu32, input_len, out_len); return LV_RESULT_INVALID; } + if(decompressed->data_size < out_len) { + LV_LOG_WARN("decompressed size mismatch: %" LV_PRIu32 ", %" LV_PRIu32, decompressed->data_size, out_len); + lv_draw_buf_destroy(decompressed); + return LV_RESULT_INVALID; + } + + img_data = decompressed->data; + if(compressed->method == LV_IMAGE_COMPRESS_RLE) { #if LV_USE_RLE /*Compress always happen on byte*/ @@ -897,37 +970,43 @@ static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image else pixel_byte = (lv_color_format_get_bpp(dsc->header.cf) + 7) >> 3; const uint8_t * input = compressed->data; - uint8_t * output = decompressed; + uint8_t * output = img_data; uint32_t len; len = lv_rle_decompress(input, input_len, output, out_len, pixel_byte); if(len != compressed->decompressed_size) { LV_LOG_WARN("Decompress failed: %" LV_PRIu32 ", got: %" LV_PRIu32, out_len, len); - lv_draw_buf_free(decompressed); + lv_draw_buf_destroy(decompressed); return LV_RESULT_INVALID; } #else LV_LOG_WARN("RLE decompress is not enabled"); - lv_draw_buf_free(decompressed); + lv_draw_buf_destroy(decompressed); return LV_RESULT_INVALID; #endif } else if(compressed->method == LV_IMAGE_COMPRESS_LZ4) { #if LV_USE_LZ4 const char * input = (const char *)compressed->data; - char * output = (char *)decompressed; + char * output = (char *)img_data; int len; len = LZ4_decompress_safe(input, output, input_len, out_len); if(len < 0 || (uint32_t)len != compressed->decompressed_size) { LV_LOG_WARN("Decompress failed: %" LV_PRId32 ", got: %" LV_PRId32, out_len, len); - lv_draw_buf_free(decompressed); + lv_draw_buf_destroy(decompressed); return LV_RESULT_INVALID; } #else LV_LOG_WARN("LZ4 decompress is not enabled"); - lv_draw_buf_free(decompressed); + lv_draw_buf_destroy(decompressed); return LV_RESULT_INVALID; #endif } + else { + LV_UNUSED(img_data); + LV_LOG_WARN("Unknown compression method: %d", compressed->method); + lv_draw_buf_destroy(decompressed); + return LV_RESULT_INVALID; + } decoder_data->decompressed = decompressed; /*Free on decoder close*/ return LV_RESULT_OK; @@ -941,27 +1020,7 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); if(cache) { - dsc->img_data = lv_cache_get_data(cache); - /** - * The img_data may not be consistent with dsc->header.cf - * For indexed image, it could be converted to ARGB8888 when enabled. - * For alpha only image, it's always converted to A8 format. - */ - if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(dsc->header.cf)) { - uint8_t bpp = lv_color_format_get_bpp(dsc->header.cf); - lv_image_header_t header; - lv_image_decoder_get_info(dsc->src, &header); - uint32_t w = (header.stride * 8) / bpp; - uint32_t buf_stride = (w * 8 + 7) >> 3; /*stride for img_data*/ - dsc->header.cf = LV_COLOR_FORMAT_A8; - dsc->header.stride = buf_stride; - } -#if LV_BIN_DECODER_RAM_LOAD - else if(LV_COLOR_FORMAT_IS_INDEXED(dsc->header.cf)) { - dsc->header.stride = lv_draw_buf_width_to_stride(dsc->header.w, LV_COLOR_FORMAT_ARGB8888); - dsc->header.cf = LV_COLOR_FORMAT_ARGB8888; - } -#endif + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ lv_cache_unlock(); return LV_RESULT_OK; @@ -973,7 +1032,7 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, img_dsc, LV_CACHE_SRC_TYPE_POINTER); if(cache) { - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ lv_cache_unlock(); return LV_RESULT_OK; diff --git a/src/libs/bmp/lv_bmp.c b/src/libs/bmp/lv_bmp.c index 5ec9ad037..45890ef16 100644 --- a/src/libs/bmp/lv_bmp.c +++ b/src/libs/bmp/lv_bmp.c @@ -76,7 +76,7 @@ void lv_bmp_deinit(void) **********************/ /** - * Get info about a PNG image + * Get info about a BMP image * @param src can be file name or pointer to a C array * @param header store the info here * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't get the info @@ -135,7 +135,7 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, } /** - * Open a PNG image and return the decided image + * 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 @@ -146,7 +146,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d LV_UNUSED(decoder); LV_UNUSED(args); - /*If it's a PNG file...*/ + /*If it's a BMP file...*/ if(dsc->src_type == LV_IMAGE_SRC_FILE) { const char * fn = dsc->src; @@ -178,7 +178,6 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d LV_ASSERT_MALLOC(dsc->user_data); if(dsc->user_data == NULL) return LV_RESULT_INVALID; lv_memcpy(dsc->user_data, &b, sizeof(b)); - dsc->img_data = NULL; return LV_RESULT_OK; } /* BMP file as data not supported for simplicity. @@ -195,12 +194,13 @@ static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod { LV_UNUSED(decoder); bmp_dsc_t * b = dsc->user_data; - uint32_t line_width_byte = lv_area_get_width(full_area) * (b->bpp / 8); + lv_draw_buf_t * decoded = (void *)dsc->decoded; if(decoded_area->y1 == LV_COORD_MIN) { *decoded_area = *full_area; decoded_area->y2 = decoded_area->y1; - dsc->img_data = lv_malloc(line_width_byte); + if(decoded == NULL) decoded = lv_draw_buf_create(lv_area_get_width(full_area), 1, dsc->header.cf, 0); + dsc->decoded = decoded; } else { decoded_area->y1++; @@ -215,7 +215,8 @@ static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod uint32_t p = b->px_offset + b->row_size_bytes * y; p += (decoded_area->x1) * (b->bpp / 8); lv_fs_seek(&b->f, p, LV_FS_SEEK_SET); - lv_fs_read(&b->f, (void *)dsc->img_data, line_width_byte, NULL); + uint32_t line_width_byte = lv_area_get_width(full_area) * (b->bpp / 8); + lv_fs_read(&b->f, decoded->data, line_width_byte, NULL); return LV_RESULT_OK; } @@ -230,7 +231,7 @@ static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * bmp_dsc_t * b = dsc->user_data; lv_fs_close(&b->f); lv_free(dsc->user_data); - if(dsc->img_data) lv_free((void *)dsc->img_data); + if(dsc->decoded) lv_draw_buf_destroy((void *)dsc->decoded); } diff --git a/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c b/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c index 7cea68ea9..a0749f262 100644 --- a/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c +++ b/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c @@ -36,7 +36,7 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, 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 void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); -static const void * decode_jpeg_file(const char * filename, size_t * size); +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); static void error_exit(j_common_ptr cinfo); static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); @@ -161,11 +161,15 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d const char * fn = dsc->src; size_t decoded_size = 0; uint32_t t = lv_tick_get(); - const void * decoded_img = decode_jpeg_file(fn, &decoded_size); + lv_draw_buf_t * decoded = decode_jpeg_file(fn); + if(decoded == NULL) { + LV_LOG_WARN("decode jpeg file failed"); + return LV_RESULT_INVALID; + } t = lv_tick_elaps(t); lv_cache_lock(); - lv_cache_entry_t * cache = lv_cache_add(decoded_img, decoded_size, decoder->cache_data_type, + lv_cache_entry_t * cache = lv_cache_add(decoded, decoded_size, decoder->cache_data_type, decoded_size); if(cache == NULL) { lv_cache_unlock(); @@ -183,7 +187,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d cache->src = dsc->src; } - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; lv_cache_unlock(); @@ -212,7 +216,7 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); if(cache) { - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ lv_cache_unlock(); return LV_RESULT_OK; @@ -278,7 +282,7 @@ failed: return data; } -static const void * decode_jpeg_file(const char * filename, size_t * size) +static lv_draw_buf_t * decode_jpeg_file(const char * filename) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). @@ -370,17 +374,16 @@ static const void * decode_jpeg_file(const char * filename, size_t * size) * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ + lv_draw_buf_t * decoded; row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - size_t output_buffer_size = cinfo.output_width * cinfo.output_height * JPEG_PIXEL_SIZE; - output_buffer = lv_draw_buf_malloc(output_buffer_size, LV_COLOR_FORMAT_RGB888); - if(output_buffer) { - uint8_t * cur_pos = output_buffer; + decoded = lv_draw_buf_create(cinfo.output_width, cinfo.output_height, LV_COLOR_FORMAT_RGB888, 0); + if(decoded != NULL) { + uint8_t * cur_pos = decoded->data; size_t stride = cinfo.output_width * JPEG_PIXEL_SIZE; - if(size) *size = output_buffer_size; /* while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ @@ -397,7 +400,7 @@ static const void * decode_jpeg_file(const char * filename, size_t * size) /* Assume put_scanline_someplace wants a pointer and sample count. */ lv_memcpy(cur_pos, buffer[0], stride); - cur_pos += stride; + cur_pos += decoded->header.stride; } } @@ -426,7 +429,7 @@ static const void * decode_jpeg_file(const char * filename, size_t * size) */ /* And we're done! */ - return output_buffer; + return decoded; } static bool get_jpeg_size(const char * filename, uint32_t * width, uint32_t * height) @@ -482,7 +485,7 @@ static void error_exit(j_common_ptr cinfo) static void cache_invalidate_cb(lv_cache_entry_t * entry) { if(entry->src_type == LV_CACHE_SRC_TYPE_PATH) lv_free((void *)entry->src); - lv_free((void *)entry->data); + lv_draw_buf_destroy((lv_draw_buf_t *)entry->data); } #endif /*LV_USE_LIBJPEG_TURBO*/ diff --git a/src/libs/libpng/lv_libpng.c b/src/libs/libpng/lv_libpng.c index fbd657dfe..189bd6f0c 100644 --- a/src/libs/libpng/lv_libpng.c +++ b/src/libs/libpng/lv_libpng.c @@ -27,7 +27,7 @@ static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, 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 void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); -static const void * decode_png_file(const char * filename); +static lv_draw_buf_t * decode_png_file(const char * filename); static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); static void cache_invalidate_cb(lv_cache_entry_t * entry); @@ -135,12 +135,31 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d if(dsc->src_type == LV_IMAGE_SRC_FILE) { const char * fn = dsc->src; uint32_t t = lv_tick_get(); - const void * decoded_img = decode_png_file(fn); + lv_draw_buf_t * decoded = decode_png_file(fn); + if(decoded == NULL) { + return LV_RESULT_INVALID; + } + + /*Stride check and adjustment accordingly*/ + if(args && args->stride_align) { + uint32_t expected = lv_draw_buf_width_to_stride(decoded->header.w, decoded->header.cf); + if(expected != decoded->header.stride) { + LV_LOG_INFO("Convert PNG stride to %" LV_PRId32, expected); + lv_draw_buf_t * aligned = lv_draw_buf_adjust_stride(decoded, expected); + lv_draw_buf_destroy(decoded); + if(aligned == NULL) { + LV_LOG_ERROR("png stride adjust failed"); + return LV_RESULT_INVALID; + } + + decoded = aligned; + } + } + t = lv_tick_elaps(t); lv_cache_lock(); - lv_cache_entry_t * cache = lv_cache_add(decoded_img, 0, decoder->cache_data_type, - dsc->header.w * dsc->header.h * sizeof(uint32_t)); + lv_cache_entry_t * cache = lv_cache_add(decoded, 0, decoder->cache_data_type, decoded->data_size); if(cache == NULL) { lv_cache_unlock(); return LV_RESULT_INVALID; @@ -157,7 +176,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d cache->src = dsc->src; } - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; lv_cache_unlock(); @@ -187,7 +206,7 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); if(cache) { - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ lv_cache_unlock(); return LV_RESULT_OK; @@ -253,7 +272,7 @@ failed: return data; } -static const void * decode_png_file(const char * filename) +static lv_draw_buf_t * decode_png_file(const char * filename) { int ret; @@ -281,33 +300,32 @@ static const void * decode_png_file(const char * filename) image.format = PNG_FORMAT_BGRA; /*Alloc image buffer*/ - size_t image_size = PNG_IMAGE_SIZE(image); - void * image_data = lv_draw_buf_malloc(image_size, LV_COLOR_FORMAT_ARGB8888); - - if(image_data) { - /*Start decoding*/ - ret = png_image_finish_read(&image, NULL, image_data, 0, NULL); - if(!ret) { - LV_LOG_ERROR("png decode failed: %d", ret); - lv_draw_buf_free(image_data); - image_data = NULL; - } - } - else { - LV_LOG_ERROR("png alloc %zu failed", image_size); + lv_draw_buf_t * decoded; + decoded = lv_draw_buf_create(image.width, image.height, LV_COLOR_FORMAT_ARGB8888, PNG_IMAGE_ROW_STRIDE(image)); + if(decoded == NULL) { + size_t image_size = PNG_IMAGE_SIZE(image); + LV_LOG_ERROR("png draw buff alloc %zu failed: %s", image_size, filename); + lv_free(data); + return NULL; } - /*free decoder*/ + /*Start decoding*/ + ret = png_image_finish_read(&image, NULL, decoded->data, 0, NULL); png_image_free(&image); lv_free(data); + if(!ret) { + LV_LOG_ERROR("png decode failed: %d", ret); + lv_draw_buf_destroy(decoded); + return NULL; + } - return image_data; + return decoded; } static void cache_invalidate_cb(lv_cache_entry_t * entry) { lv_free((void *)entry->src); - lv_free((void *)entry->data); + lv_draw_buf_destroy((lv_draw_buf_t *)entry->data); } #endif /*LV_USE_LIBPNG*/ diff --git a/src/libs/lodepng/lodepng.c b/src/libs/lodepng/lodepng.c index 69fe98c4f..1663decde 100644 --- a/src/libs/lodepng/lodepng.c +++ b/src/libs/lodepng/lodepng.c @@ -5307,13 +5307,17 @@ static void decodeGeneric(unsigned char ** out, unsigned * w, unsigned * h, lodepng_free(idat); if(!state->error) { - outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); - *out = (unsigned char *)lv_draw_buf_malloc(outsize, LV_COLOR_FORMAT_ARGB8888); - if(!*out) state->error = 83; /*alloc fail*/ + lv_draw_buf_t * decoded = lv_draw_buf_create(*w, *h, LV_COLOR_FORMAT_ARGB8888, 4 * *w); + if(decoded) { + *out = (unsigned char*)decoded; + outsize = decoded->data_size; + } + else state->error = 83; /*alloc fail*/ } if(!state->error) { - lodepng_memset(*out, 0, outsize); - state->error = postProcessScanlines(*out, scanlines, *w, *h, &state->info_png); + lv_draw_buf_t * decoded = (lv_draw_buf_t *)*out; + lodepng_memset(decoded->data, 0, outsize); + state->error = postProcessScanlines(decoded->data, scanlines, *w, *h, &state->info_png); } lodepng_free(scanlines); } diff --git a/src/libs/lodepng/lv_lodepng.c b/src/libs/lodepng/lv_lodepng.c index f729a58a3..756ed17d2 100644 --- a/src/libs/lodepng/lv_lodepng.c +++ b/src/libs/lodepng/lv_lodepng.c @@ -32,7 +32,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d const lv_image_decoder_args_t * args); 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 const void * decode_png_data(const void * png_data, size_t png_data_size); +static lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size); static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); static void cache_invalidate_cb(lv_cache_entry_t * entry); @@ -150,7 +150,7 @@ static lv_result_t decoder_info(struct _lv_image_decoder_t * decoder, const void } /** - * Open a PNG image and decode it into dsc.img_data + * Open a PNG image and decode it into dsc.decoded * @param decoder pointer to the decoder where this function belongs * @param dsc decoded image descriptor * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image @@ -197,10 +197,26 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d } uint32_t t = lv_tick_get(); - const void * decoded_img = decode_png_data(png_data, png_data_size); + lv_draw_buf_t * decoded = decode_png_data(png_data, png_data_size); + /*Stride check and adjustment accordingly*/ + if(args && args->stride_align) { + uint32_t expected = lv_draw_buf_width_to_stride(decoded->header.w, decoded->header.cf); + if(expected != decoded->header.stride) { + LV_LOG_INFO("Convert PNG stride to %" LV_PRId32, expected); + lv_draw_buf_t * aligned = lv_draw_buf_adjust_stride(decoded, expected); + lv_draw_buf_destroy(decoded); + if(aligned == NULL) { + LV_LOG_ERROR("png stride adjust failed"); + return LV_RESULT_INVALID; + } + + decoded = aligned; + } + } + t = lv_tick_elaps(t); cache->weight = t; - cache->data = decoded_img; + cache->data = decoded; cache->invalidate_cb = cache_invalidate_cb; if(dsc->src_type == LV_IMAGE_SRC_FILE) { cache->src = lv_strdup(dsc->src); @@ -212,7 +228,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d cache->src = dsc->src; } - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; lv_cache_unlock(); @@ -242,7 +258,7 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); if(cache) { - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ lv_cache_unlock(); return LV_RESULT_OK; @@ -254,7 +270,7 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, img_dsc, LV_CACHE_SRC_TYPE_POINTER); if(cache) { - dsc->img_data = lv_cache_get_data(cache); + dsc->decoded = lv_cache_get_data(cache); dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ lv_cache_unlock(); return LV_RESULT_OK; @@ -265,24 +281,24 @@ static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) return LV_RESULT_INVALID; } -static const void * decode_png_data(const void * png_data, size_t png_data_size) +static lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size) { unsigned png_width; /*Not used, just required by the decoder*/ unsigned png_height; /*Not used, just required by the decoder*/ uint8_t * img_data = NULL; + lv_draw_buf_t * decoded; /*Decode the image in ARGB8888 */ - unsigned error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size); - + unsigned error = lodepng_decode32((unsigned char **)&decoded, &png_width, &png_height, png_data, png_data_size); if(error) { - if(img_data != NULL) lv_free(img_data); + if(img_data != NULL) lv_draw_buf_destroy(decoded); return NULL; } /*Convert the image to the system's color depth*/ - convert_color_depth(img_data, png_width * png_height); + convert_color_depth(decoded->data, png_width * png_height); - return img_data; + return decoded; } /** @@ -304,7 +320,7 @@ static void convert_color_depth(uint8_t * img_p, uint32_t px_cnt) static void cache_invalidate_cb(lv_cache_entry_t * entry) { if(entry->src_type == LV_CACHE_SRC_TYPE_PATH) lv_free((void *)entry->src); - lv_free((void *)entry->data); + lv_draw_buf_destroy((lv_draw_buf_t *)entry->data); } #endif /*LV_USE_LODEPNG*/ diff --git a/src/libs/tjpgd/lv_tjpgd.c b/src/libs/tjpgd/lv_tjpgd.c index cacd2c8db..a17aa8c87 100644 --- a/src/libs/tjpgd/lv_tjpgd.c +++ b/src/libs/tjpgd/lv_tjpgd.c @@ -206,6 +206,9 @@ static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod LV_UNUSED(full_area); JDEC * jd = dsc->user_data; + lv_draw_buf_t * decoded = (void *)dsc->decoded; + if(decoded == NULL) decoded = lv_malloc_zeroed(sizeof(lv_draw_buf_t)); + dsc->decoded = decoded; uint32_t mx, my; mx = jd->msx * 8; @@ -217,10 +220,11 @@ static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod decoded_area->x2 = -1; jd->scale = 0; jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ - dsc->img_data = jd->workbuf; jd->rst = 0; jd->rsc = 0; - dsc->header.stride = mx * 3; + decoded->data = jd->workbuf; + decoded->header = dsc->header; + decoded->header.stride = mx * 3; } decoded_area->x1 += mx; @@ -233,6 +237,10 @@ static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decod decoded_area->y2 += my; } + decoded->header.w = mx; + decoded->header.h = my; + decoded->data_size = decoded->header.stride * decoded->header.h; + /* Process restart interval if enabled */ JRESULT rc; if(jd->nrst && jd->rst++ == jd->nrst) { @@ -265,6 +273,7 @@ static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * lv_free(jd->device); lv_free(jd->pool_original); lv_free(jd); + lv_free((void *)dsc->decoded); } static int is_jpg(const uint8_t * raw_data, size_t len)