mirror of
https://github.com/lvgl/lvgl.git
synced 2026-06-01 16:58:33 +08:00
feat(image): support C array type of alpha-only image in the built-in decoder (#4797)
Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
This commit is contained in:
+50
-20
@@ -71,7 +71,7 @@ void _lv_image_decoder_init(void)
|
|||||||
decoder = lv_image_decoder_create();
|
decoder = lv_image_decoder_create();
|
||||||
LV_ASSERT_MALLOC(decoder);
|
LV_ASSERT_MALLOC(decoder);
|
||||||
if(decoder == NULL) {
|
if(decoder == NULL) {
|
||||||
LV_LOG_WARN("out of memory");
|
LV_LOG_WARN("Out of memory");
|
||||||
return;
|
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);
|
dsc->src = lv_malloc(fnlen + 1);
|
||||||
LV_ASSERT_MALLOC(dsc->src);
|
LV_ASSERT_MALLOC(dsc->src);
|
||||||
if(dsc->src == NULL) {
|
if(dsc->src == NULL) {
|
||||||
LV_LOG_WARN("out of memory");
|
LV_LOG_WARN("Out of memory");
|
||||||
return LV_RESULT_INVALID;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
lv_strcpy((char *)dsc->src, src);
|
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);
|
res = lv_fs_read(&f, header, sizeof(lv_image_header_t), &rn);
|
||||||
lv_fs_close(&f);
|
lv_fs_close(&f);
|
||||||
if(res != LV_FS_RES_OK || rn != sizeof(lv_image_header_t)) {
|
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;
|
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);
|
lv_fs_res_t res = lv_fs_open(f, dsc->src, LV_FS_MODE_RD);
|
||||||
if(res != LV_FS_RES_OK) {
|
if(res != LV_FS_RES_OK) {
|
||||||
LV_LOG_WARN("open file failed");
|
LV_LOG_WARN("Open file failed: %d", res);
|
||||||
lv_free(f);
|
lv_free(f);
|
||||||
free_decoder_data(dsc);
|
free_decoder_data(dsc);
|
||||||
return LV_RESULT_INVALID;
|
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);
|
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 {
|
else {
|
||||||
/*In case of uncompressed formats the image stored in the ROM/RAM.
|
/*In case of uncompressed formats the image stored in the ROM/RAM.
|
||||||
*So simply give its pointer*/
|
*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));
|
data = lv_malloc_zeroed(sizeof(lv_image_decoder_built_in_data_t));
|
||||||
LV_ASSERT_MALLOC(data);
|
LV_ASSERT_MALLOC(data);
|
||||||
if(data == NULL) {
|
if(data == NULL) {
|
||||||
LV_LOG_ERROR("out of memory");
|
LV_LOG_ERROR("Out of memory");
|
||||||
return NULL;
|
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_color32_t * palette = lv_malloc(palette_len);
|
||||||
LV_ASSERT_MALLOC(palette);
|
LV_ASSERT_MALLOC(palette);
|
||||||
if(palette == NULL) {
|
if(palette == NULL) {
|
||||||
LV_LOG_ERROR("out of memory");
|
LV_LOG_ERROR("Out of memory");
|
||||||
return LV_RESULT_INVALID;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fs_read_file_at(f, sizeof(lv_image_header_t), (uint8_t *)palette, palette_len, &rn);
|
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) {
|
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);
|
lv_free(palette);
|
||||||
return LV_RESULT_INVALID;
|
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);
|
uint8_t * file_buf = lv_draw_buf_malloc(stride * dsc->header.h, cf);
|
||||||
LV_ASSERT_MALLOC(file_buf);
|
LV_ASSERT_MALLOC(file_buf);
|
||||||
if(file_buf == NULL) {
|
if(file_buf == NULL) {
|
||||||
LV_LOG_ERROR("draw buffer alloc failed");
|
LV_LOG_ERROR("Draw buffer alloc failed");
|
||||||
return LV_RESULT_INVALID;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t data_len = 0;
|
uint32_t data_len = 0;
|
||||||
if(lv_fs_seek(f, 0, LV_FS_SEEK_END) != LV_FS_RES_OK ||
|
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_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;
|
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;
|
data_len -= data_offset;
|
||||||
res = fs_read_file_at(f, data_offset, (uint8_t *)file_buf, data_len, &rn);
|
res = fs_read_file_at(f, data_offset, (uint8_t *)file_buf, data_len, &rn);
|
||||||
if(res != LV_FS_RES_OK || rn != data_len) {
|
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;
|
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);
|
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);
|
uint8_t * img_data = lv_draw_buf_malloc(stride * dsc->header.h, cf);
|
||||||
if(img_data == NULL) {
|
if(img_data == NULL) {
|
||||||
LV_LOG_ERROR("no memory for indexed image");
|
LV_LOG_ERROR("No memory for indexed image");
|
||||||
goto exit_with_buf;
|
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);
|
uint8_t * img_data = lv_draw_buf_malloc(len, cf);
|
||||||
LV_ASSERT_MALLOC(img_data);
|
LV_ASSERT_MALLOC(img_data);
|
||||||
if(img_data == NULL) {
|
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;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t rn;
|
uint32_t rn;
|
||||||
res = fs_read_file_at(f, sizeof(lv_image_header_t), img_data, len, &rn);
|
res = fs_read_file_at(f, sizeof(lv_image_header_t), img_data, len, &rn);
|
||||||
if(res != LV_FS_RES_OK || rn != len) {
|
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);
|
lv_draw_buf_free(img_data);
|
||||||
return LV_RESULT_INVALID;
|
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);
|
LV_ASSERT_MALLOC(img_data);
|
||||||
if(img_data == NULL) {
|
if(img_data == NULL) {
|
||||||
LV_LOG_ERROR("out of memory");
|
LV_LOG_ERROR("Out of memory");
|
||||||
return LV_RESULT_INVALID;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fs_read_file_at(decoder_data->f, sizeof(lv_image_header_t), img_data, file_len, &rn);
|
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
|
||||||
if(res != LV_FS_RES_OK || rn != file_len) {
|
res = fs_read_file_at(decoder_data->f, sizeof(lv_image_header_t), img_data, file_len, &rn);
|
||||||
LV_LOG_WARN("Built-in image decoder can't read the palette");
|
if(res != LV_FS_RES_OK || rn != file_len) {
|
||||||
lv_draw_buf_free(img_data);
|
LV_LOG_WARN("Read header failed: %d", res);
|
||||||
return LV_RESULT_INVALID;
|
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) {
|
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 mask = (1 << bpp) - 1;
|
||||||
uint8_t shift = 0;
|
uint8_t shift = 0;
|
||||||
for(uint32_t i = 0; i < buf_len; i++) {
|
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;
|
shift += bpp;
|
||||||
if(shift >= 8) {
|
if(shift >= 8) {
|
||||||
shift = 0;
|
shift = 0;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 112 KiB |
@@ -159,6 +159,9 @@ void test_image_built_in_decode_rotate_and_recolor(void)
|
|||||||
|
|
||||||
void test_image_rle_decode(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("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("rleI1", "A:src/test_files/binimages/cogwheel.I1.rle", false, false);
|
||||||
img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.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)
|
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("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("rleI1", "A:src/test_files/binimages/cogwheel.I1.rle", true, false);
|
||||||
img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.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)
|
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("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("rleI1", "A:src/test_files/binimages/cogwheel.I1.rle", true, true);
|
||||||
img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.rle", true, true);
|
img_create("rleI2", "A:src/test_files/binimages/cogwheel.I2.rle", true, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user