From d58c8663d4c35a3f0a75256fae0abf75c3e04c47 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 14 May 2019 06:34:20 +0200 Subject: [PATCH] start to reqork the image decoder interface --- lv_conf_template.h | 4 +- src/lv_core/lv_indev.c | 2 +- src/lv_draw/lv_draw_img.c | 505 ------------------------------ src/lv_draw/lv_draw_img.h | 95 +----- src/lv_misc/lv_gc.h | 1 + src/lv_misc/lv_img_decoder.c | 587 +++++++++++++++++++++++++++++++++++ src/lv_misc/lv_img_decoder.h | 165 ++++++++++ 7 files changed, 758 insertions(+), 601 deletions(-) create mode 100644 src/lv_misc/lv_img_decoder.c create mode 100644 src/lv_misc/lv_img_decoder.h diff --git a/lv_conf_template.h b/lv_conf_template.h index 908e18ce6..7eb4065f6 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -145,6 +145,9 @@ typedef void * lv_group_user_data_t; /* 1: Enable alpha indexed images */ #define LV_IMG_CF_ALPHA 1 +/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_img_decoder_user_data_t; + /*1: Add a `user_data` to drivers and objects*/ #define LV_USE_USER_DATA_SINGLE 1 @@ -165,7 +168,6 @@ typedef void * lv_group_user_data_t; * E.g. __attribute__((aligned(4))) */ #define LV_ATTRIBUTE_MEM_ALIGN - /* 1: Variable length array is supported*/ #define LV_COMPILER_VLA_SUPPORTED 1 diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 416937af8..b31bf1ff1 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -876,7 +876,7 @@ static void indev_proc_release(lv_indev_proc_t * proc) if(proc->reset_query != 0) return; - /*Handle click focus*/ + /*Handle click focus*/ #if LV_USE_GROUP /*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/ lv_group_t * g = lv_obj_get_group(proc->types.pointer.act_obj); diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index c09bf3279..ebc9b0e3e 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -7,7 +7,6 @@ * INCLUDES *********************/ #include "lv_draw_img.h" -#include "../lv_misc/lv_fs.h" /********************* * DEFINES @@ -23,33 +22,9 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, lv_opa_t opa_scale); -static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style); -static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); -static void lv_img_decoder_close(void); -static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf); -static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf); - /********************** * STATIC VARIABLES **********************/ -static bool decoder_custom; -static const void * decoder_src; -static lv_img_src_t decoder_src_type; -static lv_img_header_t decoder_header; -static const lv_style_t * decoder_style; -#if LV_USE_FILESYSTEM -static lv_fs_file_t decoder_file; -#endif -#if LV_IMG_CF_INDEXED -static lv_color_t decoder_index_map[256]; -#endif - -static lv_img_decoder_info_f_t lv_img_decoder_info_custom; -static lv_img_decoder_open_f_t lv_img_decoder_open_custom; -static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom; -static lv_img_decoder_close_f_t lv_img_decoder_close_custom; /********************** * MACROS @@ -90,63 +65,6 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * } } -/** - * Initialize and `lv_img_dsc_t` variable with the image's info - * @param src variable, filename or symbol - * @param header store the result here - * @return LV_RES_OK: succeeded; LV_RES_INV: failed - */ -lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header) -{ - header->always_zero = 0; - /*Try to get info with the custom functions first*/ - if(lv_img_decoder_info_custom) { - lv_res_t custom_res; - custom_res = lv_img_decoder_info_custom(src, header); - if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/ - } - - lv_img_src_t src_type = lv_img_src_get_type(src); - if(src_type == LV_IMG_SRC_VARIABLE) { - header->w = ((lv_img_dsc_t *)src)->header.w; - header->h = ((lv_img_dsc_t *)src)->header.h; - header->cf = ((lv_img_dsc_t *)src)->header.cf; - } -#if LV_USE_FILESYSTEM - else if(src_type == LV_IMG_SRC_FILE) { - lv_fs_file_t file; - lv_fs_res_t res; - uint32_t rn; - res = lv_fs_open(&file, src, LV_FS_MODE_RD); - if(res == LV_FS_RES_OK) { - res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn); - lv_fs_close(&file); - } - - /*Create a dummy header on fs error*/ - if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) { - header->w = LV_DPI; - header->h = LV_DPI; - header->cf = LV_IMG_CF_UNKNOWN; - return LV_RES_INV; - } - } -#endif - else if(src_type == LV_IMG_SRC_SYMBOL) { - /*The size depend on the font but it is unknown here. It should be handled outside of the - * function*/ - header->w = 1; - header->h = 1; - /* Symbols always have transparent parts. Important because of cover check in the design - * function. The actual value doesn't matter because lv_draw_label will draw it*/ - header->cf = LV_IMG_CF_ALPHA_1BIT; - } else { - LV_LOG_WARN("Image get info found unknown src type"); - return LV_RES_INV; - } - return LV_RES_OK; -} - /** * Get the color of an image's pixel * @param dsc an image descriptor @@ -512,24 +430,6 @@ lv_img_src_t lv_img_src_get_type(const void * src) return img_src_type; } -/** - * Set custom decoder functions. See the typdefs of the function typed above for more info about - * them - * @param info_fp info get function - * @param open_fp open function - * @param read_fp read line function - * @param close_fp clode function - */ -void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, - lv_img_decoder_read_line_f_t read_fp, - lv_img_decoder_close_f_t close_fp) -{ - lv_img_decoder_info_custom = info_fp; - lv_img_decoder_open_custom = open_fp; - lv_img_decoder_read_line_custom = read_fp; - lv_img_decoder_close_custom = close_fp; -} - /********************** * STATIC FUNCTIONS **********************/ @@ -611,408 +511,3 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas return LV_RES_OK; } - -static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style) -{ - decoder_custom = false; - - /*Try to open with the custom functions first*/ - if(lv_img_decoder_open_custom) { - const uint8_t * custom_res; - custom_res = lv_img_decoder_open_custom(src, style); - if(custom_res != LV_IMG_DECODER_OPEN_FAIL) { - decoder_custom = - true; /*Mark that custom decoder function should be used for this img source.*/ - return custom_res; /*Custom open supported this source*/ - } - } - - decoder_src = src; - decoder_style = style; - decoder_src_type = lv_img_src_get_type(src); - - lv_res_t header_res; - header_res = lv_img_dsc_get_info(src, &decoder_header); - if(header_res == LV_RES_INV) { - decoder_src = NULL; - decoder_src_type = LV_IMG_SRC_UNKNOWN; - LV_LOG_WARN("Built-in image decoder can't get the header info"); - return LV_IMG_DECODER_OPEN_FAIL; - } - - /*Open the file if it's a file*/ - if(decoder_src_type == LV_IMG_SRC_FILE) { -#if LV_USE_FILESYSTEM - lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) { - LV_LOG_WARN("Built-in image decoder can't open the file"); - return LV_IMG_DECODER_OPEN_FAIL; - } -#else - LV_LOG_WARN("Image built-in decoder can read file because LV_USE_FILESYSTEM = 0"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } - - /*Process the different color formats*/ - lv_img_cf_t cf = decoder_header.cf; - if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || - cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { - if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - /*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's - * pointer*/ - return ((lv_img_dsc_t *)decoder_src)->data; - } else { - /*If it's file it need to be read line by line later*/ - return NULL; - } - } else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || - cf == LV_IMG_CF_INDEXED_4BIT || cf == LV_IMG_CF_INDEXED_8BIT) { - -#if LV_IMG_CF_INDEXED -#if LV_USE_FILESYSTEM - lv_color32_t palette_file[256]; -#endif - - lv_color32_t * palette_p = NULL; - uint8_t px_size = lv_img_color_format_get_px_size(cf); - uint32_t palette_size = 1 << px_size; - - if(decoder_src_type == LV_IMG_SRC_FILE) { - /*Read the palette from file*/ -#if LV_USE_FILESYSTEM - lv_fs_seek(&decoder_file, 4); /*Skip the header*/ - lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL); - palette_p = palette_file; -#else - LV_LOG_WARN( - "Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } else { - /*The palette begins in the beginning of the image data. Just point to it.*/ - palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data; - } - - uint32_t i; - for(i = 0; i < palette_size; i++) { - decoder_index_map[i] = - lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue); - } - return NULL; -#else - LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || - cf == LV_IMG_CF_ALPHA_4BIT || cf == LV_IMG_CF_ALPHA_8BIT) { -#if LV_IMG_CF_ALPHA - return NULL; /*Nothing to process*/ -#else - LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } else { - LV_LOG_WARN("Image decoder open: unknown color format") - return LV_IMG_DECODER_OPEN_FAIL; - } -} - -static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) -{ - /*Try to read the line with the custom functions*/ - if(decoder_custom) { - if(lv_img_decoder_read_line_custom) { - lv_res_t custom_res; - custom_res = lv_img_decoder_read_line_custom(x, y, len, buf); - return custom_res; - } else { - LV_LOG_WARN("Image open with custom decoder but read not supported") - } - return LV_RES_INV; /*It"s an error if not returned earlier*/ - } - - if(decoder_src_type == LV_IMG_SRC_FILE) { -#if LV_USE_FILESYSTEM - uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); - - lv_fs_res_t res; - - if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR || - decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || - decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { - uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3; - pos += 4; /*Skip the header*/ - res = lv_fs_seek(&decoder_file, pos); - if(res != LV_FS_RES_OK) { - LV_LOG_WARN("Built-in image decoder seek failed"); - return false; - } - uint32_t btr = len * (px_size >> 3); - uint32_t br = 0; - lv_fs_read(&decoder_file, buf, btr, &br); - if(res != LV_FS_RES_OK || btr != br) { - LV_LOG_WARN("Built-in image decoder read failed"); - return false; - } - } else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT || - decoder_header.cf == LV_IMG_CF_ALPHA_2BIT || - decoder_header.cf == LV_IMG_CF_ALPHA_4BIT || - decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) { - - lv_img_built_in_decoder_line_alpha(x, y, len, buf); - } else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT || - decoder_header.cf == LV_IMG_CF_INDEXED_2BIT || - decoder_header.cf == LV_IMG_CF_INDEXED_4BIT || - decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) { - lv_img_built_in_decoder_line_indexed(x, y, len, buf); - } else { - LV_LOG_WARN("Built-in image decoder read not supports the color format"); - return false; - } -#else - LV_LOG_WARN("Image built-in decoder can't read file because LV_USE_FILESYSTEM = 0"); - return false; -#endif - } else if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - const lv_img_dsc_t * img_dsc = decoder_src; - - if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || - img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || - img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || - img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { - lv_img_built_in_decoder_line_alpha(x, y, len, buf); - } else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || - img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT || - img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || - img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { - lv_img_built_in_decoder_line_indexed(x, y, len, buf); - } else { - LV_LOG_WARN("Built-in image decoder not supports the color format"); - return false; - } - } - - return true; -} - -static void lv_img_decoder_close(void) -{ - /*Try to close with the custom functions*/ - if(decoder_custom) { - if(lv_img_decoder_close_custom) lv_img_decoder_close_custom(); - return; - } - - /*It was opened with built-in decoder*/ - if(decoder_src) { -#if LV_USE_FILESYSTEM - if(decoder_src_type == LV_IMG_SRC_FILE) { - lv_fs_close(&decoder_file); - } -#endif - decoder_src_type = LV_IMG_SRC_UNKNOWN; - decoder_src = NULL; - } -} - -static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf) -{ - -#if LV_IMG_CF_ALPHA - const lv_opa_t alpha1_opa_table[2] = { - 0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ - const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ - const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ - 68, 85, 102, 119, 136, 153, - 170, 187, 204, 221, 238, 255}; - - /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/ - lv_color_t bg_color = decoder_style->image.color; - lv_coord_t i; - for(i = 0; i < len; i++) { -#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full; -#elif LV_COLOR_DEPTH == 16 - /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF; - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF; -#elif LV_COLOR_DEPTH == 32 - *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full; -#else -#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" -#endif - } - - const lv_opa_t * opa_table = NULL; - uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); - uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ - - lv_coord_t w = 0; - uint32_t ofs = 0; - int8_t pos = 0; - switch(decoder_header.cf) { - case LV_IMG_CF_ALPHA_1BIT: - w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ - if(decoder_header.w & 0x7) w++; - ofs += w * y + (x >> 3); /*First pixel*/ - pos = 7 - (x & 0x7); - opa_table = alpha1_opa_table; - break; - case LV_IMG_CF_ALPHA_2BIT: - w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ - if(decoder_header.w & 0x3) w++; - ofs += w * y + (x >> 2); /*First pixel*/ - pos = 6 - ((x & 0x3) * 2); - opa_table = alpha2_opa_table; - break; - case LV_IMG_CF_ALPHA_4BIT: - w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ - if(decoder_header.w & 0x1) w++; - ofs += w * y + (x >> 1); /*First pixel*/ - pos = 4 - ((x & 0x1) * 4); - opa_table = alpha4_opa_table; - break; - case LV_IMG_CF_ALPHA_8BIT: - w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ - ofs += w * y + x; /*First pixel*/ - pos = 0; - break; - } - -#if LV_USE_FILESYSTEM -#if LV_COMPILER_VLA_SUPPORTED - uint8_t fs_buf[w]; -#else - uint8_t fs_buf[LV_HOR_RES_MAX]; -#endif -#endif - const uint8_t * data_tmp = NULL; - if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - const lv_img_dsc_t * img_dsc = decoder_src; - data_tmp = img_dsc->data + ofs; - } else { -#if LV_USE_FILESYSTEM - lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ - lv_fs_read(&decoder_file, fs_buf, w, NULL); - data_tmp = fs_buf; -#else - LV_LOG_WARN( - "Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0"); - data_tmp = NULL; /*To avoid warnings*/ - return LV_RES_INV; -#endif - } - - uint8_t byte_act = 0; - uint8_t val_act; - for(i = 0; i < len; i++) { - val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; - - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = - decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act]; - - pos -= px_size; - if(pos < 0) { - pos = 8 - px_size; - data_tmp++; - } - } - - return LV_RES_OK; - -#else - LV_LOG_WARN( - "Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h"); - return LV_RES_INV; -#endif -} - -static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf) -{ - -#if LV_IMG_CF_INDEXED - uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); - uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ - - lv_coord_t w = 0; - int8_t pos = 0; - uint32_t ofs = 0; - switch(decoder_header.cf) { - case LV_IMG_CF_INDEXED_1BIT: - w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ - if(decoder_header.w & 0x7) w++; - ofs += w * y + (x >> 3); /*First pixel*/ - ofs += 8; /*Skip the palette*/ - pos = 7 - (x & 0x7); - break; - case LV_IMG_CF_INDEXED_2BIT: - w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ - if(decoder_header.w & 0x3) w++; - ofs += w * y + (x >> 2); /*First pixel*/ - ofs += 16; /*Skip the palette*/ - pos = 6 - ((x & 0x3) * 2); - break; - case LV_IMG_CF_INDEXED_4BIT: - w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ - if(decoder_header.w & 0x1) w++; - ofs += w * y + (x >> 1); /*First pixel*/ - ofs += 64; /*Skip the palette*/ - pos = 4 - ((x & 0x1) * 4); - break; - case LV_IMG_CF_INDEXED_8BIT: - w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ - ofs += w * y + x; /*First pixel*/ - ofs += 1024; /*Skip the palette*/ - pos = 0; - break; - } - -#if LV_USE_FILESYSTEM -#if LV_COMPILER_VLA_SUPPORTED - uint8_t fs_buf[w]; -#else - uint8_t fs_buf[LV_HOR_RES_MAX]; -#endif -#endif - const uint8_t * data_tmp = NULL; - if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - const lv_img_dsc_t * img_dsc = decoder_src; - data_tmp = img_dsc->data + ofs; - } else { -#if LV_USE_FILESYSTEM - lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ - lv_fs_read(&decoder_file, fs_buf, w, NULL); - data_tmp = fs_buf; -#else - LV_LOG_WARN( - "Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0"); - data_tmp = NULL; /*To avoid warnings*/ - return LV_RES_INV; -#endif - } - - uint8_t byte_act = 0; - uint8_t val_act; - lv_coord_t i; - lv_color_t * cbuf = (lv_color_t *)buf; - for(i = 0; i < len; i++) { - val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; - cbuf[i] = decoder_index_map[val_act]; - - pos -= px_size; - if(pos < 0) { - pos = 8 - px_size; - data_tmp++; - } - } - - return LV_RES_OK; -#else - LV_LOG_WARN( - "Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h"); - return LV_RES_INV; -#endif -} diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 33d332d23..43c1a13df 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -15,108 +15,15 @@ extern "C" { *********************/ #include "lv_draw.h" #include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_img_decoder.h" /********************* * DEFINES *********************/ -#define LV_IMG_DECODER_OPEN_FAIL ((void *)(-1)) /********************** * TYPEDEFS **********************/ -struct _lv_img_t; - -typedef struct -{ - - /* The first 8 bit is very important to distinguish the different source types. - * For more info see `lv_img_get_src_type()` in lv_img.c */ - uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/ - uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a - non-printable character*/ - - uint32_t reserved : 2; /*Reserved to be used later*/ - - uint32_t w : 11; /*Width of the image map*/ - uint32_t h : 11; /*Height of the image map*/ -} lv_img_header_t; - -/*Image color format*/ -enum { - LV_IMG_CF_UNKNOWN = 0, - - LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ - LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder - function*/ - LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs - custom decoder function*/ - - LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ - LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ - LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels - will be transparent*/ - - LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ - - LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ - LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ - LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ - LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ -}; -typedef uint8_t lv_img_cf_t; - -/* Image header it is compatible with - * the result image converter utility*/ -typedef struct -{ - lv_img_header_t header; - uint32_t data_size; - const uint8_t * data; -} lv_img_dsc_t; - -/* Decoder function definitions */ - -/** - * Get info from an image and store in the `header` - * @param src the image source. Can be a pointer to a C array or a file name (Use - * `lv_img_src_get_type` to determine the type) - * @param header store the info here - * @return LV_RES_OK: info written correctly; LV_RES_INV: failed - */ -typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header); - -/** - * Open an image for decoding. Prepare it as it is required to read it later - * @param src the image source. Can be a pointer to a C array or a file name (Use - * `lv_img_src_get_type` to determine the type) - * @param style the style of image (maybe it will be required to determine a color or something) - * @return there are 3 possible return values: - * 1) buffer with the decoded image - * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image - * line-by-line 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an - * error occurred - */ -typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); - -/** - * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. - * Required only if the "open" function can't return with the whole decoded pixel array. - * @param x start x coordinate - * @param y startt y coordinate - * @param len number of pixels to decode - * @param buf a buffer to store the decoded pixels - * @return LV_RES_OK: ok; LV_RES_INV: failed - */ -typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf); - -/** - * Close the pending decoding. Free resources etc. - */ -typedef void (*lv_img_decoder_close_f_t)(void); /********************** * GLOBAL PROTOTYPES diff --git a/src/lv_misc/lv_gc.h b/src/lv_misc/lv_gc.h index 97aeb6b79..ac9d93f3d 100644 --- a/src/lv_misc/lv_gc.h +++ b/src/lv_misc/lv_gc.h @@ -37,6 +37,7 @@ extern "C" { prefix lv_ll_t _lv_file_ll; \ prefix lv_ll_t _lv_anim_ll; \ prefix lv_ll_t _lv_group_ll; \ + prefix lv_ll_t _lv_img_defoder_ll; \ prefix void * _lv_task_act; #define LV_NO_PREFIX diff --git a/src/lv_misc/lv_img_decoder.c b/src/lv_misc/lv_img_decoder.c new file mode 100644 index 000000000..d0a045407 --- /dev/null +++ b/src/lv_misc/lv_img_decoder.c @@ -0,0 +1,587 @@ +/** + * @file lv_img_decoder.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_img_decoder.h" +#include "lv_ll.h" + +#if defined(LV_GC_INCLUDE) +#include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +/** + * Initialize the image decoder module + * */ +void lv_img_decoder_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_img_defoder_ll), sizeof(lv_img_decoder_t)); + + lv_img_decoder_t decoder; + + /*Create a decoder for true color images*/ + decoder = lv_img_decoder_craete(); + if(decoder) return; + + /*Create a decoder for Alpha indexed images*/ + decoder = lv_img_decoder_craete(); + if(decoder) return; + + /*Create a decoder for color indexed images*/ + decoder = lv_img_decoder_craete(); + if(decoder) return; + +} + +lv_img_decoder_t * lv_img_decoder_craete(void) +{ + lv_img_decoder_t * decoder; + decoder = lv_ll_ins_head(&LV_GC_ROOT(_lv_img_defoder_ll)); + lv_mem_assert(decoder); + + return decoder; +} + +void lv_img_decoder_delete(lv_img_decoder_t * decoder) +{ + lv_ll_rem(&LV_GC_ROOT(_lv_img_defoder_ll), decoder); + lv_mem_free(decoder); +} + +void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb) +{ + decoder->info_cb = info_cb; +} + +void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb) +{ + decoder->open_cb = open_cb; +} + +void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb) +{ + decoder->read_line_cb = read_line_cb; +} + +void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb) +{ + decoder->read_line_cb = close_cb; +} + +void lv_img_decoder_set_user_data(lv_img_decoder_t * decoder, lv_img_decoder_t user_data) +{ + memcpy(&decoder->user_data, &user_data, sizeof(user_data)); +} + +lv_img_decoder_t lv_img_decoder_get_user_data(lv_img_decoder_t * decoder) +{ + return decoder->user_data; +} + +lv_img_decoder_t * lv_img_decoder_get_user_data_ptr(lv_img_decoder_t * decoder) +{ + return &decoder->user_data; +} + + +lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header) +{ + header->always_zero = 0; + + lv_res_t res; + lv_img_decoder_t * d; + LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d) { + res = LV_RES_INV; + if(d->info_cb) { + res = d->info_cb(d, src, header); + if(res == LV_RES_OK) break; + } + } + + return res; +} + + +const uint8_t * lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style) +{ + dsc->style = style; + dsc->src = src; + dsc->src_type = lv_img_src_get_type(src); + + lv_res_t header_res; + header_res = lv_img_decoder_get_info(src, &dsc->header); + if(header_res != LV_RES_OK) return LV_IMG_DECODER_OPEN_FAIL; + + const uint8_t * res = NULL; + lv_img_decoder_t * d; + LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d) { + res = NULL; + dsc->decoder = d; + if(d->open_cb) res = d->open_cb(d, dsc); + + if(res != LV_IMG_DECODER_OPEN_FAIL) break; + } +} + +static lv_res_t lv_img_decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + lv_res_t res = LV_RES_INV; + if(decoder->read_line_cb)res = decoder->read_line_cb(decoder, dsc, x, y, len, buf); + + return res; +} + +static void lv_img_decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) +{ + if(decoder->close_cb) decoder->close_cb(decoder, dsc); +} + + +static lv_res_t img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header) +{ + lv_img_src_t src_type = lv_img_src_get_type(src); + if(src_type == LV_IMG_SRC_VARIABLE) { + header->w = ((lv_img_dsc_t *)src)->header.w; + header->h = ((lv_img_dsc_t *)src)->header.h; + header->cf = ((lv_img_dsc_t *)src)->header.cf; + } + #if LV_USE_FILESYSTEM + else if(src_type == LV_IMG_SRC_FILE) { + lv_fs_file_t file; + lv_fs_res_t res; + uint32_t rn; + res = lv_fs_open(&file, src, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn); + lv_fs_close(&file); + } + + /*Create a dummy header on fs error*/ + if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) { + header->w = LV_DPI; + header->h = LV_DPI; + header->cf = LV_IMG_CF_UNKNOWN; + return LV_RES_INV; + } + } + #endif + else if(src_type == LV_IMG_SRC_SYMBOL) { + /*The size depend on the font but it is unknown here. It should be handled outside of the + * function*/ + header->w = 1; + header->h = 1; + /* Symbols always have transparent parts. Important because of cover check in the design + * function. The actual value doesn't matter because lv_draw_label will draw it*/ + header->cf = LV_IMG_CF_ALPHA_1BIT; + } else { + LV_LOG_WARN("Image get info found unknown src type"); + return LV_RES_INV; + } + return LV_RES_OK; +} + +static uint8_t * img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc,) +{ + if(header_res == LV_RES_INV) { + decoder_src = NULL; + decoder_src_type = LV_IMG_SRC_UNKNOWN; + LV_LOG_WARN("Built-in image decoder can't get the header info"); + return LV_IMG_DECODER_OPEN_FAIL; + } + + /*Open the file if it's a file*/ + if(decoder_src_type == LV_IMG_SRC_FILE) { +#if LV_USE_FILESYSTEM + lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder can't open the file"); + return LV_IMG_DECODER_OPEN_FAIL; + } +#else + LV_LOG_WARN("Image built-in decoder can read file because LV_USE_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } + + /*Process the different color formats*/ + lv_img_cf_t cf = decoder_header.cf; + if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + /*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's + * pointer*/ + return ((lv_img_dsc_t *)decoder_src)->data; + } else { + /*If it's file it need to be read line by line later*/ + return NULL; + } + } else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || + cf == LV_IMG_CF_INDEXED_4BIT || cf == LV_IMG_CF_INDEXED_8BIT) { + +#if LV_IMG_CF_INDEXED +#if LV_USE_FILESYSTEM + lv_color32_t palette_file[256]; +#endif + + lv_color32_t * palette_p = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(cf); + uint32_t palette_size = 1 << px_size; + + if(decoder_src_type == LV_IMG_SRC_FILE) { + /*Read the palette from file*/ +#if LV_USE_FILESYSTEM + lv_fs_seek(&decoder_file, 4); /*Skip the header*/ + lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL); + palette_p = palette_file; +#else + LV_LOG_WARN( + "Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + /*The palette begins in the beginning of the image data. Just point to it.*/ + palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data; + } + + uint32_t i; + for(i = 0; i < palette_size; i++) { + decoder_index_map[i] = + lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue); + } + return NULL; +#else + LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || + cf == LV_IMG_CF_ALPHA_4BIT || cf == LV_IMG_CF_ALPHA_8BIT) { +#if LV_IMG_CF_ALPHA + return NULL; /*Nothing to process*/ +#else + LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + LV_LOG_WARN("Image decoder open: unknown color format") + return LV_IMG_DECODER_OPEN_FAIL; + } +} + + +static lv_res_t lv_img_decoder_built_in_line_read(lv_img_decoder_t * decoder, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf) +{ + if(dsc->src_type == LV_IMG_SRC_FILE) { + #if LV_USE_FILESYSTEM + uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + + lv_fs_res_t res; + + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || + dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) + { + uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3; + pos += 4; /*Skip the header*/ + res = lv_fs_seek(&decoder_file, pos); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder seek failed"); + return false; + } + uint32_t btr = len * (px_size >> 3); + uint32_t br = 0; + lv_fs_read(&decoder_file, buf, btr, &br); + if(res != LV_FS_RES_OK || btr != br) { + LV_LOG_WARN("Built-in image decoder read failed"); + return false; + } + } else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_2BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_4BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) { + + lv_img_built_in_decoder_line_alpha(x, y, len, buf); + } else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_2BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_4BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) { + lv_img_built_in_decoder_line_indexed(x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder read not supports the color format"); + return false; + } + #else + LV_LOG_WARN("Image built-in decoder can't read file because LV_USE_FILESYSTEM = 0"); + return false; + #endif + } else if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + + if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + lv_img_built_in_decoder_line_alpha(x, y, len, buf); + } else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { + lv_img_built_in_decoder_line_indexed(x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder not supports the color format"); + return false; + } + } + + return true; +} + +static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) +{ + + /*It was opened with built-in decoder*/ + if(decoder_src) { +#if LV_USE_FILESYSTEM + if(decoder_src_type == LV_IMG_SRC_FILE) { + lv_fs_close(&decoder_file); + } +#endif + decoder_src_type = LV_IMG_SRC_UNKNOWN; + decoder_src = NULL; + } +} + + +static lv_res_t lv_img_built_in_decoder_line_alpha(lv_img_decoder_t * decoder, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf) +{ + +#if LV_IMG_CF_ALPHA + const lv_opa_t alpha1_opa_table[2] = { + 0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, 136, 153, + 170, 187, 204, 221, 238, 255}; + + /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/ + lv_color_t bg_color = decoder_style->image.color; + lv_coord_t i; + for(i = 0; i < len; i++) { +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF; + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF; +#elif LV_COLOR_DEPTH == 32 + *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full; +#else +#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" +#endif + } + + const lv_opa_t * opa_table = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + uint32_t ofs = 0; + int8_t pos = 0; + switch(decoder_header.cf) { + case LV_IMG_CF_ALPHA_1BIT: + w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(decoder_header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + pos = 7 - (x & 0x7); + opa_table = alpha1_opa_table; + break; + case LV_IMG_CF_ALPHA_2BIT: + w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(decoder_header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + pos = 6 - ((x & 0x3) * 2); + opa_table = alpha2_opa_table; + break; + case LV_IMG_CF_ALPHA_4BIT: + w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(decoder_header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + pos = 4 - ((x & 0x1) * 4); + opa_table = alpha4_opa_table; + break; + case LV_IMG_CF_ALPHA_8BIT: + w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + pos = 0; + break; + } + +#if LV_USE_FILESYSTEM +#if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +#else + uint8_t fs_buf[LV_HOR_RES_MAX]; +#endif +#endif + const uint8_t * data_tmp = NULL; + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + data_tmp = img_dsc->data + ofs; + } else { +#if LV_USE_FILESYSTEM + lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(&decoder_file, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN( + "Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + uint8_t byte_act = 0; + uint8_t val_act; + for(i = 0; i < len; i++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = + decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; + +#else + LV_LOG_WARN( + "Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} + +static lv_res_t lv_img_built_in_decoder_line_indexed(lv_img_decoder_t * decoder, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf) +{ + +#if LV_IMG_CF_INDEXED + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + int8_t pos = 0; + uint32_t ofs = 0; + switch(decoder_header.cf) { + case LV_IMG_CF_INDEXED_1BIT: + w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(decoder_header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + ofs += 8; /*Skip the palette*/ + pos = 7 - (x & 0x7); + break; + case LV_IMG_CF_INDEXED_2BIT: + w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(decoder_header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + ofs += 16; /*Skip the palette*/ + pos = 6 - ((x & 0x3) * 2); + break; + case LV_IMG_CF_INDEXED_4BIT: + w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(decoder_header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + ofs += 64; /*Skip the palette*/ + pos = 4 - ((x & 0x1) * 4); + break; + case LV_IMG_CF_INDEXED_8BIT: + w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + ofs += 1024; /*Skip the palette*/ + pos = 0; + break; + } + +#if LV_USE_FILESYSTEM +#if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +#else + uint8_t fs_buf[LV_HOR_RES_MAX]; +#endif +#endif + const uint8_t * data_tmp = NULL; + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + data_tmp = img_dsc->data + ofs; + } else { +#if LV_USE_FILESYSTEM + lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(&decoder_file, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN( + "Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + uint8_t byte_act = 0; + uint8_t val_act; + lv_coord_t i; + lv_color_t * cbuf = (lv_color_t *)buf; + for(i = 0; i < len; i++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + cbuf[i] = decoder_index_map[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; +#else + LV_LOG_WARN( + "Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} + + + + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/src/lv_misc/lv_img_decoder.h b/src/lv_misc/lv_img_decoder.h new file mode 100644 index 000000000..7432a4342 --- /dev/null +++ b/src/lv_misc/lv_img_decoder.h @@ -0,0 +1,165 @@ +/** + * @file lv_img_decoder.h + * + */ + +#ifndef LV_IMG_DEOCER_H +#define LV_IMG_DEOCER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../../lv_conf.h" +#endif + +#include +#include "lv_fs.h" + +/********************* + * DEFINES + *********************/ +#define LV_IMG_DECODER_OPEN_FAIL ((void *)(-1)); + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a + non-printable character*/ + + uint32_t reserved : 2; /*Reserved to be used later*/ + + uint32_t w : 11; /*Width of the image map*/ + uint32_t h : 11; /*Height of the image map*/ +} lv_img_header_t; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKNOWN = 0, + + LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder + function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs + custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels + will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + +struct _lv_img_decoder; +struct _lv_img_decoder_dsc; + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use + * `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(struct _lv_img_decoder * decoder, const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param src the image source. Can be a pointer to a C array or a file name (Use + * `lv_img_src_get_type` to determine the type) + * @param style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image + * line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an + * error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param x start x coordinate + * @param y start y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc); + +typedef struct _lv_img_decoder_dsc { + lv_img_decoder_info_f_t info_cb; + lv_img_decoder_open_f_t open_cb; + lv_img_decoder_read_line_f_t read_line_cb; + lv_img_decoder_close_f_t close_cb; + +#if LV_USE_USER_DATA_SINGLE + lv_img_decoder_user_data_t user_data; +#endif +}lv_img_decoder_t; + + +typedef struct { + lv_img_decoder_t * decoder; + const lv_style_t * style; + const void * src; + lv_img_src_t src_type; + lv_img_header_t header; + +#if LV_USE_USER_DATA_SINGLE + void * user_data; +#endif +}lv_img_decoder_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/