1 /**
2  * @file lv_img.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_img.h"
10 #if LV_USE_IMG != 0
11 
12 #include "../misc/lv_assert.h"
13 #include "../draw/lv_img_decoder.h"
14 #include "../misc/lv_fs.h"
15 #include "../misc/lv_txt.h"
16 #include "../misc/lv_math.h"
17 #include "../misc/lv_log.h"
18 
19 /*********************
20  *      DEFINES
21  *********************/
22 #define MY_CLASS &lv_img_class
23 
24 /**********************
25  *      TYPEDEFS
26  **********************/
27 
28 /**********************
29  *  STATIC PROTOTYPES
30  **********************/
31 static void lv_img_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
32 static void lv_img_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
33 static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e);
34 static void draw_img(lv_event_t * e);
35 
36 /**********************
37  *  STATIC VARIABLES
38  **********************/
39 const lv_obj_class_t lv_img_class = {
40     .constructor_cb = lv_img_constructor,
41     .destructor_cb = lv_img_destructor,
42     .event_cb = lv_img_event,
43     .width_def = LV_SIZE_CONTENT,
44     .height_def = LV_SIZE_CONTENT,
45     .instance_size = sizeof(lv_img_t),
46     .base_class = &lv_obj_class
47 };
48 
49 /**********************
50  *      MACROS
51  **********************/
52 
53 /**********************
54  *   GLOBAL FUNCTIONS
55  **********************/
56 
lv_img_create(lv_obj_t * parent)57 lv_obj_t * lv_img_create(lv_obj_t * parent)
58 {
59     LV_LOG_INFO("begin");
60     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
61     lv_obj_class_init_obj(obj);
62     return obj;
63 }
64 
65 /*=====================
66  * Setter functions
67  *====================*/
68 
lv_img_set_src(lv_obj_t * obj,const void * src)69 void lv_img_set_src(lv_obj_t * obj, const void * src)
70 {
71     LV_ASSERT_OBJ(obj, MY_CLASS);
72 
73     lv_obj_invalidate(obj);
74 
75     lv_img_src_t src_type = lv_img_src_get_type(src);
76     lv_img_t * img = (lv_img_t *)obj;
77 
78 #if LV_USE_LOG && LV_LOG_LEVEL >= LV_LOG_LEVEL_INFO
79     switch(src_type) {
80         case LV_IMG_SRC_FILE:
81             LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_FILE` type found");
82             break;
83         case LV_IMG_SRC_VARIABLE:
84             LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found");
85             break;
86         case LV_IMG_SRC_SYMBOL:
87             LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_SYMBOL` type found");
88             break;
89         default:
90             LV_LOG_WARN("lv_img_set_src: unknown type");
91     }
92 #endif
93 
94     /*If the new source type is unknown free the memories of the old source*/
95     if(src_type == LV_IMG_SRC_UNKNOWN) {
96         LV_LOG_WARN("lv_img_set_src: unknown image type");
97         if(img->src_type == LV_IMG_SRC_SYMBOL || img->src_type == LV_IMG_SRC_FILE) {
98             lv_mem_free((void *)img->src);
99         }
100         img->src      = NULL;
101         img->src_type = LV_IMG_SRC_UNKNOWN;
102         return;
103     }
104 
105     lv_img_header_t header;
106     lv_img_decoder_get_info(src, &header);
107 
108     /*Save the source*/
109     if(src_type == LV_IMG_SRC_VARIABLE) {
110         /*If memory was allocated because of the previous `src_type` then free it*/
111         if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
112             lv_mem_free((void *)img->src);
113         }
114         img->src = src;
115     }
116     else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) {
117         /*If the new and the old src are the same then it was only a refresh.*/
118         if(img->src != src) {
119             const void * old_src = NULL;
120             /*If memory was allocated because of the previous `src_type` then save its pointer and free after allocation.
121              *It's important to allocate first to be sure the new data will be on a new address.
122              *Else `img_cache` wouldn't see the change in source.*/
123             if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
124                 old_src = img->src;
125             }
126             char * new_str = lv_mem_alloc(strlen(src) + 1);
127             LV_ASSERT_MALLOC(new_str);
128             if(new_str == NULL) return;
129             strcpy(new_str, src);
130             img->src = new_str;
131 
132             if(old_src) lv_mem_free((void *)old_src);
133         }
134     }
135 
136     if(src_type == LV_IMG_SRC_SYMBOL) {
137         /*`lv_img_dsc_get_info` couldn't set the with and height of a font so set it here*/
138         const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
139         lv_coord_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
140         lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
141         lv_point_t size;
142         lv_txt_get_size(&size, src, font, letter_space, line_space, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
143         header.w = size.x;
144         header.h = size.y;
145     }
146 
147     img->src_type = src_type;
148     img->w        = header.w;
149     img->h        = header.h;
150     img->cf       = header.cf;
151     img->pivot.x = header.w / 2;
152     img->pivot.y = header.h / 2;
153 
154     lv_obj_refresh_self_size(obj);
155 
156     /*Provide enough room for the rotated corners*/
157     if(img->angle || img->zoom != LV_IMG_ZOOM_NONE) lv_obj_refresh_ext_draw_size(obj);
158 
159     lv_obj_invalidate(obj);
160 }
161 
lv_img_set_offset_x(lv_obj_t * obj,lv_coord_t x)162 void lv_img_set_offset_x(lv_obj_t * obj, lv_coord_t x)
163 {
164     LV_ASSERT_OBJ(obj, MY_CLASS);
165 
166     lv_img_t * img = (lv_img_t *)obj;
167 
168     x = x % img->w;
169 
170     img->offset.x = x;
171     lv_obj_invalidate(obj);
172 }
173 
lv_img_set_offset_y(lv_obj_t * obj,lv_coord_t y)174 void lv_img_set_offset_y(lv_obj_t * obj, lv_coord_t y)
175 {
176     LV_ASSERT_OBJ(obj, MY_CLASS);
177 
178     lv_img_t * img = (lv_img_t *)obj;
179 
180     y = y % img->h;
181 
182     img->offset.y = y;
183     lv_obj_invalidate(obj);
184 }
185 
lv_img_set_angle(lv_obj_t * obj,int16_t angle)186 void lv_img_set_angle(lv_obj_t * obj, int16_t angle)
187 {
188     if(angle < 0 || angle >= 3600) angle = angle % 3600;
189 
190     lv_img_t * img = (lv_img_t *)obj;
191     if(angle == img->angle) return;
192 
193     lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
194     transf_zoom = ((int32_t)transf_zoom * img->zoom) >> 8;
195 
196     lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
197 
198     lv_obj_update_layout(obj);  /*Be sure the object's size is calculated*/
199     lv_coord_t w = lv_obj_get_width(obj);
200     lv_coord_t h = lv_obj_get_height(obj);
201     lv_area_t a;
202     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle + img->angle, transf_zoom, &img->pivot);
203     a.x1 += obj->coords.x1;
204     a.y1 += obj->coords.y1;
205     a.x2 += obj->coords.x1;
206     a.y2 += obj->coords.y1;
207     lv_obj_invalidate_area(obj, &a);
208 
209     img->angle = angle;
210     lv_obj_refresh_ext_draw_size(obj);
211 
212     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle + img->angle, transf_zoom, &img->pivot);
213     a.x1 += obj->coords.x1;
214     a.y1 += obj->coords.y1;
215     a.x2 += obj->coords.x1;
216     a.y2 += obj->coords.y1;
217     lv_obj_invalidate_area(obj, &a);
218 }
219 
lv_img_set_pivot(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)220 void lv_img_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
221 {
222     lv_img_t * img = (lv_img_t *)obj;
223     if(img->pivot.x == x && img->pivot.y == y) return;
224 
225     lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
226     transf_zoom = ((int32_t)transf_zoom * img->zoom) >> 8;
227 
228     lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
229     transf_angle += img->angle;
230 
231     lv_obj_update_layout(obj);  /*Be sure the object's size is calculated*/
232     lv_coord_t w = lv_obj_get_width(obj);
233     lv_coord_t h = lv_obj_get_height(obj);
234     lv_area_t a;
235     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &img->pivot);
236     a.x1 += obj->coords.x1;
237     a.y1 += obj->coords.y1;
238     a.x2 += obj->coords.x1;
239     a.y2 += obj->coords.y1;
240     lv_obj_invalidate_area(obj, &a);
241 
242     img->pivot.x = x;
243     img->pivot.y = y;
244     lv_obj_refresh_ext_draw_size(obj);
245 
246     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &img->pivot);
247     a.x1 += obj->coords.x1;
248     a.y1 += obj->coords.y1;
249     a.x2 += obj->coords.x1;
250     a.y2 += obj->coords.y1;
251     lv_obj_invalidate_area(obj, &a);
252 }
253 
lv_img_set_zoom(lv_obj_t * obj,uint16_t zoom)254 void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom)
255 {
256     lv_img_t * img = (lv_img_t *)obj;
257     if(zoom == img->zoom) return;
258 
259     if(zoom == 0) zoom = 1;
260 
261     lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
262 
263     lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
264     transf_angle += img->angle;
265 
266     lv_obj_update_layout(obj);  /*Be sure the object's size is calculated*/
267     lv_coord_t w = lv_obj_get_width(obj);
268     lv_coord_t h = lv_obj_get_height(obj);
269     lv_area_t a;
270     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, ((int32_t)transf_zoom * img->zoom) >> 8, &img->pivot);
271     a.x1 += obj->coords.x1 - 1;
272     a.y1 += obj->coords.y1 - 1;
273     a.x2 += obj->coords.x1 + 1;
274     a.y2 += obj->coords.y1 + 1;
275     lv_obj_invalidate_area(obj, &a);
276 
277     img->zoom = zoom;
278     lv_obj_refresh_ext_draw_size(obj);
279 
280     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, ((int32_t)transf_zoom * img->zoom) >> 8, &img->pivot);
281     a.x1 += obj->coords.x1 - 1;
282     a.y1 += obj->coords.y1 - 1;
283     a.x2 += obj->coords.x1 + 1;
284     a.y2 += obj->coords.y1 + 1;
285     lv_obj_invalidate_area(obj, &a);
286 }
287 
lv_img_set_antialias(lv_obj_t * obj,bool antialias)288 void lv_img_set_antialias(lv_obj_t * obj, bool antialias)
289 {
290     lv_img_t * img = (lv_img_t *)obj;
291     if(antialias == img->antialias) return;
292 
293     img->antialias = antialias;
294     lv_obj_invalidate(obj);
295 }
296 
lv_img_set_size_mode(lv_obj_t * obj,lv_img_size_mode_t mode)297 void lv_img_set_size_mode(lv_obj_t * obj, lv_img_size_mode_t mode)
298 {
299     LV_ASSERT_OBJ(obj, MY_CLASS);
300     lv_img_t * img = (lv_img_t *)obj;
301     if(mode == img->obj_size_mode) return;
302 
303     img->obj_size_mode = mode;
304     lv_obj_invalidate(obj);
305 }
306 
307 /*=====================
308  * Getter functions
309  *====================*/
310 
lv_img_get_src(lv_obj_t * obj)311 const void * lv_img_get_src(lv_obj_t * obj)
312 {
313     LV_ASSERT_OBJ(obj, MY_CLASS);
314 
315     lv_img_t * img = (lv_img_t *)obj;
316 
317     return img->src;
318 }
319 
lv_img_get_offset_x(lv_obj_t * obj)320 lv_coord_t lv_img_get_offset_x(lv_obj_t * obj)
321 {
322     LV_ASSERT_OBJ(obj, MY_CLASS);
323 
324     lv_img_t * img = (lv_img_t *)obj;
325 
326     return img->offset.x;
327 }
328 
lv_img_get_offset_y(lv_obj_t * obj)329 lv_coord_t lv_img_get_offset_y(lv_obj_t * obj)
330 {
331     LV_ASSERT_OBJ(obj, MY_CLASS);
332 
333     lv_img_t * img = (lv_img_t *)obj;
334 
335     return img->offset.y;
336 }
337 
lv_img_get_angle(lv_obj_t * obj)338 uint16_t lv_img_get_angle(lv_obj_t * obj)
339 {
340     LV_ASSERT_OBJ(obj, MY_CLASS);
341 
342     lv_img_t * img = (lv_img_t *)obj;
343 
344     return img->angle;
345 }
346 
lv_img_get_pivot(lv_obj_t * obj,lv_point_t * pivot)347 void lv_img_get_pivot(lv_obj_t * obj, lv_point_t * pivot)
348 {
349     LV_ASSERT_OBJ(obj, MY_CLASS);
350 
351     lv_img_t * img = (lv_img_t *)obj;
352 
353     *pivot = img->pivot;
354 }
355 
lv_img_get_zoom(lv_obj_t * obj)356 uint16_t lv_img_get_zoom(lv_obj_t * obj)
357 {
358     LV_ASSERT_OBJ(obj, MY_CLASS);
359 
360     lv_img_t * img = (lv_img_t *)obj;
361 
362     return img->zoom;
363 }
364 
lv_img_get_antialias(lv_obj_t * obj)365 bool lv_img_get_antialias(lv_obj_t * obj)
366 {
367     LV_ASSERT_OBJ(obj, MY_CLASS);
368 
369     lv_img_t * img = (lv_img_t *)obj;
370 
371     return img->antialias ? true : false;
372 }
373 
lv_img_get_size_mode(lv_obj_t * obj)374 lv_img_size_mode_t lv_img_get_size_mode(lv_obj_t * obj)
375 {
376     LV_ASSERT_OBJ(obj, MY_CLASS);
377     lv_img_t * img = (lv_img_t *)obj;
378     return img->obj_size_mode;
379 }
380 
381 /**********************
382  *   STATIC FUNCTIONS
383  **********************/
384 
lv_img_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)385 static void lv_img_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
386 {
387     LV_UNUSED(class_p);
388     LV_TRACE_OBJ_CREATE("begin");
389 
390     lv_img_t * img = (lv_img_t *)obj;
391 
392     img->src       = NULL;
393     img->src_type  = LV_IMG_SRC_UNKNOWN;
394     img->cf        = LV_IMG_CF_UNKNOWN;
395     img->w         = lv_obj_get_width(obj);
396     img->h         = lv_obj_get_height(obj);
397     img->angle = 0;
398     img->zoom = LV_IMG_ZOOM_NONE;
399     img->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
400     img->offset.x  = 0;
401     img->offset.y  = 0;
402     img->pivot.x = 0;
403     img->pivot.y = 0;
404     img->obj_size_mode = LV_IMG_SIZE_MODE_VIRTUAL;
405 
406     lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE);
407     lv_obj_add_flag(obj, LV_OBJ_FLAG_ADV_HITTEST);
408 
409     LV_TRACE_OBJ_CREATE("finished");
410 }
411 
lv_img_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)412 static void lv_img_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
413 {
414     LV_UNUSED(class_p);
415     lv_img_t * img = (lv_img_t *)obj;
416     if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
417         lv_mem_free((void *)img->src);
418         img->src      = NULL;
419         img->src_type = LV_IMG_SRC_UNKNOWN;
420     }
421 }
422 
lv_img_get_transformed_size(lv_obj_t * obj)423 static lv_point_t lv_img_get_transformed_size(lv_obj_t * obj)
424 {
425     lv_img_t * img = (lv_img_t *)obj;
426 
427     int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
428     zoom_final = (zoom_final * img->zoom) >> 8;
429     int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
430     angle_final += img->angle;
431 
432     lv_area_t area_transform;
433     _lv_img_buf_get_transformed_area(&area_transform, img->w, img->h,
434                                      angle_final, zoom_final, &img->pivot);
435 
436     return (lv_point_t) {
437         lv_area_get_width(&area_transform), lv_area_get_height(&area_transform)
438     };
439 }
440 
lv_img_event(const lv_obj_class_t * class_p,lv_event_t * e)441 static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e)
442 {
443     LV_UNUSED(class_p);
444 
445     lv_event_code_t code = lv_event_get_code(e);
446 
447     /*Ancestor events will be called during drawing*/
448     if(code != LV_EVENT_DRAW_MAIN && code != LV_EVENT_DRAW_POST) {
449         /*Call the ancestor's event handler*/
450         lv_res_t res = lv_obj_event_base(MY_CLASS, e);
451         if(res != LV_RES_OK) return;
452     }
453 
454     lv_obj_t * obj = lv_event_get_target(e);
455     lv_img_t * img = (lv_img_t *)obj;
456 
457     if(code == LV_EVENT_STYLE_CHANGED) {
458         /*Refresh the file name to refresh the symbol text size*/
459         if(img->src_type == LV_IMG_SRC_SYMBOL) {
460             lv_img_set_src(obj, img->src);
461         }
462         else {
463             /*With transformation it might change*/
464             lv_obj_refresh_ext_draw_size(obj);
465         }
466     }
467     else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
468 
469         lv_coord_t * s = lv_event_get_param(e);
470         lv_coord_t transf_zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
471         transf_zoom = ((int32_t)transf_zoom * img->zoom) >> 8;
472 
473         lv_coord_t transf_angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
474         transf_angle += img->angle;
475 
476         /*If the image has angle provide enough room for the rotated corners*/
477         if(transf_angle || transf_zoom != LV_IMG_ZOOM_NONE) {
478             lv_area_t a;
479             lv_coord_t w = lv_obj_get_width(obj);
480             lv_coord_t h = lv_obj_get_height(obj);
481             _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &img->pivot);
482             lv_coord_t pad_ori = *s;
483             *s = LV_MAX(*s, pad_ori - a.x1);
484             *s = LV_MAX(*s, pad_ori - a.y1);
485             *s = LV_MAX(*s, pad_ori + a.x2 - w);
486             *s = LV_MAX(*s, pad_ori + a.y2 - h);
487         }
488     }
489     else if(code == LV_EVENT_HIT_TEST) {
490         lv_hit_test_info_t * info = lv_event_get_param(e);
491         lv_coord_t zoom = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
492         zoom = (zoom * img->zoom) >> 8;
493 
494         lv_coord_t angle = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
495         angle += img->angle;
496 
497         /*If the object is exactly image sized (not cropped, not mosaic) and transformed
498          *perform hit test on its transformed area*/
499         if(img->w == lv_obj_get_width(obj) && img->h == lv_obj_get_height(obj) &&
500            (zoom != LV_IMG_ZOOM_NONE || angle != 0 || img->pivot.x != img->w / 2 || img->pivot.y != img->h / 2)) {
501 
502             lv_coord_t w = lv_obj_get_width(obj);
503             lv_coord_t h = lv_obj_get_height(obj);
504             lv_area_t coords;
505             _lv_img_buf_get_transformed_area(&coords, w, h, angle, zoom, &img->pivot);
506             coords.x1 += obj->coords.x1;
507             coords.y1 += obj->coords.y1;
508             coords.x2 += obj->coords.x1;
509             coords.y2 += obj->coords.y1;
510 
511             info->res = _lv_area_is_point_on(&coords, info->point, 0);
512         }
513         else {
514             lv_area_t a;
515             lv_obj_get_click_area(obj, &a);
516             info->res = _lv_area_is_point_on(&a, info->point, 0);
517         }
518     }
519     else if(code == LV_EVENT_GET_SELF_SIZE) {
520         lv_point_t * p = lv_event_get_param(e);
521         if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
522             *p = lv_img_get_transformed_size(obj);
523         }
524         else {
525             p->x = img->w;
526             p->y = img->h;
527         }
528     }
529     else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) {
530         draw_img(e);
531     }
532 }
533 
draw_img(lv_event_t * e)534 static void draw_img(lv_event_t * e)
535 {
536     lv_event_code_t code = lv_event_get_code(e);
537     lv_obj_t * obj = lv_event_get_target(e);
538     lv_img_t * img = (lv_img_t *)obj;
539     if(code == LV_EVENT_COVER_CHECK) {
540         lv_cover_check_info_t * info = lv_event_get_param(e);
541         if(info->res == LV_COVER_RES_MASKED) return;
542         if(img->src_type == LV_IMG_SRC_UNKNOWN || img->src_type == LV_IMG_SRC_SYMBOL) {
543             info->res = LV_COVER_RES_NOT_COVER;
544             return;
545         }
546 
547         /*Non true color format might have "holes"*/
548         if(img->cf != LV_IMG_CF_TRUE_COLOR && img->cf != LV_IMG_CF_RAW) {
549             info->res = LV_COVER_RES_NOT_COVER;
550             return;
551         }
552 
553         /*With not LV_OPA_COVER images can't cover an area */
554         if(lv_obj_get_style_img_opa(obj, LV_PART_MAIN) != LV_OPA_COVER) {
555             info->res = LV_COVER_RES_NOT_COVER;
556             return;
557         }
558 
559         int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
560         angle_final += img->angle;
561 
562         if(angle_final != 0) {
563             info->res = LV_COVER_RES_NOT_COVER;
564             return;
565         }
566 
567         int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
568         zoom_final = (zoom_final * img->zoom) >> 8;
569 
570         const lv_area_t * clip_area = lv_event_get_param(e);
571         if(zoom_final == LV_IMG_ZOOM_NONE) {
572             if(_lv_area_is_in(clip_area, &obj->coords, 0) == false) {
573                 info->res = LV_COVER_RES_NOT_COVER;
574                 return;
575             }
576         }
577         else {
578             lv_area_t a;
579             _lv_img_buf_get_transformed_area(&a, lv_obj_get_width(obj), lv_obj_get_height(obj), 0, zoom_final, &img->pivot);
580             a.x1 += obj->coords.x1;
581             a.y1 += obj->coords.y1;
582             a.x2 += obj->coords.x1;
583             a.y2 += obj->coords.y1;
584 
585             if(_lv_area_is_in(clip_area, &a, 0) == false) {
586                 info->res = LV_COVER_RES_NOT_COVER;
587                 return;
588             }
589         }
590     }
591     else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST) {
592 
593         int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
594         zoom_final = (zoom_final * img->zoom) >> 8;
595 
596         int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
597         angle_final += img->angle;
598 
599         lv_coord_t obj_w = lv_obj_get_width(obj);
600         lv_coord_t obj_h = lv_obj_get_height(obj);
601 
602         lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
603         lv_coord_t pleft = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width;
604         lv_coord_t pright = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width;
605         lv_coord_t ptop = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width;
606         lv_coord_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width;
607 
608         lv_point_t bg_pivot;
609         bg_pivot.x = img->pivot.x + pleft;
610         bg_pivot.y = img->pivot.y + ptop;
611         lv_area_t bg_coords;
612 
613         if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
614             /*Object size equals to transformed image size*/
615             lv_obj_get_coords(obj, &bg_coords);
616         }
617         else {
618             _lv_img_buf_get_transformed_area(&bg_coords, obj_w, obj_h,
619                                              angle_final, zoom_final, &bg_pivot);
620 
621             /*Modify the coordinates to draw the background for the rotated and scaled coordinates*/
622             bg_coords.x1 += obj->coords.x1;
623             bg_coords.y1 += obj->coords.y1;
624             bg_coords.x2 += obj->coords.x1;
625             bg_coords.y2 += obj->coords.y1;
626         }
627 
628         lv_area_t ori_coords;
629         lv_area_copy(&ori_coords, &obj->coords);
630         lv_area_copy(&obj->coords, &bg_coords);
631 
632         lv_res_t res = lv_obj_event_base(MY_CLASS, e);
633         if(res != LV_RES_OK) return;
634 
635         lv_area_copy(&obj->coords, &ori_coords);
636 
637         if(code == LV_EVENT_DRAW_MAIN) {
638             if(img->h == 0 || img->w == 0) return;
639             if(zoom_final == 0) return;
640 
641             lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
642 
643             lv_area_t img_max_area;
644             lv_area_copy(&img_max_area, &obj->coords);
645 
646             lv_point_t img_size_final = lv_img_get_transformed_size(obj);
647 
648             if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
649                 img_max_area.x1 -= ((img->w - img_size_final.x) + 1) / 2;
650                 img_max_area.x2 -= ((img->w - img_size_final.x) + 1) / 2;
651                 img_max_area.y1 -= ((img->h - img_size_final.y) + 1) / 2;
652                 img_max_area.y2 -= ((img->h - img_size_final.y) + 1) / 2;
653             }
654             else {
655                 img_max_area.x2 = img_max_area.x1 + lv_area_get_width(&bg_coords) - 1;
656                 img_max_area.y2 = img_max_area.y1 + lv_area_get_height(&bg_coords) - 1;
657             }
658 
659             img_max_area.x1 += pleft;
660             img_max_area.y1 += ptop;
661             img_max_area.x2 -= pright;
662             img_max_area.y2 -= pbottom;
663 
664             if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_VARIABLE) {
665                 lv_draw_img_dsc_t img_dsc;
666                 lv_draw_img_dsc_init(&img_dsc);
667                 lv_obj_init_draw_img_dsc(obj, LV_PART_MAIN, &img_dsc);
668 
669                 img_dsc.zoom = zoom_final;
670                 img_dsc.angle = angle_final;
671                 img_dsc.pivot.x = img->pivot.x;
672                 img_dsc.pivot.y = img->pivot.y;
673                 img_dsc.antialias = img->antialias;
674 
675                 lv_area_t img_clip_area;
676                 img_clip_area.x1 = bg_coords.x1 + pleft;
677                 img_clip_area.y1 = bg_coords.y1 + ptop;
678                 img_clip_area.x2 = bg_coords.x2 - pright;
679                 img_clip_area.y2 = bg_coords.y2 - pbottom;
680                 const lv_area_t * clip_area_ori = draw_ctx->clip_area;
681 
682                 if(!_lv_area_intersect(&img_clip_area, draw_ctx->clip_area, &img_clip_area)) return;
683                 draw_ctx->clip_area = &img_clip_area;
684 
685                 lv_area_t coords_tmp;
686                 coords_tmp.y1 = img_max_area.y1 + img->offset.y;
687                 if(coords_tmp.y1 > img_max_area.y1) coords_tmp.y1 -= img->h;
688                 coords_tmp.y2 = coords_tmp.y1 + img->h - 1;
689 
690                 for(; coords_tmp.y1 < img_max_area.y2; coords_tmp.y1 += img_size_final.y, coords_tmp.y2 += img_size_final.y) {
691                     coords_tmp.x1 = img_max_area.x1 + img->offset.x;
692                     if(coords_tmp.x1 > img_max_area.x1) coords_tmp.x1 -= img->w;
693                     coords_tmp.x2 = coords_tmp.x1 + img->w - 1;
694 
695                     for(; coords_tmp.x1 < img_max_area.x2; coords_tmp.x1 += img_size_final.x, coords_tmp.x2 += img_size_final.x) {
696                         lv_draw_img(draw_ctx, &img_dsc, &coords_tmp, img->src);
697                     }
698                 }
699                 draw_ctx->clip_area = clip_area_ori;
700             }
701             else if(img->src_type == LV_IMG_SRC_SYMBOL) {
702                 lv_draw_label_dsc_t label_dsc;
703                 lv_draw_label_dsc_init(&label_dsc);
704                 lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_dsc);
705 
706                 lv_draw_label(draw_ctx, &label_dsc, &obj->coords, img->src, NULL);
707             }
708             else {
709                 /*Trigger the error handler of image draw*/
710                 LV_LOG_WARN("draw_img: image source type is unknown");
711                 lv_draw_img(draw_ctx, NULL, &obj->coords, NULL);
712             }
713         }
714     }
715 }
716 
717 #endif
718