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 "../core/lv_disp.h"
13 #include "../misc/lv_assert.h"
14 #include "../draw/lv_img_decoder.h"
15 #include "../misc/lv_fs.h"
16 #include "../misc/lv_txt.h"
17 #include "../misc/lv_math.h"
18 #include "../misc/lv_log.h"
19
20 /*********************
21 * DEFINES
22 *********************/
23 #define MY_CLASS &lv_img_class
24
25 /**********************
26 * TYPEDEFS
27 **********************/
28
29 /**********************
30 * STATIC PROTOTYPES
31 **********************/
32 static void lv_img_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
33 static void lv_img_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
34 static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e);
35 static void draw_img(lv_event_t * e);
36
37 /**********************
38 * STATIC VARIABLES
39 **********************/
40 const lv_obj_class_t lv_img_class = {
41 .constructor_cb = lv_img_constructor,
42 .destructor_cb = lv_img_destructor,
43 .event_cb = lv_img_event,
44 .width_def = LV_SIZE_CONTENT,
45 .height_def = LV_SIZE_CONTENT,
46 .instance_size = sizeof(lv_img_t),
47 .base_class = &lv_obj_class
48 };
49
50 /**********************
51 * MACROS
52 **********************/
53
54 /**********************
55 * GLOBAL FUNCTIONS
56 **********************/
57
lv_img_create(lv_obj_t * parent)58 lv_obj_t * lv_img_create(lv_obj_t * parent)
59 {
60 LV_LOG_INFO("begin");
61 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
62 lv_obj_class_init_obj(obj);
63 return obj;
64 }
65
66 /*=====================
67 * Setter functions
68 *====================*/
69
lv_img_set_src(lv_obj_t * obj,const void * src)70 void lv_img_set_src(lv_obj_t * obj, const void * src)
71 {
72 LV_ASSERT_OBJ(obj, MY_CLASS);
73
74 lv_obj_invalidate(obj);
75
76 lv_img_src_t src_type = lv_img_src_get_type(src);
77 lv_img_t * img = (lv_img_t *)obj;
78
79 #if LV_USE_LOG && LV_LOG_LEVEL >= LV_LOG_LEVEL_INFO
80 switch(src_type) {
81 case LV_IMG_SRC_FILE:
82 LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_FILE` type found");
83 break;
84 case LV_IMG_SRC_VARIABLE:
85 LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found");
86 break;
87 case LV_IMG_SRC_SYMBOL:
88 LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_SYMBOL` type found");
89 break;
90 default:
91 LV_LOG_WARN("lv_img_set_src: unknown type");
92 }
93 #endif
94
95 /*If the new source type is unknown free the memories of the old source*/
96 if(src_type == LV_IMG_SRC_UNKNOWN) {
97 LV_LOG_WARN("lv_img_set_src: unknown image type");
98 if(img->src_type == LV_IMG_SRC_SYMBOL || img->src_type == LV_IMG_SRC_FILE) {
99 lv_mem_free((void *)img->src);
100 }
101 img->src = NULL;
102 img->src_type = LV_IMG_SRC_UNKNOWN;
103 return;
104 }
105
106 lv_img_header_t header;
107 lv_img_decoder_get_info(src, &header);
108
109 /*Save the source*/
110 if(src_type == LV_IMG_SRC_VARIABLE) {
111 /*If memory was allocated because of the previous `src_type` then free it*/
112 if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
113 lv_mem_free((void *)img->src);
114 }
115 img->src = src;
116 }
117 else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) {
118 /*If the new and the old src are the same then it was only a refresh.*/
119 if(img->src != src) {
120 const void * old_src = NULL;
121 /*If memory was allocated because of the previous `src_type` then save its pointer and free after allocation.
122 *It's important to allocate first to be sure the new data will be on a new address.
123 *Else `img_cache` wouldn't see the change in source.*/
124 if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
125 old_src = img->src;
126 }
127 char * new_str = lv_mem_alloc(strlen(src) + 1);
128 LV_ASSERT_MALLOC(new_str);
129 if(new_str == NULL) return;
130 strcpy(new_str, src);
131 img->src = new_str;
132
133 if(old_src) lv_mem_free((void *)old_src);
134 }
135 }
136
137 if(src_type == LV_IMG_SRC_SYMBOL) {
138 /*`lv_img_dsc_get_info` couldn't set the width and height of a font so set it here*/
139 const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
140 lv_coord_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
141 lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
142 lv_point_t size;
143 lv_txt_get_size(&size, src, font, letter_space, line_space, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
144 header.w = size.x;
145 header.h = size.y;
146 }
147
148 img->src_type = src_type;
149 img->w = header.w;
150 img->h = header.h;
151 img->cf = header.cf;
152 img->pivot.x = header.w / 2;
153 img->pivot.y = header.h / 2;
154
155 lv_obj_refresh_self_size(obj);
156
157 /*Provide enough room for the rotated corners*/
158 if(img->angle || img->zoom != LV_IMG_ZOOM_NONE) lv_obj_refresh_ext_draw_size(obj);
159
160 lv_obj_invalidate(obj);
161 }
162
lv_img_set_offset_x(lv_obj_t * obj,lv_coord_t x)163 void lv_img_set_offset_x(lv_obj_t * obj, lv_coord_t x)
164 {
165 LV_ASSERT_OBJ(obj, MY_CLASS);
166
167 lv_img_t * img = (lv_img_t *)obj;
168
169 img->offset.x = x;
170 lv_obj_invalidate(obj);
171 }
172
lv_img_set_offset_y(lv_obj_t * obj,lv_coord_t y)173 void lv_img_set_offset_y(lv_obj_t * obj, lv_coord_t y)
174 {
175 LV_ASSERT_OBJ(obj, MY_CLASS);
176
177 lv_img_t * img = (lv_img_t *)obj;
178
179 img->offset.y = y;
180 lv_obj_invalidate(obj);
181 }
182
lv_img_set_angle(lv_obj_t * obj,int16_t angle)183 void lv_img_set_angle(lv_obj_t * obj, int16_t angle)
184 {
185 while(angle >= 3600) angle -= 3600;
186 while(angle < 0) angle += 3600;
187
188 lv_img_t * img = (lv_img_t *)obj;
189 if(angle == img->angle) return;
190
191 lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
192 lv_coord_t w = lv_obj_get_width(obj);
193 lv_coord_t h = lv_obj_get_height(obj);
194 lv_area_t a;
195 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
196 a.x1 += obj->coords.x1;
197 a.y1 += obj->coords.y1;
198 a.x2 += obj->coords.x1;
199 a.y2 += obj->coords.y1;
200 lv_obj_invalidate_area(obj, &a);
201
202 img->angle = angle;
203
204 /* Disable invalidations because lv_obj_refresh_ext_draw_size would invalidate
205 * the whole ext draw area */
206 lv_disp_t * disp = lv_obj_get_disp(obj);
207 lv_disp_enable_invalidation(disp, false);
208 lv_obj_refresh_ext_draw_size(obj);
209 lv_disp_enable_invalidation(disp, true);
210
211 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
212 a.x1 += obj->coords.x1;
213 a.y1 += obj->coords.y1;
214 a.x2 += obj->coords.x1;
215 a.y2 += obj->coords.y1;
216 lv_obj_invalidate_area(obj, &a);
217 }
218
lv_img_set_pivot(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)219 void lv_img_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
220 {
221 lv_img_t * img = (lv_img_t *)obj;
222 if(img->pivot.x == x && img->pivot.y == y) return;
223
224 lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
225 lv_coord_t w = lv_obj_get_width(obj);
226 lv_coord_t h = lv_obj_get_height(obj);
227 lv_area_t a;
228 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
229 a.x1 += obj->coords.x1;
230 a.y1 += obj->coords.y1;
231 a.x2 += obj->coords.x1;
232 a.y2 += obj->coords.y1;
233 lv_obj_invalidate_area(obj, &a);
234
235 img->pivot.x = x;
236 img->pivot.y = y;
237
238 /* Disable invalidations because lv_obj_refresh_ext_draw_size would invalidate
239 * the whole ext draw area */
240 lv_disp_t * disp = lv_obj_get_disp(obj);
241 lv_disp_enable_invalidation(disp, false);
242 lv_obj_refresh_ext_draw_size(obj);
243 lv_disp_enable_invalidation(disp, true);
244
245 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
246 a.x1 += obj->coords.x1;
247 a.y1 += obj->coords.y1;
248 a.x2 += obj->coords.x1;
249 a.y2 += obj->coords.y1;
250 lv_obj_invalidate_area(obj, &a);
251 }
252
lv_img_set_zoom(lv_obj_t * obj,uint16_t zoom)253 void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom)
254 {
255 lv_img_t * img = (lv_img_t *)obj;
256 if(zoom == img->zoom) return;
257
258 if(zoom == 0) zoom = 1;
259
260 lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
261 lv_coord_t w = lv_obj_get_width(obj);
262 lv_coord_t h = lv_obj_get_height(obj);
263 lv_area_t a;
264 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom >> 8, &img->pivot);
265 a.x1 += obj->coords.x1 - 1;
266 a.y1 += obj->coords.y1 - 1;
267 a.x2 += obj->coords.x1 + 1;
268 a.y2 += obj->coords.y1 + 1;
269 lv_obj_invalidate_area(obj, &a);
270
271 img->zoom = zoom;
272
273 /* Disable invalidations because lv_obj_refresh_ext_draw_size would invalidate
274 * the whole ext draw area */
275 lv_disp_t * disp = lv_obj_get_disp(obj);
276 lv_disp_enable_invalidation(disp, false);
277 lv_obj_refresh_ext_draw_size(obj);
278 lv_disp_enable_invalidation(disp, true);
279
280 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &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
428 lv_area_t area_transform;
429 _lv_img_buf_get_transformed_area(&area_transform, img->w, img->h,
430 img->angle, img->zoom, &img->pivot);
431
432 return (lv_point_t) {
433 lv_area_get_width(&area_transform), lv_area_get_height(&area_transform)
434 };
435 }
436
lv_img_event(const lv_obj_class_t * class_p,lv_event_t * e)437 static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e)
438 {
439 LV_UNUSED(class_p);
440
441 lv_event_code_t code = lv_event_get_code(e);
442
443 /*Ancestor events will be called during drawing*/
444 if(code != LV_EVENT_DRAW_MAIN && code != LV_EVENT_DRAW_POST) {
445 /*Call the ancestor's event handler*/
446 lv_res_t res = lv_obj_event_base(MY_CLASS, e);
447 if(res != LV_RES_OK) return;
448 }
449
450 lv_obj_t * obj = lv_event_get_target(e);
451 lv_img_t * img = (lv_img_t *)obj;
452
453 if(code == LV_EVENT_STYLE_CHANGED) {
454 /*Refresh the file name to refresh the symbol text size*/
455 if(img->src_type == LV_IMG_SRC_SYMBOL) {
456 lv_img_set_src(obj, img->src);
457 }
458 else {
459 /*With transformation it might change*/
460 lv_obj_refresh_ext_draw_size(obj);
461 }
462 }
463 else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
464
465 lv_coord_t * s = lv_event_get_param(e);
466
467 /*If the image has angle provide enough room for the rotated corners*/
468 if(img->angle || img->zoom != LV_IMG_ZOOM_NONE) {
469 lv_area_t a;
470 lv_coord_t w = lv_obj_get_width(obj);
471 lv_coord_t h = lv_obj_get_height(obj);
472 _lv_img_buf_get_transformed_area(&a, w, h, img->angle, img->zoom, &img->pivot);
473 *s = LV_MAX(*s, -a.x1);
474 *s = LV_MAX(*s, -a.y1);
475 *s = LV_MAX(*s, a.x2 - w);
476 *s = LV_MAX(*s, a.y2 - h);
477 }
478 }
479 else if(code == LV_EVENT_HIT_TEST) {
480 lv_hit_test_info_t * info = lv_event_get_param(e);
481
482 /*If the object is exactly image sized (not cropped, not mosaic) and transformed
483 *perform hit test on its transformed area*/
484 if(img->w == lv_obj_get_width(obj) && img->h == lv_obj_get_height(obj) &&
485 (img->zoom != LV_IMG_ZOOM_NONE || img->angle != 0 || img->pivot.x != img->w / 2 || img->pivot.y != img->h / 2)) {
486
487 lv_coord_t w = lv_obj_get_width(obj);
488 lv_coord_t h = lv_obj_get_height(obj);
489 lv_area_t coords;
490 _lv_img_buf_get_transformed_area(&coords, w, h, img->angle, img->zoom, &img->pivot);
491 coords.x1 += obj->coords.x1;
492 coords.y1 += obj->coords.y1;
493 coords.x2 += obj->coords.x1;
494 coords.y2 += obj->coords.y1;
495
496 info->res = _lv_area_is_point_on(&coords, info->point, 0);
497 }
498 else {
499 lv_area_t a;
500 lv_obj_get_click_area(obj, &a);
501 info->res = _lv_area_is_point_on(&a, info->point, 0);
502 }
503 }
504 else if(code == LV_EVENT_GET_SELF_SIZE) {
505 lv_point_t * p = lv_event_get_param(e);
506 if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
507 *p = lv_img_get_transformed_size(obj);
508 }
509 else {
510 p->x = img->w;
511 p->y = img->h;
512 }
513 }
514 else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) {
515 draw_img(e);
516 }
517 }
518
draw_img(lv_event_t * e)519 static void draw_img(lv_event_t * e)
520 {
521 lv_event_code_t code = lv_event_get_code(e);
522 lv_obj_t * obj = lv_event_get_target(e);
523 lv_img_t * img = (lv_img_t *)obj;
524 if(code == LV_EVENT_COVER_CHECK) {
525 lv_cover_check_info_t * info = lv_event_get_param(e);
526 if(info->res == LV_COVER_RES_MASKED) return;
527 if(img->src_type == LV_IMG_SRC_UNKNOWN || img->src_type == LV_IMG_SRC_SYMBOL) {
528 info->res = LV_COVER_RES_NOT_COVER;
529 return;
530 }
531
532 /*Non true color format might have "holes"*/
533 if(img->cf != LV_IMG_CF_TRUE_COLOR && img->cf != LV_IMG_CF_RAW) {
534 info->res = LV_COVER_RES_NOT_COVER;
535 return;
536 }
537
538 /*With not LV_OPA_COVER images can't cover an area */
539 if(lv_obj_get_style_img_opa(obj, LV_PART_MAIN) != LV_OPA_COVER) {
540 info->res = LV_COVER_RES_NOT_COVER;
541 return;
542 }
543
544 if(img->angle != 0) {
545 info->res = LV_COVER_RES_NOT_COVER;
546 return;
547 }
548
549 const lv_area_t * clip_area = lv_event_get_param(e);
550 if(img->zoom == LV_IMG_ZOOM_NONE) {
551 if(_lv_area_is_in(clip_area, &obj->coords, 0) == false) {
552 info->res = LV_COVER_RES_NOT_COVER;
553 return;
554 }
555 }
556 else {
557 lv_area_t a;
558 _lv_img_buf_get_transformed_area(&a, lv_obj_get_width(obj), lv_obj_get_height(obj), 0, img->zoom, &img->pivot);
559 a.x1 += obj->coords.x1;
560 a.y1 += obj->coords.y1;
561 a.x2 += obj->coords.x1;
562 a.y2 += obj->coords.y1;
563
564 if(_lv_area_is_in(clip_area, &a, 0) == false) {
565 info->res = LV_COVER_RES_NOT_COVER;
566 return;
567 }
568 }
569 }
570 else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST) {
571
572 lv_coord_t obj_w = lv_obj_get_width(obj);
573 lv_coord_t obj_h = lv_obj_get_height(obj);
574
575 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
576 lv_coord_t pleft = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width;
577 lv_coord_t pright = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width;
578 lv_coord_t ptop = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width;
579 lv_coord_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width;
580
581 lv_point_t bg_pivot;
582 bg_pivot.x = img->pivot.x + pleft;
583 bg_pivot.y = img->pivot.y + ptop;
584 lv_area_t bg_coords;
585
586 if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
587 /*Object size equals to transformed image size*/
588 lv_obj_get_coords(obj, &bg_coords);
589 }
590 else {
591 _lv_img_buf_get_transformed_area(&bg_coords, obj_w, obj_h,
592 img->angle, img->zoom, &bg_pivot);
593
594 /*Modify the coordinates to draw the background for the rotated and scaled coordinates*/
595 bg_coords.x1 += obj->coords.x1;
596 bg_coords.y1 += obj->coords.y1;
597 bg_coords.x2 += obj->coords.x1;
598 bg_coords.y2 += obj->coords.y1;
599 }
600
601 lv_area_t ori_coords;
602 lv_area_copy(&ori_coords, &obj->coords);
603 lv_area_copy(&obj->coords, &bg_coords);
604
605 lv_res_t res = lv_obj_event_base(MY_CLASS, e);
606 if(res != LV_RES_OK) return;
607
608 lv_area_copy(&obj->coords, &ori_coords);
609
610 if(code == LV_EVENT_DRAW_MAIN) {
611 if(img->h == 0 || img->w == 0) return;
612 if(img->zoom == 0) return;
613
614 lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
615
616 lv_area_t img_max_area;
617 lv_area_copy(&img_max_area, &obj->coords);
618
619 lv_point_t img_size_final = lv_img_get_transformed_size(obj);
620
621 if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
622 img_max_area.x1 -= ((img->w - img_size_final.x) + 1) / 2;
623 img_max_area.x2 -= ((img->w - img_size_final.x) + 1) / 2;
624 img_max_area.y1 -= ((img->h - img_size_final.y) + 1) / 2;
625 img_max_area.y2 -= ((img->h - img_size_final.y) + 1) / 2;
626 }
627 else {
628 img_max_area.x2 = img_max_area.x1 + lv_area_get_width(&bg_coords) - 1;
629 img_max_area.y2 = img_max_area.y1 + lv_area_get_height(&bg_coords) - 1;
630 }
631
632 img_max_area.x1 += pleft;
633 img_max_area.y1 += ptop;
634 img_max_area.x2 -= pright;
635 img_max_area.y2 -= pbottom;
636
637 if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_VARIABLE) {
638 lv_draw_img_dsc_t img_dsc;
639 lv_draw_img_dsc_init(&img_dsc);
640 lv_obj_init_draw_img_dsc(obj, LV_PART_MAIN, &img_dsc);
641
642 img_dsc.zoom = img->zoom;
643 img_dsc.angle = img->angle;
644 img_dsc.pivot.x = img->pivot.x;
645 img_dsc.pivot.y = img->pivot.y;
646 img_dsc.antialias = img->antialias;
647
648 lv_area_t img_clip_area;
649 img_clip_area.x1 = bg_coords.x1 + pleft;
650 img_clip_area.y1 = bg_coords.y1 + ptop;
651 img_clip_area.x2 = bg_coords.x2 - pright;
652 img_clip_area.y2 = bg_coords.y2 - pbottom;
653 const lv_area_t * clip_area_ori = draw_ctx->clip_area;
654
655 if(!_lv_area_intersect(&img_clip_area, draw_ctx->clip_area, &img_clip_area)) return;
656 draw_ctx->clip_area = &img_clip_area;
657
658 lv_area_t coords_tmp;
659 lv_coord_t offset_x = img->offset.x % img->w;
660 lv_coord_t offset_y = img->offset.y % img->h;
661 coords_tmp.y1 = img_max_area.y1 + offset_y;
662 if(coords_tmp.y1 > img_max_area.y1) coords_tmp.y1 -= img->h;
663 coords_tmp.y2 = coords_tmp.y1 + img->h - 1;
664
665 for(; coords_tmp.y1 < img_max_area.y2; coords_tmp.y1 += img_size_final.y, coords_tmp.y2 += img_size_final.y) {
666 coords_tmp.x1 = img_max_area.x1 + offset_x;
667 if(coords_tmp.x1 > img_max_area.x1) coords_tmp.x1 -= img->w;
668 coords_tmp.x2 = coords_tmp.x1 + img->w - 1;
669
670 for(; coords_tmp.x1 < img_max_area.x2; coords_tmp.x1 += img_size_final.x, coords_tmp.x2 += img_size_final.x) {
671 lv_draw_img(draw_ctx, &img_dsc, &coords_tmp, img->src);
672 }
673 }
674 draw_ctx->clip_area = clip_area_ori;
675 }
676 else if(img->src_type == LV_IMG_SRC_SYMBOL) {
677 lv_draw_label_dsc_t label_dsc;
678 lv_draw_label_dsc_init(&label_dsc);
679 lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_dsc);
680
681 lv_draw_label(draw_ctx, &label_dsc, &obj->coords, img->src, NULL);
682 }
683 else {
684 /*Trigger the error handler of image draw*/
685 LV_LOG_WARN("draw_img: image source type is unknown");
686 lv_draw_img(draw_ctx, NULL, &obj->coords, NULL);
687 }
688 }
689 }
690 }
691
692 #endif
693