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 /*Testing of dependencies*/
13 #if LV_USE_LABEL == 0
14     #error "lv_img: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL  1) "
15 #endif
16 
17 #include "../lv_misc/lv_debug.h"
18 #include "../lv_themes/lv_theme.h"
19 #include "../lv_draw/lv_img_decoder.h"
20 #include "../lv_misc/lv_fs.h"
21 #include "../lv_misc/lv_txt.h"
22 #include "../lv_misc/lv_math.h"
23 #include "../lv_misc/lv_log.h"
24 
25 /*********************
26  *      DEFINES
27  *********************/
28 #define LV_OBJX_NAME "lv_img"
29 
30 /**********************
31  *      TYPEDEFS
32  **********************/
33 
34 /**********************
35  *  STATIC PROTOTYPES
36  **********************/
37 static lv_design_res_t lv_img_design(lv_obj_t * img, const lv_area_t * clip_area, lv_design_mode_t mode);
38 static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param);
39 static lv_style_list_t * lv_img_get_style(lv_obj_t * img, uint8_t type);
40 
41 /**********************
42  *  STATIC VARIABLES
43  **********************/
44 static lv_signal_cb_t ancestor_signal;
45 
46 /**********************
47  *      MACROS
48  **********************/
49 
50 /**********************
51  *   GLOBAL FUNCTIONS
52  **********************/
53 
54 /**
55  * Create an image objects
56  * @param par pointer to an object, it will be the parent of the new button
57  * @param copy pointer to a image object, if not NULL then the new object will be copied from it
58  * @return pointer to the created image
59  */
lv_img_create(lv_obj_t * par,const lv_obj_t * copy)60 lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy)
61 {
62     LV_LOG_TRACE("image create started");
63 
64     /*Create a basic object*/
65     lv_obj_t * img = lv_obj_create(par, copy);
66     LV_ASSERT_MEM(img);
67     if(img == NULL) return NULL;
68 
69     if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(img);
70 
71     /*Extend the basic object to image object*/
72     lv_img_ext_t * ext = lv_obj_allocate_ext_attr(img, sizeof(lv_img_ext_t));
73     LV_ASSERT_MEM(ext);
74     if(ext == NULL) {
75         lv_obj_del(img);
76         return NULL;
77     }
78 
79     ext->src       = NULL;
80     ext->src_type  = LV_IMG_SRC_UNKNOWN;
81     ext->cf        = LV_IMG_CF_UNKNOWN;
82     ext->w         = lv_obj_get_width(img);
83     ext->h         = lv_obj_get_height(img);
84     ext->angle = 0;
85     ext->zoom = LV_IMG_ZOOM_NONE;
86     ext->antialias = LV_ANTIALIAS ? 1 : 0;
87     ext->auto_size = 1;
88     ext->offset.x  = 0;
89     ext->offset.y  = 0;
90     ext->pivot.x = 0;
91     ext->pivot.y = 0;
92 
93     /*Init the new object*/
94     lv_obj_set_signal_cb(img, lv_img_signal);
95     lv_obj_set_design_cb(img, lv_img_design);
96 
97     if(copy == NULL) {
98         lv_theme_apply(img, LV_THEME_IMAGE);
99         lv_obj_set_click(img, false);
100         lv_obj_set_adv_hittest(img, true); /*Images have fast hit-testing*/
101         /* Enable auto size for non screens
102          * because image screens are wallpapers
103          * and must be screen sized*/
104         if(par != NULL) {
105             ext->auto_size = 1;
106         }
107         else {
108             ext->auto_size = 0;
109         }
110     }
111     else {
112         lv_img_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
113         ext->auto_size     = copy_ext->auto_size;
114         ext->zoom          = copy_ext->zoom;
115         ext->angle         = copy_ext->angle;
116         ext->antialias     = copy_ext->antialias;
117         ext->offset.x     = copy_ext->offset.x;
118         ext->offset.y     = copy_ext->offset.y;
119         ext->pivot.x     = copy_ext->pivot.x;
120         ext->pivot.y     = copy_ext->pivot.y;
121         lv_img_set_src(img, copy_ext->src);
122 
123         /*Refresh the style with new signal function*/
124         lv_obj_refresh_style(img, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
125     }
126 
127     LV_LOG_INFO("image created");
128 
129     return img;
130 }
131 
132 /*=====================
133  * Setter functions
134  *====================*/
135 
136 /**
137  * Set the pixel map to display by the image
138  * @param img pointer to an image object
139  * @param data the image data
140  */
lv_img_set_src(lv_obj_t * img,const void * src_img)141 void lv_img_set_src(lv_obj_t * img, const void * src_img)
142 {
143     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
144 
145     lv_img_src_t src_type = lv_img_src_get_type(src_img);
146     lv_img_ext_t * ext    = lv_obj_get_ext_attr(img);
147 
148 #if LV_USE_LOG && LV_LOG_LEVEL >= LV_LOG_LEVEL_INFO
149     switch(src_type) {
150         case LV_IMG_SRC_FILE:
151             LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_FILE` type found");
152             break;
153         case LV_IMG_SRC_VARIABLE:
154             LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found");
155             break;
156         case LV_IMG_SRC_SYMBOL:
157             LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_SYMBOL` type found");
158             break;
159         default:
160             LV_LOG_WARN("lv_img_set_src: unknown type");
161     }
162 #endif
163 
164     /*If the new source type is unknown free the memories of the old source*/
165     if(src_type == LV_IMG_SRC_UNKNOWN) {
166         LV_LOG_WARN("lv_img_set_src: unknown image type");
167         if(ext->src_type == LV_IMG_SRC_SYMBOL || ext->src_type == LV_IMG_SRC_FILE) {
168             lv_mem_free(ext->src);
169         }
170         ext->src      = NULL;
171         ext->src_type = LV_IMG_SRC_UNKNOWN;
172         return;
173     }
174 
175     lv_img_header_t header;
176     lv_img_decoder_get_info(src_img, &header);
177 
178     /*Save the source*/
179     if(src_type == LV_IMG_SRC_VARIABLE) {
180         LV_LOG_INFO("lv_img_set_src:  `LV_IMG_SRC_VARIABLE` type found");
181 
182         /*If memory was allocated because of the previous `src_type` then free it*/
183         if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {
184             lv_mem_free(ext->src);
185         }
186         ext->src = src_img;
187     }
188     else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) {
189         /* If the new and the old src are the same then it was only a refresh.*/
190         if(ext->src != src_img) {
191             const void * old_src = NULL;
192             /* If memory was allocated because of the previous `src_type` then save its pointer and free after allocation.
193              * It's important to allocate first to be sure the new data will be on a new address.
194              * Else `img_cache` wouldn't see the change in source.*/
195             if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {
196                 old_src = ext->src;
197             }
198             char * new_str = lv_mem_alloc(strlen(src_img) + 1);
199             LV_ASSERT_MEM(new_str);
200             if(new_str == NULL) return;
201             strcpy(new_str, src_img);
202             ext->src = new_str;
203 
204             if(old_src) lv_mem_free(old_src);
205         }
206     }
207 
208     if(src_type == LV_IMG_SRC_SYMBOL) {
209         /*`lv_img_dsc_get_info` couldn't set the with and height of a font so set it here*/
210         const lv_font_t * font = lv_obj_get_style_text_font(img, LV_IMG_PART_MAIN);
211         lv_style_int_t letter_space = lv_obj_get_style_text_letter_space(img, LV_IMG_PART_MAIN);
212         lv_style_int_t line_space = lv_obj_get_style_text_line_space(img, LV_IMG_PART_MAIN);
213         lv_point_t size;
214         _lv_txt_get_size(&size, src_img, font, letter_space, line_space,
215                          LV_COORD_MAX, LV_TXT_FLAG_NONE);
216         header.w = size.x;
217         header.h = size.y;
218     }
219 
220     ext->src_type = src_type;
221     ext->w        = header.w;
222     ext->h        = header.h;
223     ext->cf       = header.cf;
224     ext->pivot.x = header.w / 2;
225     ext->pivot.y = header.h / 2;
226 
227     if(lv_img_get_auto_size(img) != false) {
228         lv_obj_set_size(img, ext->w, ext->h);
229     }
230 
231     /*Provide enough room for the rotated corners*/
232     if(ext->angle || ext->zoom != LV_IMG_ZOOM_NONE) lv_obj_refresh_ext_draw_pad(img);
233 
234     lv_obj_invalidate(img);
235 }
236 
237 /**
238  * Enable the auto size feature.
239  * If enabled the object size will be same as the picture size.
240  * @param img pointer to an image
241  * @param en true: auto size enable, false: auto size disable
242  */
lv_img_set_auto_size(lv_obj_t * img,bool en)243 void lv_img_set_auto_size(lv_obj_t * img, bool en)
244 {
245     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
246 
247     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
248 
249     ext->auto_size = (en == false ? 0 : 1);
250 }
251 
252 /**
253  * Set an offset for the source of an image.
254  * so the image will be displayed from the new origin.
255  * @param img pointer to an image
256  * @param x: the new offset along x axis.
257  */
lv_img_set_offset_x(lv_obj_t * img,lv_coord_t x)258 void lv_img_set_offset_x(lv_obj_t * img, lv_coord_t x)
259 {
260     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
261 
262     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
263 
264     x = x % ext->w;
265 
266     ext->offset.x = x;
267     lv_obj_invalidate(img);
268 }
269 
270 /**
271  * Set an offset for the source of an image.
272  * so the image will be displayed from the new origin.
273  * @param img pointer to an image
274  * @param y: the new offset along y axis.
275  */
lv_img_set_offset_y(lv_obj_t * img,lv_coord_t y)276 void lv_img_set_offset_y(lv_obj_t * img, lv_coord_t y)
277 {
278     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
279 
280     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
281 
282     y = y % ext->h;
283 
284     ext->offset.y = y;
285     lv_obj_invalidate(img);
286 }
287 
288 /**
289  * Set the rotation center of the image.
290  * The image will be rotated around this point
291  * @param img pointer to an image object
292  * @param pivot_x rotation center x of the image
293  * @param pivot_y rotation center y of the image
294  */
lv_img_set_pivot(lv_obj_t * img,lv_coord_t pivot_x,lv_coord_t pivot_y)295 void lv_img_set_pivot(lv_obj_t * img, lv_coord_t pivot_x, lv_coord_t pivot_y)
296 {
297     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
298     if(ext->pivot.x == pivot_x && ext->pivot.y == pivot_y) return;
299 
300     lv_style_int_t transf_zoom = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
301     transf_zoom = (transf_zoom * ext->zoom) >> 8;
302 
303     lv_style_int_t transf_angle = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
304     transf_angle += ext->angle;
305 
306     lv_coord_t w = lv_obj_get_width(img);
307     lv_coord_t h = lv_obj_get_height(img);
308     lv_area_t a;
309     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &ext->pivot);
310     a.x1 += img->coords.x1;
311     a.y1 += img->coords.y1;
312     a.x2 += img->coords.x1;
313     a.y2 += img->coords.y1;
314     lv_obj_invalidate_area(img, &a);
315 
316     ext->pivot.x = pivot_x;
317     ext->pivot.y = pivot_y;
318     lv_obj_refresh_ext_draw_pad(img);
319 
320     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &ext->pivot);
321     a.x1 += img->coords.x1;
322     a.y1 += img->coords.y1;
323     a.x2 += img->coords.x1;
324     a.y2 += img->coords.y1;
325     lv_obj_invalidate_area(img, &a);
326 }
327 
328 /**
329  * Set the rotation angle of the image.
330  * The image will be rotated around the set pivot set by `lv_img_set_pivot()`
331  * @param img pointer to an image object
332  * @param angle rotation angle in degree with 0.1 degree resolution (0..3600: clock wise)
333  */
lv_img_set_angle(lv_obj_t * img,int16_t angle)334 void lv_img_set_angle(lv_obj_t * img, int16_t angle)
335 {
336     if(angle < 0 || angle >= 3600) angle = angle % 3600;
337 
338     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
339     if(angle == ext->angle) return;
340 
341     lv_style_int_t transf_zoom = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
342     transf_zoom = (transf_zoom * ext->zoom) >> 8;
343 
344     lv_style_int_t transf_angle = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
345 
346     lv_coord_t w = lv_obj_get_width(img);
347     lv_coord_t h = lv_obj_get_height(img);
348     lv_area_t a;
349     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle + ext->angle, transf_zoom, &ext->pivot);
350     a.x1 += img->coords.x1;
351     a.y1 += img->coords.y1;
352     a.x2 += img->coords.x1;
353     a.y2 += img->coords.y1;
354     lv_obj_invalidate_area(img, &a);
355 
356     ext->angle = angle;
357     lv_obj_refresh_ext_draw_pad(img);
358 
359     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle + ext->angle, transf_zoom, &ext->pivot);
360     a.x1 += img->coords.x1;
361     a.y1 += img->coords.y1;
362     a.x2 += img->coords.x1;
363     a.y2 += img->coords.y1;
364     lv_obj_invalidate_area(img, &a);
365 }
366 
367 /**
368  * Set the zoom factor of the image.
369  * @param img pointer to an image object
370  * @param zoom the zoom factor.
371  * - 256 or LV_ZOOM_IMG_NONE for no zoom
372  * - <256: scale down
373  * - >256 scale up
374  * - 128 half size
375  * - 512 double size
376  */
lv_img_set_zoom(lv_obj_t * img,uint16_t zoom)377 void lv_img_set_zoom(lv_obj_t * img, uint16_t zoom)
378 {
379     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
380     if(zoom == ext->zoom) return;
381 
382     if(zoom == 0) zoom = 1;
383 
384     lv_style_int_t transf_zoom = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
385 
386     lv_style_int_t transf_angle = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
387     transf_angle += ext->angle;
388 
389     lv_coord_t w = lv_obj_get_width(img);
390     lv_coord_t h = lv_obj_get_height(img);
391     lv_area_t a;
392     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, (transf_zoom * ext->zoom) >> 8, &ext->pivot);
393     a.x1 += img->coords.x1;
394     a.y1 += img->coords.y1;
395     a.x2 += img->coords.x1;
396     a.y2 += img->coords.y1;
397     lv_obj_invalidate_area(img, &a);
398 
399     ext->zoom = zoom;
400     lv_obj_refresh_ext_draw_pad(img);
401 
402     _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, (transf_zoom * ext->zoom) >> 8, &ext->pivot);
403     a.x1 += img->coords.x1;
404     a.y1 += img->coords.y1;
405     a.x2 += img->coords.x1;
406     a.y2 += img->coords.y1;
407     lv_obj_invalidate_area(img, &a);
408 }
409 
410 /**
411  * Enable/disable anti-aliasing for the transformations (rotate, zoom) or not
412  * @param img pointer to an image object
413  * @param antialias true: anti-aliased; false: not anti-aliased
414  */
lv_img_set_antialias(lv_obj_t * img,bool antialias)415 void lv_img_set_antialias(lv_obj_t * img, bool antialias)
416 {
417     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
418     if(antialias == ext->antialias) return;
419 
420     ext->antialias = antialias;
421     lv_obj_invalidate(img);
422 }
423 
424 /*=====================
425  * Getter functions
426  *====================*/
427 
428 /**
429  * Get the source of the image
430  * @param img pointer to an image object
431  * @return the image source (symbol, file name or C array)
432  */
lv_img_get_src(lv_obj_t * img)433 const void * lv_img_get_src(lv_obj_t * img)
434 {
435     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
436 
437     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
438 
439     return ext->src;
440 }
441 
442 /**
443  * Get the name of the file set for an image
444  * @param img pointer to an image
445  * @return file name
446  */
lv_img_get_file_name(const lv_obj_t * img)447 const char * lv_img_get_file_name(const lv_obj_t * img)
448 {
449     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
450 
451     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
452 
453     if(ext->src_type == LV_IMG_SRC_FILE)
454         return ext->src;
455     else
456         return "";
457 }
458 
459 /**
460  * Get the auto size enable attribute
461  * @param img pointer to an image
462  * @return true: auto size is enabled, false: auto size is disabled
463  */
lv_img_get_auto_size(const lv_obj_t * img)464 bool lv_img_get_auto_size(const lv_obj_t * img)
465 {
466     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
467 
468     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
469 
470     return ext->auto_size == 0 ? false : true;
471 }
472 
473 /**
474  * Get the offset.x attribute of the img object.
475  * @param img pointer to an image
476  * @return offset.x value.
477  */
lv_img_get_offset_x(lv_obj_t * img)478 lv_coord_t lv_img_get_offset_x(lv_obj_t * img)
479 {
480     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
481 
482     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
483 
484     return ext->offset.x;
485 }
486 
487 /**
488  * Get the offset.y attribute of the img object.
489  * @param img pointer to an image
490  * @return offset.y value.
491  */
lv_img_get_offset_y(lv_obj_t * img)492 lv_coord_t lv_img_get_offset_y(lv_obj_t * img)
493 {
494     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
495 
496     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
497 
498     return ext->offset.y;
499 }
500 
501 /**
502  * Get the rotation center of the image.
503  * @param img pointer to an image object
504  * @param center rotation center of the image
505  */
lv_img_get_pivot(lv_obj_t * img,lv_point_t * pivot)506 void lv_img_get_pivot(lv_obj_t * img, lv_point_t * pivot)
507 {
508     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
509 
510     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
511 
512     *pivot = ext->pivot;
513 }
514 
515 /**
516  * Get the rotation angle of the image.
517  * @param img pointer to an image object
518  * @return rotation angle in degree (0..359)
519  */
lv_img_get_angle(lv_obj_t * img)520 uint16_t lv_img_get_angle(lv_obj_t * img)
521 {
522     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
523 
524     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
525 
526     return ext->angle;
527 }
528 
529 /**
530  * Get the zoom factor of the image.
531  * @param img pointer to an image object
532  * @return zoom factor (256: no zoom)
533  */
lv_img_get_zoom(lv_obj_t * img)534 uint16_t lv_img_get_zoom(lv_obj_t * img)
535 {
536     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
537 
538     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
539 
540     return ext->zoom;
541 }
542 
543 /**
544  * Get whether the transformations (rotate, zoom) are anti-aliased or not
545  * @param img pointer to an image object
546  * @return true: anti-aliased; false: not anti-aliased
547  */
lv_img_get_antialias(lv_obj_t * img)548 bool lv_img_get_antialias(lv_obj_t * img)
549 {
550     LV_ASSERT_OBJ(img, LV_OBJX_NAME);
551 
552     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
553 
554     return ext->antialias ? true : false;
555 }
556 
557 /**********************
558  *   STATIC FUNCTIONS
559  **********************/
560 
561 /**
562  * Handle the drawing related tasks of the images
563  * @param img pointer to an object
564  * @param clip_area the object will be drawn only in this area
565  * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
566  *                                  (return 'true' if yes)
567  *             LV_DESIGN_DRAW: draw the object (always return 'true')
568  *             LV_DESIGN_DRAW_POST: drawing after every children are drawn
569  * @param return an element of `lv_design_res_t`
570  */
lv_img_design(lv_obj_t * img,const lv_area_t * clip_area,lv_design_mode_t mode)571 static lv_design_res_t lv_img_design(lv_obj_t * img, const lv_area_t * clip_area, lv_design_mode_t mode)
572 {
573     lv_img_ext_t * ext       = lv_obj_get_ext_attr(img);
574 
575     if(mode == LV_DESIGN_COVER_CHK) {
576         if(lv_obj_get_style_clip_corner(img, LV_IMG_PART_MAIN)) return LV_DESIGN_RES_MASKED;
577 
578         if(ext->src_type == LV_IMG_SRC_UNKNOWN || ext->src_type == LV_IMG_SRC_SYMBOL) return LV_DESIGN_RES_NOT_COVER;
579 
580         /*Non true color format might have "holes"*/
581         if(ext->cf != LV_IMG_CF_TRUE_COLOR && ext->cf != LV_IMG_CF_RAW) return LV_DESIGN_RES_NOT_COVER;
582 
583         /*With not LV_OPA_COVER images acn't cover an area */
584         if(lv_obj_get_style_image_opa(img, LV_IMG_PART_MAIN) != LV_OPA_COVER) return LV_DESIGN_RES_NOT_COVER;
585 
586         int32_t angle_final = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
587         angle_final += ext->angle;
588 
589         if(angle_final != 0) return LV_DESIGN_RES_NOT_COVER;
590 
591         int32_t zoom_final = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
592         zoom_final = (zoom_final * ext->zoom) >> 8;
593 
594         if(zoom_final == LV_IMG_ZOOM_NONE) {
595             if(_lv_area_is_in(clip_area, &img->coords, 0) == false) return LV_DESIGN_RES_NOT_COVER;
596         }
597         else {
598             lv_area_t a;
599             _lv_img_buf_get_transformed_area(&a, lv_obj_get_width(img), lv_obj_get_height(img), 0, zoom_final, &ext->pivot);
600             a.x1 += img->coords.x1;
601             a.y1 += img->coords.y1;
602             a.x2 += img->coords.x1;
603             a.y2 += img->coords.y1;
604 
605             if(_lv_area_is_in(clip_area, &a, 0) == false) return LV_DESIGN_RES_NOT_COVER;
606         }
607 
608 #if LV_USE_BLEND_MODES
609         if(lv_obj_get_style_bg_blend_mode(img, LV_IMG_PART_MAIN) != LV_BLEND_MODE_NORMAL) return LV_DESIGN_RES_NOT_COVER;
610         if(lv_obj_get_style_image_blend_mode(img, LV_IMG_PART_MAIN) != LV_BLEND_MODE_NORMAL) return LV_DESIGN_RES_NOT_COVER;
611 #endif
612 
613         return LV_DESIGN_RES_COVER;
614     }
615     else if(mode == LV_DESIGN_DRAW_MAIN) {
616         if(ext->h == 0 || ext->w == 0) return true;
617 
618         lv_draw_rect_dsc_t bg_dsc;
619         lv_draw_rect_dsc_init(&bg_dsc);
620         lv_obj_init_draw_rect_dsc(img, LV_IMG_PART_MAIN, &bg_dsc);
621 
622         /*If the border is drawn later disable loading its properties*/
623         if(lv_obj_get_style_border_post(img, LV_OBJ_PART_MAIN)) {
624             bg_dsc.border_opa = LV_OPA_TRANSP;
625         }
626 
627 
628         int32_t zoom_final = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
629         zoom_final = (zoom_final * ext->zoom) >> 8;
630 
631         int32_t angle_final = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
632         angle_final += ext->angle;
633 
634         lv_coord_t obj_w = lv_obj_get_width(img);
635         lv_coord_t obj_h = lv_obj_get_height(img);
636 
637         lv_area_t bg_coords;
638         _lv_img_buf_get_transformed_area(&bg_coords, obj_w, obj_h,
639                                          angle_final, zoom_final, &ext->pivot);
640         bg_coords.x1 += img->coords.x1;
641         bg_coords.y1 += img->coords.y1;
642         bg_coords.x2 += img->coords.x1;
643         bg_coords.y2 += img->coords.y1;
644         bg_coords.x1 -= lv_obj_get_style_pad_left(img, LV_IMG_PART_MAIN);
645         bg_coords.x2 += lv_obj_get_style_pad_right(img, LV_IMG_PART_MAIN);
646         bg_coords.y1 -= lv_obj_get_style_pad_top(img, LV_IMG_PART_MAIN);
647         bg_coords.y2 += lv_obj_get_style_pad_bottom(img, LV_IMG_PART_MAIN);
648 
649         lv_draw_rect(&bg_coords, clip_area, &bg_dsc);
650 
651         if(zoom_final == 0) return LV_DESIGN_RES_OK;
652 
653         if(lv_obj_get_style_clip_corner(img, LV_OBJ_PART_MAIN)) {
654             lv_draw_mask_radius_param_t * mp = _lv_mem_buf_get(sizeof(lv_draw_mask_radius_param_t));
655 
656             lv_coord_t r = lv_obj_get_style_radius(img, LV_OBJ_PART_MAIN);
657 
658             lv_draw_mask_radius_init(mp, &bg_coords, r, false);
659             /*Add the mask and use `img+8` as custom id. Don't use `obj` directly because it might be used by the user*/
660             lv_draw_mask_add(mp, img + 8);
661         }
662 
663         if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_VARIABLE) {
664             LV_LOG_TRACE("lv_img_design: start to draw image");
665 
666             lv_draw_img_dsc_t img_dsc;
667             lv_draw_img_dsc_init(&img_dsc);
668             lv_obj_init_draw_img_dsc(img, LV_IMG_PART_MAIN, &img_dsc);
669 
670             img_dsc.zoom = zoom_final;
671 
672             if(img_dsc.zoom == 0) return LV_DESIGN_RES_OK;
673 
674             img_dsc.angle = angle_final;
675 
676             img_dsc.pivot.x = ext->pivot.x;
677             img_dsc.pivot.y = ext->pivot.y;
678             img_dsc.antialias = ext->antialias;
679 
680             lv_coord_t zoomed_src_w = (int32_t)((int32_t)ext->w * zoom_final) >> 8;
681             if(zoomed_src_w <= 0) return LV_DESIGN_RES_OK;
682             lv_coord_t zoomed_src_h = (int32_t)((int32_t)ext->h * zoom_final) >> 8;
683             if(zoomed_src_h <= 0) return LV_DESIGN_RES_OK;
684             lv_area_t zommed_coords;
685             lv_obj_get_coords(img, &zommed_coords);
686 
687             zommed_coords.x1 += (int32_t)((int32_t)ext->offset.x * zoom_final) >> 8;
688             zommed_coords.y1 += (int32_t)((int32_t)ext->offset.y * zoom_final) >> 8;
689             zommed_coords.x2 = zommed_coords.x1 + ((int32_t)((int32_t)(obj_w - 1) * zoom_final) >> 8);
690             zommed_coords.y2 = zommed_coords.y1 + ((int32_t)((int32_t)(obj_h - 1) * zoom_final) >> 8);
691 
692             if(zommed_coords.x1 > img->coords.x1) zommed_coords.x1 -= ext->w;
693             if(zommed_coords.y1 > img->coords.y1) zommed_coords.y1 -= ext->h;
694 
695             lv_area_t clip_real;
696             _lv_img_buf_get_transformed_area(&clip_real, lv_obj_get_width(img), lv_obj_get_height(img), angle_final, zoom_final,
697                                              &ext->pivot);
698             clip_real.x1 += img->coords.x1;
699             clip_real.x2 += img->coords.x1;
700             clip_real.y1 += img->coords.y1;
701             clip_real.y2 += img->coords.y1;
702 
703             if(_lv_area_intersect(&clip_real, &clip_real, clip_area) == false) return LV_DESIGN_RES_OK;
704 
705             lv_area_t coords_tmp;
706             coords_tmp.y1 = zommed_coords.y1;
707             coords_tmp.y2 = zommed_coords.y1 + ext->h - 1;
708 
709             for(; coords_tmp.y1 <= clip_real.y2; coords_tmp.y1 += zoomed_src_h, coords_tmp.y2 += zoomed_src_h) {
710                 coords_tmp.x1 = zommed_coords.x1;
711                 coords_tmp.x2 = zommed_coords.x1 + ext->w - 1;
712                 for(; coords_tmp.x1 <= clip_real.x2; coords_tmp.x1 += zoomed_src_w, coords_tmp.x2 += zoomed_src_w) {
713                     lv_draw_img(&coords_tmp, &clip_real, ext->src, &img_dsc);
714                 }
715             }
716         }
717         else if(ext->src_type == LV_IMG_SRC_SYMBOL) {
718             LV_LOG_TRACE("lv_img_design: start to draw symbol");
719             lv_draw_label_dsc_t label_dsc;
720             lv_draw_label_dsc_init(&label_dsc);
721             lv_obj_init_draw_label_dsc(img, LV_IMG_PART_MAIN, &label_dsc);
722 
723             label_dsc.color = lv_obj_get_style_image_recolor(img, LV_IMG_PART_MAIN);
724             lv_draw_label(&img->coords, clip_area, &label_dsc, ext->src, NULL);
725         }
726         else {
727             /*Trigger the error handler of image drawer*/
728             LV_LOG_WARN("lv_img_design: image source type is unknown");
729             lv_draw_img(&img->coords, clip_area, NULL, NULL);
730         }
731     }
732     else if(mode == LV_DESIGN_DRAW_POST) {
733         if(lv_obj_get_style_clip_corner(img, LV_OBJ_PART_MAIN)) {
734             lv_draw_mask_radius_param_t * param = lv_draw_mask_remove_custom(img + 8);
735             _lv_mem_buf_release(param);
736         }
737 
738         /*If the border is drawn later disable loading other properties*/
739         if(lv_obj_get_style_border_post(img, LV_OBJ_PART_MAIN)) {
740             lv_draw_rect_dsc_t draw_dsc;
741             lv_draw_rect_dsc_init(&draw_dsc);
742             draw_dsc.bg_opa = LV_OPA_TRANSP;
743             draw_dsc.pattern_opa = LV_OPA_TRANSP;
744             draw_dsc.shadow_opa = LV_OPA_TRANSP;
745             lv_obj_init_draw_rect_dsc(img, LV_OBJ_PART_MAIN, &draw_dsc);
746 
747             int32_t zoom_final = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
748             zoom_final = (zoom_final * ext->zoom) >> 8;
749 
750             int32_t angle_final = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
751             angle_final += ext->angle;
752 
753             lv_area_t bg_coords;
754             _lv_img_buf_get_transformed_area(&bg_coords, lv_area_get_width(&img->coords), lv_area_get_height(&img->coords),
755                                              angle_final, zoom_final, &ext->pivot);
756             bg_coords.x1 += img->coords.x1;
757             bg_coords.y1 += img->coords.y1;
758             bg_coords.x2 += img->coords.x1;
759             bg_coords.y2 += img->coords.y1;
760             bg_coords.x1 -= lv_obj_get_style_pad_left(img, LV_IMG_PART_MAIN);
761             bg_coords.x2 += lv_obj_get_style_pad_right(img, LV_IMG_PART_MAIN);
762             bg_coords.y1 -= lv_obj_get_style_pad_top(img, LV_IMG_PART_MAIN);
763             bg_coords.y2 += lv_obj_get_style_pad_bottom(img, LV_IMG_PART_MAIN);
764 
765             lv_draw_rect(&img->coords, clip_area, &draw_dsc);
766         }
767     }
768 
769     return LV_DESIGN_RES_OK;
770 }
771 
772 /**
773  * Signal function of the image
774  * @param img pointer to an image object
775  * @param sign a signal type from lv_signal_t enum
776  * @param param pointer to a signal specific variable
777  * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
778  */
lv_img_signal(lv_obj_t * img,lv_signal_t sign,void * param)779 static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param)
780 {
781     lv_res_t res;
782     if(sign == LV_SIGNAL_GET_STYLE) {
783 
784         lv_get_style_info_t * info = param;
785         info->result = lv_img_get_style(img, info->part);
786         if(info->result != NULL) return LV_RES_OK;
787         else return ancestor_signal(img, sign, param);
788     }
789 
790     /* Include the ancient signal function */
791     res = ancestor_signal(img, sign, param);
792     if(res != LV_RES_OK) return res;
793 
794     if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
795 
796     lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
797     if(sign == LV_SIGNAL_CLEANUP) {
798         if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {
799             lv_mem_free(ext->src);
800             ext->src      = NULL;
801             ext->src_type = LV_IMG_SRC_UNKNOWN;
802         }
803     }
804     else if(sign == LV_SIGNAL_STYLE_CHG) {
805         /*Refresh the file name to refresh the symbol text size*/
806         if(ext->src_type == LV_IMG_SRC_SYMBOL) {
807             lv_img_set_src(img, ext->src);
808         }
809     }
810     else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
811 
812         lv_style_int_t transf_zoom = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
813         transf_zoom = (transf_zoom * ext->zoom) >> 8;
814 
815         lv_style_int_t transf_angle = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
816         transf_angle += ext->angle;
817 
818         /*If the image has angle provide enough room for the rotated corners */
819         if(transf_angle || transf_zoom != LV_IMG_ZOOM_NONE) {
820             lv_area_t a;
821             lv_coord_t w = lv_obj_get_width(img);
822             lv_coord_t h = lv_obj_get_height(img);
823             _lv_img_buf_get_transformed_area(&a, w, h, transf_angle, transf_zoom, &ext->pivot);
824             lv_coord_t pad_ori = img->ext_draw_pad;
825             img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, pad_ori - a.x1);
826             img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, pad_ori - a.y1);
827             img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, pad_ori + a.x2 - w);
828             img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, pad_ori + a.y2 - h);
829         }
830 
831         /*Handle the padding of the background*/
832         lv_style_int_t left = lv_obj_get_style_pad_left(img, LV_IMG_PART_MAIN);
833         lv_style_int_t right = lv_obj_get_style_pad_right(img, LV_IMG_PART_MAIN);
834         lv_style_int_t top = lv_obj_get_style_pad_top(img, LV_IMG_PART_MAIN);
835         lv_style_int_t bottom = lv_obj_get_style_pad_bottom(img, LV_IMG_PART_MAIN);
836 
837         img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, left);
838         img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, right);
839         img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, top);
840         img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, bottom);
841 
842 
843     }
844     else if(sign == LV_SIGNAL_HIT_TEST) {
845         lv_hit_test_info_t * info = param;
846         lv_style_int_t zoom = lv_obj_get_style_transform_zoom(img, LV_IMG_PART_MAIN);
847         zoom = (zoom * ext->zoom) >> 8;
848 
849         lv_style_int_t angle = lv_obj_get_style_transform_angle(img, LV_IMG_PART_MAIN);
850         angle += ext->angle;
851 
852         /* If the object is exactly image sized (not cropped, not mosaic) and transformed
853          * perform hit test on it's transformed area */
854         if(ext->w == lv_obj_get_width(img) && ext->h == lv_obj_get_height(img) &&
855            (zoom != LV_IMG_ZOOM_NONE || angle != 0 || ext->pivot.x != ext->w / 2 || ext->pivot.y != ext->h / 2)) {
856 
857             lv_coord_t w = lv_obj_get_width(img);
858             lv_coord_t h = lv_obj_get_height(img);
859             lv_area_t coords;
860             _lv_img_buf_get_transformed_area(&coords, w, h, angle, zoom, &ext->pivot);
861             coords.x1 += img->coords.x1;
862             coords.y1 += img->coords.y1;
863             coords.x2 += img->coords.x1;
864             coords.y2 += img->coords.y1;
865 
866             info->result = _lv_area_is_point_on(&coords, info->point, 0);
867         }
868         else
869             info->result = lv_obj_is_point_on_coords(img, info->point);
870     }
871 
872     return res;
873 }
874 
875 
lv_img_get_style(lv_obj_t * img,uint8_t type)876 static lv_style_list_t * lv_img_get_style(lv_obj_t * img, uint8_t type)
877 {
878     lv_style_list_t * style_dsc_p;
879     switch(type) {
880         case LV_IMG_PART_MAIN:
881             style_dsc_p = &img->style_list;
882             break;
883         default:
884             style_dsc_p = NULL;
885     }
886 
887     return style_dsc_p;
888 }
889 
890 #endif
891