diff --git a/src/draw/lv_draw_image.h b/src/draw/lv_draw_image.h index 3d50419db..6449d13ff 100644 --- a/src/draw/lv_draw_image.h +++ b/src/draw/lv_draw_image.h @@ -56,6 +56,7 @@ typedef struct _lv_draw_image_dsc_t { int32_t frame_id; uint16_t antialias : 1; + uint16_t tile : 1; lv_draw_image_sup_t * sup; } lv_draw_image_dsc_t; diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c index 5e9363d66..4758ad173 100644 --- a/src/draw/sw/lv_draw_sw_img.c +++ b/src/draw/sw/lv_draw_sw_img.c @@ -32,8 +32,20 @@ /********************** * STATIC PROTOTYPES **********************/ -static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * draw_area, - const lv_image_decoder_dsc_t * src, lv_draw_image_sup_t * sup, const lv_area_t * img_coords); + +static void img_draw_normal(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + const lv_area_t * coords); + +static void img_draw_tiled(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + const lv_area_t * coords); + +static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + lv_image_decoder_dsc_t * decoder_dsc, + const lv_area_t * img_area, const lv_area_t * clipped_img_area); + +static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup, + const lv_area_t * img_coords, const lv_area_t * clipped_img_area); /********************** * STATIC VARIABLES @@ -149,29 +161,37 @@ void lv_draw_sw_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dr #endif } - - LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_image(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * coords) { - lv_area_t transformed_area; - lv_area_copy(&transformed_area, coords); + if(!draw_dsc->tile) { + img_draw_normal(draw_unit, draw_dsc, coords); + } + else { + img_draw_tiled(draw_unit, draw_dsc, coords); + } +} + +static void img_draw_normal(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + const lv_area_t * coords) +{ + lv_area_t draw_area; + lv_area_copy(&draw_area, coords); if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) { int32_t w = lv_area_get_width(coords); int32_t h = lv_area_get_height(coords); - _lv_image_buf_get_transformed_area(&transformed_area, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y, + _lv_image_buf_get_transformed_area(&draw_area, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y, &draw_dsc->pivot); - transformed_area.x1 += coords->x1; - transformed_area.y1 += coords->y1; - transformed_area.x2 += coords->x1; - transformed_area.y2 += coords->y1; + draw_area.x1 += coords->x1; + draw_area.y1 += coords->y1; + draw_area.x2 += coords->x1; + draw_area.y2 += coords->y1; } - lv_area_t draw_area; /*Common area of cilp_area and coords. The image is visible only here*/ - /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ - if(!_lv_area_intersect(&draw_area, draw_unit->clip_area, &transformed_area)) { + lv_area_t clipped_img_area; + if(!_lv_area_intersect(&clipped_img_area, &draw_area, draw_unit->clip_area)) { return; } @@ -182,56 +202,100 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_image(lv_draw_unit_t * draw_unit, const lv return; } + img_decode_and_draw(draw_unit, draw_dsc, &decoder_dsc, coords, &clipped_img_area); + + lv_image_decoder_close(&decoder_dsc); +} + +static void img_draw_tiled(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + const lv_area_t * coords) +{ + lv_image_decoder_dsc_t decoder_dsc; + lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, draw_dsc->recolor, -1); + if(res != LV_RESULT_OK) { + LV_LOG_ERROR("Failed to open image"); + return; + } + + int32_t img_w = lv_area_get_width(coords); + int32_t img_h = lv_area_get_height(coords); + + lv_area_t tile_area = *coords; + int32_t tile_x_start = tile_area.x1; + + while(tile_area.y1 < draw_unit->clip_area->y2) { + while(tile_area.x1 < draw_unit->clip_area->x2) { + + lv_area_t clipped_img_area; + if(_lv_area_intersect(&clipped_img_area, &tile_area, draw_unit->clip_area)) { + img_decode_and_draw(draw_unit, draw_dsc, &decoder_dsc, &tile_area, &clipped_img_area); + } + + tile_area.x1 += img_w; + tile_area.x2 += img_w; + } + + tile_area.y1 += img_h; + tile_area.y2 += img_h; + tile_area.x1 = tile_x_start; + tile_area.x2 = tile_x_start + img_w - 1; + } + + lv_image_decoder_close(&decoder_dsc); +} + +static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + lv_image_decoder_dsc_t * decoder_dsc, + const lv_area_t * img_area, const lv_area_t * clipped_img_area) +{ lv_draw_image_sup_t sup; sup.alpha_color = draw_dsc->recolor; - sup.palette = decoder_dsc.palette; - sup.palette_size = decoder_dsc.palette_size; + sup.palette = decoder_dsc->palette; + sup.palette_size = decoder_dsc->palette_size; /*The whole image is available, just draw it*/ - if(decoder_dsc.img_data) { - img_draw_core(draw_unit, draw_dsc, &draw_area, &decoder_dsc, - &sup, coords); + if(decoder_dsc->img_data) { + img_draw_core(draw_unit, draw_dsc, decoder_dsc, &sup, img_area, clipped_img_area); } - /*Draw line by line*/ + /*Draw in smaller pieces*/ else { - lv_area_t relative_full_area_to_decode = draw_area; - lv_area_move(&relative_full_area_to_decode, -coords->x1, -coords->y1); + lv_area_t relative_full_area_to_decode = *clipped_img_area; + lv_area_move(&relative_full_area_to_decode, -img_area->x1, -img_area->y1); lv_area_t relative_decoded_area; relative_decoded_area.x1 = LV_COORD_MIN; relative_decoded_area.y1 = LV_COORD_MIN; relative_decoded_area.x2 = LV_COORD_MIN; relative_decoded_area.y2 = LV_COORD_MIN; - res = LV_RESULT_OK; + lv_result_t res = LV_RESULT_OK; + while(res == LV_RESULT_OK) { - res = lv_image_decoder_get_area(&decoder_dsc, &relative_full_area_to_decode, &relative_decoded_area); + res = lv_image_decoder_get_area(decoder_dsc, &relative_full_area_to_decode, &relative_decoded_area); lv_area_t absolute_decoded_area = relative_decoded_area; - lv_area_move(&absolute_decoded_area, coords->x1, coords->y1); + lv_area_move(&absolute_decoded_area, img_area->x1, img_area->y1); if(res == LV_RESULT_OK) { /*Limit draw area to the current decoded area and draw the image*/ - lv_area_t draw_area_sub; - if(_lv_area_intersect(&draw_area_sub, &draw_area, &absolute_decoded_area)) { - img_draw_core(draw_unit, draw_dsc, &draw_area_sub, &decoder_dsc, - &sup, &absolute_decoded_area); + lv_area_t clipped_img_area_sub; + if(_lv_area_intersect(&clipped_img_area_sub, clipped_img_area, &absolute_decoded_area)) { + img_draw_core(draw_unit, draw_dsc, decoder_dsc, &sup, + &absolute_decoded_area, &clipped_img_area_sub); } } } } - - lv_image_decoder_close(&decoder_dsc); } - -static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * draw_area, - const lv_image_decoder_dsc_t * src, lv_draw_image_sup_t * sup, const lv_area_t * img_coords) +static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, + const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup, + const lv_area_t * img_coords, const lv_area_t * clipped_img_area) { bool transformed = draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE ? true : false; lv_draw_sw_blend_dsc_t blend_dsc; - const uint8_t * src_buf = src->img_data; - const lv_image_header_t * header = &src->header; + const uint8_t * src_buf = decoder_dsc->img_data; + const lv_image_header_t * header = &decoder_dsc->header; uint32_t img_stride = header->stride; lv_color_format_t cf = header->cf; @@ -280,7 +344,7 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t } /*In the other cases every pixel need to be checked one-by-one*/ else { - lv_area_t blend_area = *draw_area; + lv_area_t blend_area = *clipped_img_area; blend_dsc.blend_area = &blend_area; int32_t src_w = lv_area_get_width(img_coords); diff --git a/src/libs/barcode/lv_barcode.c b/src/libs/barcode/lv_barcode.c index 7bb96f18f..f832120a3 100644 --- a/src/libs/barcode/lv_barcode.c +++ b/src/libs/barcode/lv_barcode.c @@ -188,6 +188,7 @@ static void lv_barcode_constructor(const lv_obj_class_t * class_p, lv_obj_t * ob barcode->light_color = lv_color_white(); barcode->scale = 1; barcode->direction = LV_DIR_HOR; + lv_image_set_align(obj, LV_IMAGE_ALIGN_TILE); } static void lv_barcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) diff --git a/src/widgets/image/lv_image.c b/src/widgets/image/lv_image.c index 8880f4024..a0fa46540 100644 --- a/src/widgets/image/lv_image.c +++ b/src/widgets/image/lv_image.c @@ -28,6 +28,7 @@ static void lv_image_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_image_event(const lv_obj_class_t * class_p, lv_event_t * e); static void draw_image(lv_event_t * e); static void scale_update(lv_obj_t * obj, int32_t scale_x, int32_t scale_y); +static void update_align(lv_obj_t * obj); #if LV_USE_OBJ_PROPERTY static const lv_property_ops_t properties[] = { @@ -67,9 +68,9 @@ static const lv_property_ops_t properties[] = { .getter = lv_image_get_antialias, }, { - .id = LV_PROPERTY_IMAGE_SIZE_MODE, - .setter = lv_image_set_size_mode, - .getter = lv_image_get_size_mode, + .id = LV_PROPERTY_IMAGE_ALIGN, + .setter = lv_image_set_align, + .getter = lv_image_get_align, }, }; #endif @@ -204,8 +205,12 @@ void lv_image_set_src(lv_obj_t * obj, const void * src) lv_obj_refresh_self_size(obj); + update_align(obj); + /*Provide enough room for the rotated corners*/ - if(img->rotation || img->scale_x != LV_SCALE_NONE || img->scale_y != LV_SCALE_NONE) lv_obj_refresh_ext_draw_size(obj); + if(img->rotation || img->scale_x != LV_SCALE_NONE || img->scale_y != LV_SCALE_NONE) { + lv_obj_refresh_ext_draw_size(obj); + } lv_obj_invalidate(obj); } @@ -232,17 +237,17 @@ void lv_image_set_offset_y(lv_obj_t * obj, int32_t y) void lv_image_set_rotation(lv_obj_t * obj, int32_t angle) { - while(angle >= 3600) angle -= 3600; - while(angle < 0) angle += 3600; lv_image_t * img = (lv_image_t *)obj; - if((uint32_t)angle == img->rotation) return; - - if(img->obj_size_mode == LV_IMAGE_SIZE_MODE_REAL) { - img->rotation = angle; - lv_obj_invalidate_area(obj, &obj->coords); - return; + if(img->align > _LV_IMAGE_ALIGN_AUTO_TRANSFORM) { + angle = 0; } + else { + while(angle >= 3600) angle -= 3600; + while(angle < 0) angle += 3600; + } + + if((uint32_t)angle == img->rotation) return; lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/ int32_t w = lv_obj_get_width(obj); @@ -277,15 +282,13 @@ void lv_image_set_rotation(lv_obj_t * obj, int32_t angle) void lv_image_set_pivot(lv_obj_t * obj, int32_t x, int32_t y) { lv_image_t * img = (lv_image_t *)obj; - if(img->pivot.x == x && img->pivot.y == y) return; - - if(img->obj_size_mode == LV_IMAGE_SIZE_MODE_REAL) { - img->pivot.x = x; - img->pivot.y = y; - lv_obj_invalidate_area(obj, &obj->coords); - return; + if(img->align > _LV_IMAGE_ALIGN_AUTO_TRANSFORM) { + x = 0; + y = 0; } + if(img->pivot.x == x && img->pivot.y == y) return; + lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/ int32_t w = lv_obj_get_width(obj); int32_t h = lv_obj_get_height(obj); @@ -321,6 +324,10 @@ void lv_image_set_pivot(lv_obj_t * obj, int32_t x, int32_t y) void lv_image_set_scale(lv_obj_t * obj, uint32_t zoom) { lv_image_t * img = (lv_image_t *)obj; + + /*If scale is set internally, do no overwrite it*/ + if(img->align > _LV_IMAGE_ALIGN_AUTO_TRANSFORM) return; + if(zoom == img->scale_x && zoom == img->scale_y) return; if(zoom == 0) zoom = 1; @@ -331,6 +338,10 @@ void lv_image_set_scale(lv_obj_t * obj, uint32_t zoom) void lv_image_set_scale_x(lv_obj_t * obj, uint32_t zoom) { lv_image_t * img = (lv_image_t *)obj; + + /*If scale is set internally, do no overwrite it*/ + if(img->align > _LV_IMAGE_ALIGN_AUTO_TRANSFORM) return; + if(zoom == img->scale_x) return; if(zoom == 0) zoom = 1; @@ -341,6 +352,10 @@ void lv_image_set_scale_x(lv_obj_t * obj, uint32_t zoom) void lv_image_set_scale_y(lv_obj_t * obj, uint32_t zoom) { lv_image_t * img = (lv_image_t *)obj; + + /*If scale is set internally, do no overwrite it*/ + if(img->align > _LV_IMAGE_ALIGN_AUTO_TRANSFORM) return; + if(zoom == img->scale_y) return; if(zoom == 0) zoom = 1; @@ -357,13 +372,16 @@ void lv_image_set_antialias(lv_obj_t * obj, bool antialias) lv_obj_invalidate(obj); } -void lv_image_set_size_mode(lv_obj_t * obj, lv_image_size_mode_t mode) +void lv_image_set_align(lv_obj_t * obj, lv_image_align_t align) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_image_t * img = (lv_image_t *)obj; - if(mode == img->obj_size_mode) return; + if(align == img->align) return; + + img->align = align; + + update_align(obj); - img->obj_size_mode = mode; lv_obj_invalidate(obj); } @@ -453,11 +471,11 @@ bool lv_image_get_antialias(lv_obj_t * obj) return img->antialias ? true : false; } -lv_image_size_mode_t lv_image_get_size_mode(lv_obj_t * obj) +lv_image_align_t lv_image_get_align(lv_obj_t * obj) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_image_t * img = (lv_image_t *)obj; - return img->obj_size_mode; + return img->align; } /********************** @@ -484,7 +502,7 @@ static void lv_image_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) img->offset.y = 0; img->pivot.x = LV_PCT(50); /*Default pivot to image center*/ img->pivot.y = LV_PCT(50); - img->obj_size_mode = LV_IMAGE_SIZE_MODE_VIRTUAL; + img->align = LV_IMAGE_ALIGN_CENTER; lv_obj_remove_flag(obj, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_flag(obj, LV_OBJ_FLAG_ADV_HITTEST); @@ -503,35 +521,15 @@ static void lv_image_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) } } -static lv_point_t lv_image_get_transformed_size(lv_obj_t * obj) -{ - lv_image_t * img = (lv_image_t *)obj; - - - lv_area_t area_transform; - - lv_point_t pivot_px; - lv_image_get_pivot(obj, &pivot_px); - _lv_image_buf_get_transformed_area(&area_transform, img->w, img->h, - img->rotation, img->scale_x, img->scale_y, &pivot_px); - - return (lv_point_t) { - lv_area_get_width(&area_transform), lv_area_get_height(&area_transform) - }; -} - static void lv_image_event(const lv_obj_class_t * class_p, lv_event_t * e) { LV_UNUSED(class_p); lv_event_code_t code = lv_event_get_code(e); - /*Ancestor events will be called during drawing*/ - if(code != LV_EVENT_DRAW_MAIN && code != LV_EVENT_DRAW_POST) { - /*Call the ancestor's event handler*/ - lv_result_t res = lv_obj_event_base(MY_CLASS, e); - if(res != LV_RESULT_OK) return; - } + /*Call the ancestor's event handler*/ + lv_result_t res = lv_obj_event_base(MY_CLASS, e); + if(res != LV_RESULT_OK) return; lv_obj_t * obj = lv_event_get_target(e); lv_image_t * img = (lv_image_t *)obj; @@ -592,13 +590,8 @@ static void lv_image_event(const lv_obj_class_t * class_p, lv_event_t * e) } else if(code == LV_EVENT_GET_SELF_SIZE) { lv_point_t * p = lv_event_get_param(e); - if(img->obj_size_mode == LV_IMAGE_SIZE_MODE_REAL) { - *p = lv_image_get_transformed_size(obj); - } - else { - p->x = img->w; - p->y = img->h; - } + p->x = img->w; + p->y = img->h; } else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) { draw_image(e); @@ -659,132 +652,61 @@ static void draw_image(lv_event_t * e) } } } - else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST) { + else if(code == LV_EVENT_DRAW_MAIN) { - int32_t obj_w = lv_obj_get_width(obj); - int32_t obj_h = lv_obj_get_height(obj); + if(img->h == 0 || img->w == 0) return; + if(img->scale_x == 0 || img->scale_y == 0) return; - int32_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); - int32_t pleft = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width; - int32_t pright = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width; - int32_t ptop = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width; - int32_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width; + lv_layer_t * layer = lv_event_get_layer(e); - lv_point_t bg_pivot; - lv_point_t pivot_px; - lv_image_get_pivot(obj, &pivot_px); + if(img->src_type == LV_IMAGE_SRC_FILE || img->src_type == LV_IMAGE_SRC_VARIABLE) { + lv_draw_image_dsc_t draw_dsc; + lv_draw_image_dsc_init(&draw_dsc); + lv_obj_init_draw_image_dsc(obj, LV_PART_MAIN, &draw_dsc); - bg_pivot.x = pivot_px.x + pleft; - bg_pivot.y = pivot_px.y + ptop; - lv_area_t bg_coords; + lv_area_t clip_area_ori = layer->clip_area; - if(img->obj_size_mode == LV_IMAGE_SIZE_MODE_REAL) { - /*Object size equals to transformed image size*/ - lv_obj_get_coords(obj, &bg_coords); + lv_image_get_pivot(obj, &draw_dsc.pivot); + draw_dsc.scale_x = img->scale_x; + draw_dsc.scale_y = img->scale_y; + draw_dsc.rotation = img->rotation; + draw_dsc.antialias = img->antialias; + draw_dsc.src = img->src; + + lv_area_t img_area = {obj->coords.x1, obj->coords.y1, + obj->coords.x1 + img->w - 1, obj->coords.y1 + img->h - 1 + }; + if(img->align < _LV_IMAGE_ALIGN_AUTO_TRANSFORM) { + lv_area_align(&obj->coords, &img_area, img->align, img->offset.x, img->offset.y); + } + else if(img->align == LV_IMAGE_ALIGN_TILE) { + _lv_area_intersect(&layer->clip_area, &layer->clip_area, &obj->coords); + lv_area_move(&img_area, img->offset.x, img->offset.y); + + lv_area_move(&img_area, + ((layer->clip_area.x1 - img_area.x1 - (img->w - 1)) / img->w) * img->w, + ((layer->clip_area.y1 - img_area.y1 - (img->h - 1)) / img->h) * img->h); + draw_dsc.tile = 1; + } + + lv_draw_image(layer, &draw_dsc, &img_area); + layer->clip_area = clip_area_ori; + + } + else if(img->src_type == LV_IMAGE_SRC_SYMBOL) { + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_dsc); + label_dsc.text = img->src; + lv_draw_label(layer, &label_dsc, &obj->coords); + } + else if(img->src == NULL) { + /*Do not need to draw image when src is NULL*/ + LV_LOG_WARN("image source is NULL"); } else { - _lv_image_buf_get_transformed_area(&bg_coords, obj_w, obj_h, - img->rotation, img->scale_x, img->scale_y, &bg_pivot); - - /*Modify the coordinates to draw the background for the rotated and scaled coordinates*/ - bg_coords.x1 += obj->coords.x1; - bg_coords.y1 += obj->coords.y1; - bg_coords.x2 += obj->coords.x1; - bg_coords.y2 += obj->coords.y1; - } - - lv_area_t ori_coords; - lv_area_copy(&ori_coords, &obj->coords); - lv_area_copy(&obj->coords, &bg_coords); - - lv_result_t res = lv_obj_event_base(MY_CLASS, e); - if(res != LV_RESULT_OK) return; - - lv_area_copy(&obj->coords, &ori_coords); - - if(code == LV_EVENT_DRAW_MAIN) { - if(img->h == 0 || img->w == 0) return; - if(img->scale_x == 0 || img->scale_y == 0) return; - - lv_layer_t * layer = lv_event_get_layer(e); - - lv_area_t img_max_area; - lv_area_copy(&img_max_area, &obj->coords); - - lv_point_t img_size_final = lv_image_get_transformed_size(obj); - - if(img->obj_size_mode == LV_IMAGE_SIZE_MODE_REAL) { - img_max_area.x1 -= ((img->w - img_size_final.x) + 1) / 2; - img_max_area.x2 -= ((img->w - img_size_final.x) + 1) / 2; - img_max_area.y1 -= ((img->h - img_size_final.y) + 1) / 2; - img_max_area.y2 -= ((img->h - img_size_final.y) + 1) / 2; - } - else { - img_max_area.x2 = img_max_area.x1 + lv_area_get_width(&bg_coords) - 1; - img_max_area.y2 = img_max_area.y1 + lv_area_get_height(&bg_coords) - 1; - } - - img_max_area.x1 += pleft; - img_max_area.y1 += ptop; - img_max_area.x2 -= pright; - img_max_area.y2 -= pbottom; - - if(img->src_type == LV_IMAGE_SRC_FILE || img->src_type == LV_IMAGE_SRC_VARIABLE) { - lv_draw_image_dsc_t img_dsc; - lv_draw_image_dsc_init(&img_dsc); - lv_obj_init_draw_image_dsc(obj, LV_PART_MAIN, &img_dsc); - - img_dsc.scale_x = img->scale_x; - img_dsc.scale_y = img->scale_y; - img_dsc.rotation = img->rotation; - img_dsc.pivot.x = pivot_px.x; - img_dsc.pivot.y = pivot_px.y; - img_dsc.antialias = img->antialias; - img_dsc.src = img->src; - - lv_area_t img_clip_area; - img_clip_area.x1 = bg_coords.x1 + pleft; - img_clip_area.y1 = bg_coords.y1 + ptop; - img_clip_area.x2 = bg_coords.x2 - pright; - img_clip_area.y2 = bg_coords.y2 - pbottom; - const lv_area_t clip_area_ori = layer->clip_area; - - if(!_lv_area_intersect(&img_clip_area, &layer->clip_area, &img_clip_area)) return; - layer->clip_area = img_clip_area; - - lv_area_t coords_tmp; - int32_t offset_x = img->offset.x % img->w; - int32_t offset_y = img->offset.y % img->h; - coords_tmp.y1 = img_max_area.y1 + offset_y; - if(coords_tmp.y1 > img_max_area.y1) coords_tmp.y1 -= img->h; - coords_tmp.y2 = coords_tmp.y1 + img->h - 1; - - for(; coords_tmp.y1 < img_max_area.y2; coords_tmp.y1 += img_size_final.y, coords_tmp.y2 += img_size_final.y) { - coords_tmp.x1 = img_max_area.x1 + offset_x; - if(coords_tmp.x1 > img_max_area.x1) coords_tmp.x1 -= img->w; - coords_tmp.x2 = coords_tmp.x1 + img->w - 1; - - for(; coords_tmp.x1 < img_max_area.x2; coords_tmp.x1 += img_size_final.x, coords_tmp.x2 += img_size_final.x) { - lv_draw_image(layer, &img_dsc, &coords_tmp); - } - } - layer->clip_area = clip_area_ori; - } - else if(img->src_type == LV_IMAGE_SRC_SYMBOL) { - lv_draw_label_dsc_t label_dsc; - lv_draw_label_dsc_init(&label_dsc); - lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_dsc); - label_dsc.text = img->src; - lv_draw_label(layer, &label_dsc, &obj->coords); - } - else if(img->src == NULL) { - /*Do not need to draw image when src is NULL*/ - LV_LOG_WARN("image source is NULL"); - } - else { - /*Trigger the error handler of image draw*/ - LV_LOG_WARN("image source type is unknown"); - } + /*Trigger the error handler of image draw*/ + LV_LOG_WARN("image source type is unknown"); } } } @@ -793,13 +715,6 @@ static void scale_update(lv_obj_t * obj, int32_t scale_x, int32_t scale_y) { lv_image_t * img = (lv_image_t *)obj; - if(img->obj_size_mode == LV_IMAGE_SIZE_MODE_REAL) { - img->scale_x = scale_x; - img->scale_y = scale_y; - lv_obj_invalidate_area(obj, &obj->coords); - return; - } - lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/ int32_t w = lv_obj_get_width(obj); int32_t h = lv_obj_get_height(obj); @@ -829,7 +744,24 @@ static void scale_update(lv_obj_t * obj, int32_t scale_x, int32_t scale_y) a.x2 += obj->coords.x1 + 1; a.y2 += obj->coords.y1 + 1; lv_obj_invalidate_area(obj, &a); - } + +static void update_align(lv_obj_t * obj) +{ + lv_image_t * img = (lv_image_t *)obj; + if(img->align == LV_IMAGE_ALIGN_STRETCH) { + lv_image_set_rotation(obj, 0); + lv_image_set_pivot(obj, 0, 0); + int32_t scale_x = lv_obj_get_width(obj) * LV_SCALE_NONE / img->w; + int32_t scale_y = lv_obj_get_height(obj) * LV_SCALE_NONE / img->h; + scale_update(obj, scale_x, scale_y); + } + else if(img->align == LV_IMAGE_ALIGN_TILE) { + lv_image_set_rotation(obj, 0); + lv_image_set_pivot(obj, 0, 0); + scale_update(obj, LV_SCALE_NONE, LV_SCALE_NONE); + + } +} #endif diff --git a/src/widgets/image/lv_image.h b/src/widgets/image/lv_image.h index f4567dac9..06dfc444f 100644 --- a/src/widgets/image/lv_image.h +++ b/src/widgets/image/lv_image.h @@ -39,18 +39,18 @@ extern "C" { */ typedef struct { lv_obj_t obj; - const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + const void * src; /**< Image source: Pointer to an array or a file or a symbol*/ lv_point_t offset; - int32_t w; /*Width of the image (Handled by the library)*/ - int32_t h; /*Height of the image (Handled by the library)*/ - uint32_t rotation; /*rotation angle of the image*/ - uint32_t scale_x; /*256 means no zoom, 512 double size, 128 half size*/ - uint32_t scale_y; /*256 means no zoom, 512 double size, 128 half size*/ - lv_point_t pivot; /*rotation center of the image*/ - uint8_t src_type : 2; /*See: lv_image_src_t*/ - uint8_t cf : 5; /*Color format from `lv_color_format_t`*/ - uint8_t antialias : 1; /*Apply anti-aliasing in transformations (rotate, zoom)*/ - uint8_t obj_size_mode: 2; /*Image size mode when image size and object size is different.*/ + int32_t w; /**< Width of the image (Handled by the library)*/ + int32_t h; /**< Height of the image (Handled by the library)*/ + uint32_t rotation; /**< Rotation angle of the image*/ + uint32_t scale_x; /**< 256 means no zoom, 512 double size, 128 half size*/ + uint32_t scale_y; /**< 256 means no zoom, 512 double size, 128 half size*/ + lv_point_t pivot; /**< Rotation center of the image*/ + uint8_t src_type : 2; /**< See: lv_image_src_t*/ + uint8_t cf : 5; /**< Color format from `lv_color_format_t`*/ + uint8_t antialias : 1; /**< Apply anti-aliasing in transformations (rotate, zoom)*/ + uint8_t align: 4; /**< Image size mode when image size and object size is different. See `lv_image_align_t`*/ } lv_image_t; LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_image_class; @@ -58,22 +58,26 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_image_class; /** * Image size mode, when image size and object size is different */ -enum _lv_image_size_mode_t { - /** Zoom doesn't affect the coordinates of the object, - * however if zoomed in the image is drawn out of the its coordinates. - * The layout's won't change on zoom */ - LV_IMAGE_SIZE_MODE_VIRTUAL = 0, - - /** If the object size is set to SIZE_CONTENT, then object size equals zoomed image size. - * It causes layout recalculation. - * If the object size is set explicitly, the image will be cropped when zoomed in.*/ - LV_IMAGE_SIZE_MODE_REAL, +enum _lv_image_align_t { + LV_IMAGE_ALIGN_DEFAULT = 0, + LV_IMAGE_ALIGN_TOP_LEFT, + LV_IMAGE_ALIGN_TOP_MID, + LV_IMAGE_ALIGN_TOP_RIGHT, + LV_IMAGE_ALIGN_BOTTOM_LEFT, + LV_IMAGE_ALIGN_BOTTOM_MID, + LV_IMAGE_ALIGN_BOTTOM_RIGHT, + LV_IMAGE_ALIGN_LEFT_MID, + LV_IMAGE_ALIGN_RIGHT_MID, + LV_IMAGE_ALIGN_CENTER, + _LV_IMAGE_ALIGN_AUTO_TRANSFORM, + LV_IMAGE_ALIGN_STRETCH, + LV_IMAGE_ALIGN_TILE, }; #ifdef DOXYGEN -typedef _lv_image_size_mode_t lv_image_size_mode_t; +typedef _lv_image_align_t lv_image_align_t; #else -typedef uint8_t lv_image_size_mode_t; +typedef uint8_t lv_image_align_t; #endif /*DOXYGEN*/ #if LV_USE_OBJ_PROPERTY @@ -85,7 +89,7 @@ enum { LV_PROPERTY_ID(IMAGE, PIVOT, LV_PROPERTY_TYPE_POINTER, 4), LV_PROPERTY_ID(IMAGE, SCALE, LV_PROPERTY_TYPE_INT, 5), LV_PROPERTY_ID(IMAGE, ANTIALIAS, LV_PROPERTY_TYPE_INT, 6), - LV_PROPERTY_ID(IMAGE, SIZE_MODE, LV_PROPERTY_TYPE_INT, 7), + LV_PROPERTY_ID(IMAGE, ALIGN, LV_PROPERTY_TYPE_INT, 7), LV_PROPERTY_IMAGE_END, }; #endif @@ -135,7 +139,10 @@ void lv_image_set_offset_y(lv_obj_t * obj, int32_t y); * The image will be rotated around the set pivot set by `lv_image_set_pivot()` * Note that indexed and alpha only images can't be transformed. * @param obj pointer to an image object - * @param angle rotation in degree with 0.1 degree resolution (0..3600: clock wise) + * @param angle rotation in degree with 0.1 degree resolution (0..3600: clock wise) + * @note if image_align is `LV_IMAGE_ALIGN_STRETCH` or `LV_IMAGE_ALIGN_FIT` + * rotation will be set to 0 automatically. + * */ void lv_image_set_rotation(lv_obj_t * obj, int32_t angle); @@ -208,11 +215,13 @@ void lv_image_set_antialias(lv_obj_t * obj, bool antialias); /** * Set the image object size mode. - * * @param obj pointer to an image object - * @param mode the new size mode. + * @param align the new align mode. + * @note if image_align is `LV_IMAGE_ALIGN_STRETCH` or `LV_IMAGE_ALIGN_FIT` + * rotation, scale and pivot will be overwritten and controlled internally. */ -void lv_image_set_size_mode(lv_obj_t * obj, lv_image_size_mode_t mode); +void lv_image_set_align(lv_obj_t * obj, lv_image_align_t align); + /*===================== * Getter functions *====================*/ @@ -241,7 +250,9 @@ int32_t lv_image_get_offset_y(lv_obj_t * obj); /** * Get the rotation of the image. * @param obj pointer to an image object - * @return rotation in 0.1 degrees (0..3600) + * @return rotation in 0.1 degrees (0..3600) + * @note if image_align is `LV_IMAGE_ALIGN_STRETCH` or `LV_IMAGE_ALIGN_FIT` + * rotation will be set to 0 automatically. */ int32_t lv_image_get_rotation(lv_obj_t * obj); @@ -284,9 +295,9 @@ bool lv_image_get_antialias(lv_obj_t * obj); /** * Get the size mode of the image * @param obj pointer to an image object - * @return element of @ref lv_image_size_mode_t + * @return element of @ref lv_image_align_t */ -lv_image_size_mode_t lv_image_get_size_mode(lv_obj_t * obj); +lv_image_align_t lv_image_get_align(lv_obj_t * obj); /********************** * MACROS diff --git a/tests/ref_imgs/image_normal_align.png b/tests/ref_imgs/image_normal_align.png new file mode 100644 index 000000000..672ad0f5e Binary files /dev/null and b/tests/ref_imgs/image_normal_align.png differ diff --git a/tests/ref_imgs/image_normal_align_offset.png b/tests/ref_imgs/image_normal_align_offset.png new file mode 100644 index 000000000..1696cc7be Binary files /dev/null and b/tests/ref_imgs/image_normal_align_offset.png differ diff --git a/tests/ref_imgs/image_rotate_and_scale_pivot_center.png b/tests/ref_imgs/image_rotate_and_scale_pivot_center.png new file mode 100644 index 000000000..07e50c81a Binary files /dev/null and b/tests/ref_imgs/image_rotate_and_scale_pivot_center.png differ diff --git a/tests/ref_imgs/image_rotate_and_scale_pivot_top_left.png b/tests/ref_imgs/image_rotate_and_scale_pivot_top_left.png new file mode 100644 index 000000000..220c4a530 Binary files /dev/null and b/tests/ref_imgs/image_rotate_and_scale_pivot_top_left.png differ diff --git a/tests/ref_imgs/image_rotate_pivot_center.png b/tests/ref_imgs/image_rotate_pivot_center.png new file mode 100644 index 000000000..cae4bc77a Binary files /dev/null and b/tests/ref_imgs/image_rotate_pivot_center.png differ diff --git a/tests/ref_imgs/image_rotate_pivot_top_left.png b/tests/ref_imgs/image_rotate_pivot_top_left.png new file mode 100644 index 000000000..afbfd0924 Binary files /dev/null and b/tests/ref_imgs/image_rotate_pivot_top_left.png differ diff --git a/tests/ref_imgs/image_scale_pivot_center.png b/tests/ref_imgs/image_scale_pivot_center.png new file mode 100644 index 000000000..18ade2de6 Binary files /dev/null and b/tests/ref_imgs/image_scale_pivot_center.png differ diff --git a/tests/ref_imgs/image_scale_pivot_top_left.png b/tests/ref_imgs/image_scale_pivot_top_left.png new file mode 100644 index 000000000..d9a232073 Binary files /dev/null and b/tests/ref_imgs/image_scale_pivot_top_left.png differ diff --git a/tests/ref_imgs/image_scale_x_pivot_center.png b/tests/ref_imgs/image_scale_x_pivot_center.png new file mode 100644 index 000000000..970e8dde2 Binary files /dev/null and b/tests/ref_imgs/image_scale_x_pivot_center.png differ diff --git a/tests/ref_imgs/image_scale_x_pivot_top_left.png b/tests/ref_imgs/image_scale_x_pivot_top_left.png new file mode 100644 index 000000000..95e9c0f6a Binary files /dev/null and b/tests/ref_imgs/image_scale_x_pivot_top_left.png differ diff --git a/tests/ref_imgs/image_scale_y_pivot_center.png b/tests/ref_imgs/image_scale_y_pivot_center.png new file mode 100644 index 000000000..7e6cd386a Binary files /dev/null and b/tests/ref_imgs/image_scale_y_pivot_center.png differ diff --git a/tests/ref_imgs/image_scale_y_pivot_top_left.png b/tests/ref_imgs/image_scale_y_pivot_top_left.png new file mode 100644 index 000000000..0814be265 Binary files /dev/null and b/tests/ref_imgs/image_scale_y_pivot_top_left.png differ diff --git a/tests/ref_imgs/image_stretch.png b/tests/ref_imgs/image_stretch.png new file mode 100644 index 000000000..0ead39927 Binary files /dev/null and b/tests/ref_imgs/image_stretch.png differ diff --git a/tests/ref_imgs/image_tile.png b/tests/ref_imgs/image_tile.png new file mode 100644 index 000000000..ada3d5335 Binary files /dev/null and b/tests/ref_imgs/image_tile.png differ diff --git a/tests/ref_imgs/image_transform_align.png b/tests/ref_imgs/image_transform_align.png new file mode 100644 index 000000000..c99818ec5 Binary files /dev/null and b/tests/ref_imgs/image_transform_align.png differ diff --git a/tests/ref_imgs/image_transform_align_offset.png b/tests/ref_imgs/image_transform_align_offset.png new file mode 100644 index 000000000..a8b1543e5 Binary files /dev/null and b/tests/ref_imgs/image_transform_align_offset.png differ diff --git a/tests/src/test_cases/test_image.c b/tests/src/test_cases/test_image.c new file mode 100644 index 000000000..5faaf3d35 --- /dev/null +++ b/tests/src/test_cases/test_image.c @@ -0,0 +1,367 @@ +#if LV_BUILD_TEST || 1 +#include "../lvgl.h" + +#include "unity/unity.h" + +LV_IMAGE_DECLARE(test_img_lvgl_logo_png); + +void setUp(void) +{ + +} + +void tearDown(void) +{ + /* Function run after every test */ + lv_obj_clean(lv_screen_active()); +} + +static lv_obj_t * img_create(void) +{ + lv_obj_t * img = lv_image_create(lv_screen_active()); + lv_image_set_src(img, &test_img_lvgl_logo_png); + lv_obj_set_style_bg_opa(img, LV_OPA_20, 0); + lv_obj_set_style_shadow_width(img, 10, 0); + lv_obj_set_style_shadow_color(img, lv_color_hex(0xff0000), 0); + return img; +} + +void test_image_rotated_pivot_center(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 100 + (i % 4) * 160, 150 + (i / 4) * 150); + lv_image_set_rotation(img, i * 450); + /*The default pivot should be the center*/ + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_rotate_pivot_center.png"); +} + +void test_image_rotated_pivot_top_left(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 120 + (i % 4) * 180, 100 + (i / 4) * 300); + lv_image_set_rotation(img, i * 450); + lv_image_set_pivot(img, 0, 0); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_rotate_pivot_top_left.png"); +} + +void test_image_scale_pivot_center(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 40 + (i % 4) * 200, 150 + (i / 4) * 150); + lv_image_set_scale(img, 64 + i * 64); + /*The default pivot should be the center*/ + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_scale_pivot_center.png"); +} + +void test_image_scale_pivot_top_left(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 10 + (i % 4) * 190, 150 + (i / 4) * 150); + lv_image_set_scale(img, 64 + i * 64); + lv_image_set_pivot(img, 0, 0); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_scale_pivot_top_left.png"); +} + +void test_image_scale_x_pivot_center(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 40 + (i % 4) * 200, 150 + (i / 4) * 150); + lv_image_set_scale_x(img, 64 + i * 64); + /*The default pivot should be the center*/ + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_scale_x_pivot_center.png"); +} + +void test_image_scale_x_pivot_top_left(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 10 + (i % 4) * 190, 150 + (i / 4) * 150); + lv_image_set_scale_x(img, 64 + i * 64); + lv_image_set_pivot(img, 0, 0); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_scale_x_pivot_top_left.png"); +} + +void test_image_scale_y_pivot_center(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 40 + (i % 4) * 200, 150 + (i / 4) * 150); + lv_image_set_scale_y(img, 64 + i * 64); + /*The default pivot should be the center*/ + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_scale_y_pivot_center.png"); +} + +void test_image_scale_y_pivot_top_left(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 10 + (i % 4) * 190, 150 + (i / 4) * 150); + lv_image_set_scale_y(img, 64 + i * 64); + lv_image_set_pivot(img, 0, 0); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_scale_y_pivot_top_left.png"); +} + +void test_image_rotate_and_scale_pivot_center(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 40 + (i % 4) * 200, 150 + (i / 4) * 150); + lv_image_set_scale_x(img, 64 + i * 64); + lv_image_set_scale_y(img, 32 + i * 96); + lv_image_set_rotation(img, 200 + i * 333); + /*The default pivot should be the center*/ + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_rotate_and_scale_pivot_center.png"); +} + +void test_image_rotate_and_scale_pivot_top_left(void) +{ + lv_obj_t * img; + uint32_t i; + for(i = 0; i < 8; i++) { + img = img_create(); + lv_obj_set_pos(img, 120 + (i % 4) * 180, 120 + (i / 4) * 220); + lv_image_set_scale_x(img, 64 + i * 64); + lv_image_set_scale_y(img, 32 + i * 96); + lv_image_set_rotation(img, 200 + i * 333); + lv_image_set_pivot(img, 0, 0); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_rotate_and_scale_pivot_top_left.png"); +} + +void test_image_normal_align(void) +{ + lv_obj_t * img; + uint32_t i; + lv_image_align_t aligns[] = { + LV_IMAGE_ALIGN_TOP_LEFT, LV_IMAGE_ALIGN_TOP_MID, LV_IMAGE_ALIGN_TOP_RIGHT, + LV_IMAGE_ALIGN_LEFT_MID, LV_IMAGE_ALIGN_CENTER, LV_IMAGE_ALIGN_RIGHT_MID, + LV_IMAGE_ALIGN_BOTTOM_LEFT, LV_IMAGE_ALIGN_BOTTOM_MID, LV_IMAGE_ALIGN_BOTTOM_RIGHT, + }; + + for(i = 0; i < 9; i++) { + img = img_create(); + lv_obj_set_size(img, 200, 120); + lv_obj_set_pos(img, 30 + (i % 3) * 260, 40 + (i / 3) * 150); + lv_image_set_align(img, aligns[i]); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_normal_align.png"); +} + +void test_image_normal_align_offset(void) +{ + lv_obj_t * img; + uint32_t i; + lv_image_align_t aligns[] = { + LV_IMAGE_ALIGN_TOP_LEFT, LV_IMAGE_ALIGN_TOP_MID, LV_IMAGE_ALIGN_TOP_RIGHT, + LV_IMAGE_ALIGN_LEFT_MID, LV_IMAGE_ALIGN_CENTER, LV_IMAGE_ALIGN_RIGHT_MID, + LV_IMAGE_ALIGN_BOTTOM_LEFT, LV_IMAGE_ALIGN_BOTTOM_MID, LV_IMAGE_ALIGN_BOTTOM_RIGHT, + }; + + for(i = 0; i < 9; i++) { + img = img_create(); + lv_obj_set_size(img, 200, 120); + lv_obj_set_pos(img, 30 + (i % 3) * 260, 40 + (i / 3) * 150); + lv_image_set_align(img, aligns[i]); + lv_image_set_offset_x(img, 15); + lv_image_set_offset_y(img, 20); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_normal_align_offset.png"); +} + +void test_image_transform_align(void) +{ + lv_obj_t * img; + uint32_t i; + lv_image_align_t aligns[] = { + LV_IMAGE_ALIGN_TOP_LEFT, LV_IMAGE_ALIGN_TOP_MID, LV_IMAGE_ALIGN_TOP_RIGHT, + LV_IMAGE_ALIGN_LEFT_MID, LV_IMAGE_ALIGN_CENTER, LV_IMAGE_ALIGN_RIGHT_MID, + LV_IMAGE_ALIGN_BOTTOM_LEFT, LV_IMAGE_ALIGN_BOTTOM_MID, LV_IMAGE_ALIGN_BOTTOM_RIGHT, + }; + + for(i = 0; i < 9; i++) { + img = img_create(); + lv_obj_set_size(img, 200, 120); + lv_obj_set_pos(img, 30 + (i % 3) * 260, 40 + (i / 3) * 150); + lv_image_set_scale_x(img, 300); + lv_image_set_scale_y(img, 200); + lv_image_set_rotation(img, 200); + lv_image_set_align(img, aligns[i]); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_transform_align.png"); +} + +void test_image_transform_align_offset(void) +{ + lv_obj_t * img; + uint32_t i; + lv_image_align_t aligns[] = { + LV_IMAGE_ALIGN_TOP_LEFT, LV_IMAGE_ALIGN_TOP_MID, LV_IMAGE_ALIGN_TOP_RIGHT, + LV_IMAGE_ALIGN_LEFT_MID, LV_IMAGE_ALIGN_CENTER, LV_IMAGE_ALIGN_RIGHT_MID, + LV_IMAGE_ALIGN_BOTTOM_LEFT, LV_IMAGE_ALIGN_BOTTOM_MID, LV_IMAGE_ALIGN_BOTTOM_RIGHT, + }; + + for(i = 0; i < 9; i++) { + img = img_create(); + lv_obj_set_size(img, 200, 120); + lv_obj_set_pos(img, 30 + (i % 3) * 260, 40 + (i / 3) * 150); + lv_image_set_align(img, aligns[i]); + lv_image_set_offset_x(img, 15); + lv_image_set_offset_y(img, 20); + lv_image_set_scale_x(img, 300); + lv_image_set_scale_y(img, 200); + lv_image_set_rotation(img, 200); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_transform_align_offset.png"); +} + +void test_image_stretch(void) +{ + lv_obj_t * img; + uint32_t i; + + int32_t img_w = test_img_lvgl_logo_png.header.w; + int32_t img_h = test_img_lvgl_logo_png.header.h; + + int32_t w_array[] = {img_w / 2, img_w, img_w * 2}; + int32_t h_array[] = {img_h / 2, img_h, img_h * 2}; + + + for(i = 0; i < 9; i++) { + img = img_create(); + lv_obj_set_size(img, w_array[i / 3], h_array[i % 3]); + lv_obj_set_pos(img, 30 + (i % 3) * 260, 40 + (i / 3) * 150); + lv_image_set_align(img, LV_IMAGE_ALIGN_STRETCH); + } + + TEST_ASSERT_EQUAL_SCREENSHOT("image_stretch.png"); +} + + +void test_image_tile(void) +{ + lv_obj_t * img; + + img = img_create(); + lv_obj_set_size(img, 350, LV_SIZE_CONTENT); + lv_image_set_align(img, LV_IMAGE_ALIGN_TILE); + lv_obj_set_pos(img, 20, 20); + img = img_create(); + + lv_obj_set_size(img, LV_SIZE_CONTENT, 150); + lv_image_set_align(img, LV_IMAGE_ALIGN_TILE); + lv_obj_set_pos(img, 420, 20); + + img = img_create(); + lv_obj_set_size(img, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_image_set_align(img, LV_IMAGE_ALIGN_TILE); + lv_obj_set_pos(img, 20, 220); + lv_image_set_offset_x(img, -20); + lv_image_set_offset_y(img, 20); + + img = img_create(); + lv_obj_set_size(img, 150, 150); + lv_image_set_align(img, LV_IMAGE_ALIGN_TILE); + lv_obj_set_pos(img, 220, 220); + + img = img_create(); + lv_obj_set_size(img, 150, 150); + lv_image_set_align(img, LV_IMAGE_ALIGN_TILE); + lv_obj_set_pos(img, 420, 220); + lv_image_set_offset_x(img, -2000); + lv_image_set_offset_y(img, 2000); + + TEST_ASSERT_EQUAL_SCREENSHOT("image_tile.png"); +} + +void test_image_ignore_transformation_settings_when_stretched(void) +{ + lv_obj_t * img = img_create(); + lv_obj_set_size(img, 200, 300); + lv_image_set_align(img, LV_IMAGE_ALIGN_STRETCH); + + lv_image_set_rotation(img, 100); + lv_image_set_pivot(img, 200, 300); + TEST_ASSERT_EQUAL_INT(0, lv_image_get_rotation(img)); + + lv_point_t pivot; + lv_image_get_pivot(img, &pivot); + TEST_ASSERT_EQUAL_INT(0, pivot.x); + TEST_ASSERT_EQUAL_INT(0, pivot.y); + + int32_t scale_x_original = lv_image_get_scale_x(img); + int32_t scale_y_original = lv_image_get_scale_y(img); + lv_image_set_scale_x(img, 400); + lv_image_set_scale_y(img, 500); + TEST_ASSERT_EQUAL_INT(scale_x_original, lv_image_get_scale_x(img)); + TEST_ASSERT_EQUAL_INT(scale_y_original, lv_image_get_scale_y(img)); +} + +void test_image_ignore_transformation_settings_when_tiled(void) +{ + lv_obj_t * img = img_create(); + lv_obj_set_size(img, 200, 300); + lv_image_set_align(img, LV_IMAGE_ALIGN_TILE); + + lv_image_set_rotation(img, 100); + lv_image_set_pivot(img, 200, 300); + lv_image_set_scale_x(img, 400); + lv_image_set_scale_y(img, 500); + + lv_point_t pivot; + lv_image_get_pivot(img, &pivot); + TEST_ASSERT_EQUAL_INT(0, pivot.x); + TEST_ASSERT_EQUAL_INT(0, pivot.y); + TEST_ASSERT_EQUAL_INT(0, lv_image_get_rotation(img)); + TEST_ASSERT_EQUAL_INT(LV_SCALE_NONE, lv_image_get_scale_x(img)); + TEST_ASSERT_EQUAL_INT(LV_SCALE_NONE, lv_image_get_scale_y(img)); +} + + + +#endif