acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_draw_img.c (10832B)
1 /** 2 * @file lv_draw_img.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_draw_img.h" 10 #include "lv_img_cache.h" 11 #include "../hal/lv_hal_disp.h" 12 #include "../misc/lv_log.h" 13 #include "../core/lv_refr.h" 14 #include "../misc/lv_mem.h" 15 #include "../misc/lv_math.h" 16 17 /********************* 18 * DEFINES 19 *********************/ 20 21 /********************** 22 * TYPEDEFS 23 **********************/ 24 25 /********************** 26 * STATIC PROTOTYPES 27 **********************/ 28 LV_ATTRIBUTE_FAST_MEM static lv_res_t decode_and_draw(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, 29 const lv_area_t * coords, const void * src); 30 31 static void show_error(lv_draw_ctx_t * draw_ctx, const lv_area_t * coords, const char * msg); 32 static void draw_cleanup(_lv_img_cache_entry_t * cache); 33 34 /********************** 35 * STATIC VARIABLES 36 **********************/ 37 38 /********************** 39 * MACROS 40 **********************/ 41 42 /********************** 43 * GLOBAL FUNCTIONS 44 **********************/ 45 46 void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc) 47 { 48 lv_memset_00(dsc, sizeof(lv_draw_img_dsc_t)); 49 dsc->recolor = lv_color_black(); 50 dsc->opa = LV_OPA_COVER; 51 dsc->zoom = LV_IMG_ZOOM_NONE; 52 dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0; 53 } 54 55 /** 56 * Draw an image 57 * @param coords the coordinates of the image 58 * @param mask the image will be drawn only in this area 59 * @param src pointer to a lv_color_t array which contains the pixels of the image 60 * @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable 61 */ 62 void lv_draw_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const lv_area_t * coords, const void * src) 63 { 64 if(src == NULL) { 65 LV_LOG_WARN("Image draw: src is NULL"); 66 show_error(draw_ctx, coords, "No\ndata"); 67 return; 68 } 69 70 if(dsc->opa <= LV_OPA_MIN) return; 71 72 lv_res_t res; 73 if(draw_ctx->draw_img) { 74 res = draw_ctx->draw_img(draw_ctx, dsc, coords, src); 75 } 76 else { 77 res = decode_and_draw(draw_ctx, dsc, coords, src); 78 } 79 80 if(res == LV_RES_INV) { 81 LV_LOG_WARN("Image draw error"); 82 show_error(draw_ctx, coords, "No\ndata"); 83 return; 84 } 85 } 86 87 /** 88 * Get the pixel size of a color format in bits 89 * @param cf a color format (`LV_IMG_CF_...`) 90 * @return the pixel size in bits 91 */ 92 uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf) 93 { 94 uint8_t px_size = 0; 95 96 switch(cf) { 97 case LV_IMG_CF_UNKNOWN: 98 case LV_IMG_CF_RAW: 99 px_size = 0; 100 break; 101 case LV_IMG_CF_TRUE_COLOR: 102 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: 103 px_size = LV_COLOR_SIZE; 104 break; 105 case LV_IMG_CF_TRUE_COLOR_ALPHA: 106 px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3; 107 break; 108 case LV_IMG_CF_INDEXED_1BIT: 109 case LV_IMG_CF_ALPHA_1BIT: 110 px_size = 1; 111 break; 112 case LV_IMG_CF_INDEXED_2BIT: 113 case LV_IMG_CF_ALPHA_2BIT: 114 px_size = 2; 115 break; 116 case LV_IMG_CF_INDEXED_4BIT: 117 case LV_IMG_CF_ALPHA_4BIT: 118 px_size = 4; 119 break; 120 case LV_IMG_CF_INDEXED_8BIT: 121 case LV_IMG_CF_ALPHA_8BIT: 122 px_size = 8; 123 break; 124 default: 125 px_size = 0; 126 break; 127 } 128 129 return px_size; 130 } 131 132 /** 133 * Check if a color format is chroma keyed or not 134 * @param cf a color format (`LV_IMG_CF_...`) 135 * @return true: chroma keyed; false: not chroma keyed 136 */ 137 bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf) 138 { 139 bool is_chroma_keyed = false; 140 141 switch(cf) { 142 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: 143 case LV_IMG_CF_RAW_CHROMA_KEYED: 144 is_chroma_keyed = true; 145 break; 146 147 default: 148 is_chroma_keyed = false; 149 break; 150 } 151 152 return is_chroma_keyed; 153 } 154 155 /** 156 * Check if a color format has alpha channel or not 157 * @param cf a color format (`LV_IMG_CF_...`) 158 * @return true: has alpha channel; false: doesn't have alpha channel 159 */ 160 bool lv_img_cf_has_alpha(lv_img_cf_t cf) 161 { 162 bool has_alpha = false; 163 164 switch(cf) { 165 case LV_IMG_CF_TRUE_COLOR_ALPHA: 166 case LV_IMG_CF_RAW_ALPHA: 167 case LV_IMG_CF_INDEXED_1BIT: 168 case LV_IMG_CF_INDEXED_2BIT: 169 case LV_IMG_CF_INDEXED_4BIT: 170 case LV_IMG_CF_INDEXED_8BIT: 171 case LV_IMG_CF_ALPHA_1BIT: 172 case LV_IMG_CF_ALPHA_2BIT: 173 case LV_IMG_CF_ALPHA_4BIT: 174 case LV_IMG_CF_ALPHA_8BIT: 175 has_alpha = true; 176 break; 177 default: 178 has_alpha = false; 179 break; 180 } 181 182 return has_alpha; 183 } 184 185 /** 186 * Get the type of an image source 187 * @param src pointer to an image source: 188 * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) 189 * - a path to a file (e.g. "S:/folder/image.bin") 190 * - or a symbol (e.g. LV_SYMBOL_CLOSE) 191 * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN 192 */ 193 lv_img_src_t lv_img_src_get_type(const void * src) 194 { 195 lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN; 196 197 if(src == NULL) return img_src_type; 198 const uint8_t * u8_p = src; 199 200 /*The first byte shows the type of the image source*/ 201 if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) { 202 img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/ 203 } 204 else if(u8_p[0] >= 0x80) { 205 img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/ 206 } 207 else { 208 img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is draw to the first byte < 0x20*/ 209 } 210 211 if(LV_IMG_SRC_UNKNOWN == img_src_type) { 212 LV_LOG_WARN("lv_img_src_get_type: unknown image type"); 213 } 214 215 return img_src_type; 216 } 217 218 void lv_draw_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, 219 const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format) 220 { 221 if(draw_ctx->draw_img_decoded == NULL) return; 222 223 draw_ctx->draw_img_decoded(draw_ctx, dsc, coords, map_p, color_format); 224 } 225 226 /********************** 227 * STATIC FUNCTIONS 228 **********************/ 229 230 LV_ATTRIBUTE_FAST_MEM static lv_res_t decode_and_draw(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, 231 const lv_area_t * coords, const void * src) 232 { 233 if(draw_dsc->opa <= LV_OPA_MIN) return LV_RES_OK; 234 235 _lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id); 236 237 if(cdsc == NULL) return LV_RES_INV; 238 239 240 lv_img_cf_t cf; 241 if(lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; 242 else if(lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; 243 else cf = LV_IMG_CF_TRUE_COLOR; 244 245 if(cdsc->dec_dsc.error_msg != NULL) { 246 LV_LOG_WARN("Image draw error"); 247 248 show_error(draw_ctx, coords, cdsc->dec_dsc.error_msg); 249 } 250 /*The decoder could open the image and gave the entire uncompressed image. 251 *Just draw it!*/ 252 else if(cdsc->dec_dsc.img_data) { 253 lv_area_t map_area_rot; 254 lv_area_copy(&map_area_rot, coords); 255 if(draw_dsc->angle || draw_dsc->zoom != LV_IMG_ZOOM_NONE) { 256 int32_t w = lv_area_get_width(coords); 257 int32_t h = lv_area_get_height(coords); 258 259 _lv_img_buf_get_transformed_area(&map_area_rot, w, h, draw_dsc->angle, draw_dsc->zoom, &draw_dsc->pivot); 260 261 map_area_rot.x1 += coords->x1; 262 map_area_rot.y1 += coords->y1; 263 map_area_rot.x2 += coords->x1; 264 map_area_rot.y2 += coords->y1; 265 } 266 267 lv_area_t clip_com; /*Common area of mask and coords*/ 268 bool union_ok; 269 union_ok = _lv_area_intersect(&clip_com, draw_ctx->clip_area, &map_area_rot); 270 /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ 271 if(union_ok == false) { 272 draw_cleanup(cdsc); 273 return LV_RES_OK; 274 } 275 276 const lv_area_t * clip_area_ori = draw_ctx->clip_area; 277 draw_ctx->clip_area = &clip_com; 278 lv_draw_img_decoded(draw_ctx, draw_dsc, coords, cdsc->dec_dsc.img_data, cf); 279 draw_ctx->clip_area = clip_area_ori; 280 } 281 /*The whole uncompressed image is not available. Try to read it line-by-line*/ 282 else { 283 lv_area_t mask_com; /*Common area of mask and coords*/ 284 bool union_ok; 285 union_ok = _lv_area_intersect(&mask_com, draw_ctx->clip_area, coords); 286 /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ 287 if(union_ok == false) { 288 draw_cleanup(cdsc); 289 return LV_RES_OK; 290 } 291 292 int32_t width = lv_area_get_width(&mask_com); 293 294 uint8_t * buf = lv_mem_buf_get(lv_area_get_width(&mask_com) * 295 LV_IMG_PX_SIZE_ALPHA_BYTE); /*+1 because of the possible alpha byte*/ 296 297 const lv_area_t * clip_area_ori = draw_ctx->clip_area; 298 lv_area_t line; 299 lv_area_copy(&line, &mask_com); 300 lv_area_set_height(&line, 1); 301 int32_t x = mask_com.x1 - coords->x1; 302 int32_t y = mask_com.y1 - coords->y1; 303 int32_t row; 304 lv_res_t read_res; 305 for(row = mask_com.y1; row <= mask_com.y2; row++) { 306 lv_area_t mask_line; 307 union_ok = _lv_area_intersect(&mask_line, clip_area_ori, &line); 308 if(union_ok == false) continue; 309 310 read_res = lv_img_decoder_read_line(&cdsc->dec_dsc, x, y, width, buf); 311 if(read_res != LV_RES_OK) { 312 lv_img_decoder_close(&cdsc->dec_dsc); 313 LV_LOG_WARN("Image draw can't read the line"); 314 lv_mem_buf_release(buf); 315 draw_cleanup(cdsc); 316 draw_ctx->clip_area = clip_area_ori; 317 return LV_RES_INV; 318 } 319 320 draw_ctx->clip_area = &mask_line; 321 lv_draw_img_decoded(draw_ctx, draw_dsc, &line, buf, cf); 322 line.y1++; 323 line.y2++; 324 y++; 325 } 326 draw_ctx->clip_area = clip_area_ori; 327 lv_mem_buf_release(buf); 328 } 329 330 draw_cleanup(cdsc); 331 return LV_RES_OK; 332 } 333 334 335 static void show_error(lv_draw_ctx_t * draw_ctx, const lv_area_t * coords, const char * msg) 336 { 337 lv_draw_rect_dsc_t rect_dsc; 338 lv_draw_rect_dsc_init(&rect_dsc); 339 rect_dsc.bg_color = lv_color_white(); 340 lv_draw_rect(draw_ctx, &rect_dsc, coords); 341 342 lv_draw_label_dsc_t label_dsc; 343 lv_draw_label_dsc_init(&label_dsc); 344 lv_draw_label(draw_ctx, &label_dsc, coords, msg, NULL); 345 } 346 347 static void draw_cleanup(_lv_img_cache_entry_t * cache) 348 { 349 /*Automatically close images with no caching*/ 350 #if LV_IMG_CACHE_DEF_SIZE == 0 351 lv_img_decoder_close(&cache->dec_dsc); 352 #else 353 LV_UNUSED(cache); 354 #endif 355 }