diff --git a/src/draw/lv_image_decoder.c b/src/draw/lv_image_decoder.c index 8eab1858e6..cfeab7949c 100644 --- a/src/draw/lv_image_decoder.c +++ b/src/draw/lv_image_decoder.c @@ -71,7 +71,7 @@ void _lv_image_decoder_init(void) decoder = lv_image_decoder_create(); LV_ASSERT_MALLOC(decoder); if(decoder == NULL) { - LV_LOG_WARN("out of memory"); + LV_LOG_WARN("Out of memory"); return; } @@ -143,7 +143,7 @@ lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src dsc->src = lv_malloc(fnlen + 1); LV_ASSERT_MALLOC(dsc->src); if(dsc->src == NULL) { - LV_LOG_WARN("out of memory"); + LV_LOG_WARN("Out of memory"); return LV_RESULT_INVALID; } lv_strcpy((char *)dsc->src, src); @@ -327,7 +327,7 @@ lv_result_t lv_image_decoder_built_in_info(lv_image_decoder_t * decoder, const v res = lv_fs_read(&f, header, sizeof(lv_image_header_t), &rn); lv_fs_close(&f); if(res != LV_FS_RES_OK || rn != sizeof(lv_image_header_t)) { - LV_LOG_WARN("Image get info get read file header"); + LV_LOG_WARN("Read file header failed: %d", res); return LV_RESULT_INVALID; } } @@ -378,7 +378,7 @@ lv_result_t lv_image_decoder_built_in_open(lv_image_decoder_t * decoder, lv_imag lv_fs_res_t res = lv_fs_open(f, dsc->src, LV_FS_MODE_RD); if(res != LV_FS_RES_OK) { - LV_LOG_WARN("open file failed"); + LV_LOG_WARN("Open file failed: %d", res); lv_free(f); free_decoder_data(dsc); return LV_RESULT_INVALID; @@ -456,6 +456,15 @@ lv_result_t lv_image_decoder_built_in_open(lv_image_decoder_t * decoder, lv_imag decode_indexed_line(cf, dsc->palette, 0, y, img_dsc->header.w, in, out); } } + else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { + /*Alpha only image will need decoder data to store pointer to decoded image, to free it when decoder closes*/ + lv_image_decoder_built_in_data_t * decoder_data = get_decoder_data(dsc); + if(decoder_data == NULL) { + return LV_RESULT_INVALID; + } + + return decode_alpha_only(decoder, dsc); + } else { /*In case of uncompressed formats the image stored in the ROM/RAM. *So simply give its pointer*/ @@ -603,7 +612,7 @@ static lv_image_decoder_built_in_data_t * get_decoder_data(lv_image_decoder_dsc_ data = lv_malloc_zeroed(sizeof(lv_image_decoder_built_in_data_t)); LV_ASSERT_MALLOC(data); if(data == NULL) { - LV_LOG_ERROR("out of memory"); + LV_LOG_ERROR("Out of memory"); return NULL; } @@ -643,13 +652,13 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder lv_color32_t * palette = lv_malloc(palette_len); LV_ASSERT_MALLOC(palette); if(palette == NULL) { - LV_LOG_ERROR("out of memory"); + LV_LOG_ERROR("Out of memory"); return LV_RESULT_INVALID; } res = fs_read_file_at(f, sizeof(lv_image_header_t), (uint8_t *)palette, palette_len, &rn); if(res != LV_FS_RES_OK || rn != palette_len) { - LV_LOG_WARN("read palette failed"); + LV_LOG_WARN("Read palette failed: %d", res); lv_free(palette); return LV_RESULT_INVALID; } @@ -662,14 +671,14 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder uint8_t * file_buf = lv_draw_buf_malloc(stride * dsc->header.h, cf); LV_ASSERT_MALLOC(file_buf); if(file_buf == NULL) { - LV_LOG_ERROR("draw buffer alloc failed"); + LV_LOG_ERROR("Draw buffer alloc failed"); return LV_RESULT_INVALID; } 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) { - LV_LOG_WARN("failed to get file to size"); + LV_LOG_WARN("Failed to get file to size"); goto exit_with_buf; } @@ -677,7 +686,7 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder data_len -= data_offset; res = fs_read_file_at(f, data_offset, (uint8_t *)file_buf, data_len, &rn); if(res != LV_FS_RES_OK || rn != data_len) { - LV_LOG_WARN("read palette failed"); + LV_LOG_WARN("Read indexed image failed: %d", res); goto exit_with_buf; } @@ -685,7 +694,7 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder 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_LOG_ERROR("no memory for indexed image"); + LV_LOG_ERROR("No memory for indexed image"); goto exit_with_buf; } @@ -733,14 +742,14 @@ static lv_result_t decode_rgb(lv_image_decoder_t * decoder, lv_image_decoder_dsc uint8_t * img_data = lv_draw_buf_malloc(len, cf); LV_ASSERT_MALLOC(img_data); if(img_data == NULL) { - LV_LOG_ERROR("no memory for rgb file read"); + LV_LOG_ERROR("No memory for rgb file read"); return LV_RESULT_INVALID; } 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) { - LV_LOG_WARN("read rgb file failed"); + LV_LOG_WARN("Read rgb file failed: %d", res); lv_draw_buf_free(img_data); return LV_RESULT_INVALID; } @@ -766,15 +775,21 @@ static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_deco LV_ASSERT_MALLOC(img_data); if(img_data == NULL) { - LV_LOG_ERROR("out of memory"); + LV_LOG_ERROR("Out of memory"); return LV_RESULT_INVALID; } - 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("Built-in image decoder can't read the palette"); - lv_draw_buf_free(img_data); - return LV_RESULT_INVALID; + 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); + return LV_RESULT_INVALID; + } + } + else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { + /*Copy from image data*/ + lv_memcpy(img_data, ((lv_image_dsc_t *)dsc->src)->data, file_len); } if(dsc->header.cf != LV_COLOR_FORMAT_A8) { @@ -784,7 +799,22 @@ static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_deco uint8_t mask = (1 << bpp) - 1; uint8_t shift = 0; for(uint32_t i = 0; i < buf_len; i++) { - *out = ((*in >> shift) & mask) << (8 - bpp); + /** + * Rounding error: + * Take bpp = 4 as example, alpha value of 0x0 to 0x0F should be + * mapped to 0x00 to 0xFF, thus the equation should be below Equation 3. + * + * But it involves division and multiplication, which is slow. So, if + * we ignore the rounding errors, Equation1, 2 could be faster. But it + * will either has error when alpha is 0xff or 0x00. + * + * We use Equation 3 here for maximum accuracy. + * + * Equation 1: *out = ((*in >> shift) & mask) << (8 - bpp); + * Equation 2: *out = ((((*in >> shift) & mask) + 1) << (8 - bpp)) - 1; + * Equation 3: *out = ((*in >> shift) & mask) * 255 / ((1L << bpp) - 1) ; + */ + *out = ((*in >> shift) & mask) * 255L / ((1L << bpp) - 1) ; shift += bpp; if(shift >= 8) { shift = 0; diff --git a/tests/ref_imgs/draw/image_format_rle.png b/tests/ref_imgs/draw/image_format_rle.png index ccf92c8205..c067816021 100644 Binary files a/tests/ref_imgs/draw/image_format_rle.png and b/tests/ref_imgs/draw/image_format_rle.png differ diff --git a/tests/ref_imgs/draw/image_format_rle_rotate.png b/tests/ref_imgs/draw/image_format_rle_rotate.png index e4fe60489c..1415058d66 100644 Binary files a/tests/ref_imgs/draw/image_format_rle_rotate.png and b/tests/ref_imgs/draw/image_format_rle_rotate.png differ diff --git a/tests/ref_imgs/draw/image_format_rle_rotate_recolor.png b/tests/ref_imgs/draw/image_format_rle_rotate_recolor.png index 7aaefb14be..4ae764b078 100644 Binary files a/tests/ref_imgs/draw/image_format_rle_rotate_recolor.png and b/tests/ref_imgs/draw/image_format_rle_rotate_recolor.png differ diff --git a/tests/src/test_cases/draw/test_image_formats.c b/tests/src/test_cases/draw/test_image_formats.c index 62bebf2c87..79de1ec994 100644 --- a/tests/src/test_cases/draw/test_image_formats.c +++ b/tests/src/test_cases/draw/test_image_formats.c @@ -159,6 +159,9 @@ void test_image_built_in_decode_rotate_and_recolor(void) void test_image_rle_decode(void) { + img_create("rleA1", "A:src/test_files/binimages/cogwheel.A1.rle", false, false); + img_create("rleA2", "A:src/test_files/binimages/cogwheel.A2.rle", false, false); + img_create("rleA4", "A:src/test_files/binimages/cogwheel.A4.rle", false, false); img_create("rleA8", "A:src/test_files/binimages/cogwheel.A8.rle", false, false); img_create("rleI1", "A:src/test_files/binimages/cogwheel.I1.rle", false, false); img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.rle", false, false); @@ -175,6 +178,9 @@ void test_image_rle_decode(void) void test_image_rle_decode_rotate(void) { + img_create("rleA1", "A:src/test_files/binimages/cogwheel.A1.rle", true, false); + img_create("rleA2", "A:src/test_files/binimages/cogwheel.A2.rle", true, false); + img_create("rleA4", "A:src/test_files/binimages/cogwheel.A4.rle", true, false); img_create("rleA8", "A:src/test_files/binimages/cogwheel.A8.rle", true, false); img_create("rleI1", "A:src/test_files/binimages/cogwheel.I1.rle", true, false); img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.rle", true, false); @@ -191,6 +197,9 @@ void test_image_rle_decode_rotate(void) void test_image_rle_decode_rotate_recolor(void) { + img_create("rleA1", "A:src/test_files/binimages/cogwheel.A1.rle", true, true); + img_create("rleA2", "A:src/test_files/binimages/cogwheel.A2.rle", true, true); + img_create("rleA4", "A:src/test_files/binimages/cogwheel.A4.rle", true, true); img_create("rleA8", "A:src/test_files/binimages/cogwheel.A8.rle", true, true); img_create("rleI1", "A:src/test_files/binimages/cogwheel.I1.rle", true, true); img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.rle", true, true);