From 84a70d16175b0d089f70e337fa12ee4742500f85 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 1 Nov 2019 06:00:04 +0100 Subject: [PATCH 01/12] add lv_img_get_px_rotated --- src/lv_draw/lv_draw_img.c | 228 +++++++++++++++++++++++++++----------- src/lv_draw/lv_draw_img.h | 13 ++- src/lv_objx/lv_canvas.c | 114 ++++--------------- 3 files changed, 189 insertions(+), 166 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 2bb8c95b5..1b2bd8563 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -10,6 +10,7 @@ #include "lv_img_cache.h" #include "../lv_misc/lv_log.h" #include "../lv_misc/lv_mem.h" +#include "../lv_misc/lv_math.h" /********************* * DEFINES @@ -23,7 +24,7 @@ * STATIC PROTOTYPES **********************/ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, - const lv_style_t * style, lv_opa_t opa_scale); + const lv_style_t * style, lv_opa_t opa_scale); /********************** * STATIC VARIABLES @@ -46,7 +47,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas * @param opa_scale scale down all opacities by the factor */ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, - lv_opa_t opa_scale) + lv_opa_t opa_scale) { if(src == NULL) { LV_LOG_WARN("Image draw: src is NULL"); @@ -71,12 +72,11 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * * @param dsc an image descriptor * @param x x coordinate of the point to get * @param y x coordinate of the point to get - * @param style style of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` `style->image.color` shows - * the color. Can be `NULL` but for `ALPHA` images black will be returned. In other cases it is not - * used. + * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. + * Not used in other cases. * @return color of the point */ -lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, const lv_style_t * style) +lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color) { lv_color_t p_color = LV_COLOR_BLACK; if(x >= dsc->header.w) { @@ -98,7 +98,7 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t uint8_t * buf_u8 = (uint8_t *)dsc->data; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED || - dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3; uint32_t px = dsc->header.w * y * px_size + x * px_size; memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t)); @@ -140,11 +140,8 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t uint32_t px = dsc->header.w * y + x; p_color.full = buf_u8[px]; } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || - dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { - if(style) - p_color = style->image.color; - else - p_color = LV_COLOR_BLACK; + dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + p_color = color; } return p_color; } @@ -203,7 +200,7 @@ lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y) return opa_table[px_opa]; } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) { const uint8_t opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ - 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255}; + 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255}; uint8_t bit = (x & 0x1) * 4; x = x >> 1; @@ -337,6 +334,103 @@ void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_ } } +bool lv_img_get_px_rotated(lv_img_dsc_t * img, uint16_t angle, lv_color_t color, lv_point_t * point, lv_point_t * pivot, lv_color_t * res_color, lv_opa_t * res_opa) +{ + + int32_t sinma = lv_trigo_sin(-angle); + int32_t cosma = lv_trigo_sin(-angle + 90); /* cos */ + + /*Get the target point relative coordinates to the pivot*/ + int32_t xt = point->x - pivot->x; + int32_t yt = point->y - pivot->y; + + /*Get the source pixel from the upscaled image*/ + int32_t xs = ((cosma * xt - sinma * yt) >> (LV_TRIGO_SHIFT - 8)) + pivot->x * 256; + int32_t ys = ((sinma * xt + cosma * yt) >> (LV_TRIGO_SHIFT - 8)) + pivot->y * 256; + + /*Get the integer part of the source pixel*/ + int xs_int = xs >> 8; + int ys_int = ys >> 8; + + if(xs_int >= img->header.w) return false; + else if(xs_int < 0) return false; + + if(ys_int >= img->header.h) return false; + else if(ys_int < 0) return false; + + /*Get the fractional part of the source pixel*/ + int xs_fract = xs & 0xff; + int ys_fract = ys & 0xff; + + /* If the fractional < 0x70 mix the source pixel with the left/top pixel + * If the fractional > 0x90 mix the source pixel with the right/bottom pixel + * In the 0x70..0x90 range use the unchanged source pixel */ + + int xn; /*x neightboor*/ + lv_opa_t xr; /*x mix ratio*/ + if(xs_fract < 0x70) { + xn = xs_int - 1; + xr = xs_fract * 2; + } else if(xs_fract > 0x90) { + xn = xs_int + 1; + xr = (0xFF - xs_fract) * 2; + } else { + xn = xs_int; + xr = 0xFF; + } + + /*Handle under/overflow*/ + if(xn >= img->header.w) return false; + else if(xn < 0) return false; + + int yn; /*y neightboor*/ + lv_opa_t yr; /*y mix ratio*/ + if(ys_fract < 0x70) { + yn = ys_int - 1; + yr = ys_fract * 2; + } else if(ys_fract > 0x90) { + yn = ys_int + 1; + yr = (0xFF - ys_fract) * 2; + } else { + yn = ys_int; + yr = 0xFF; + } + + /*Handle under/overflow*/ + if(yn >= img->header.h) return false; + else if(yn < 0) return false; + + /*Get the mixture of the original source and the neightboor pixels in both directions*/ + /*Get the mixture of the original source and the neightboor pixels in both directions*/ + lv_color_t c_dest_int = lv_img_buf_get_px_color(img, xs_int, ys_int, color); + + if(lv_img_color_format_is_chroma_keyed(img->header.cf)) { + lv_color_t ct = LV_COLOR_TRANSP; + if(c_dest_int.full == ct.full) return false; + } + + lv_color_t c_dest_xn = lv_img_buf_get_px_color(img, xn, ys_int, color); + lv_color_t c_dest_yn = lv_img_buf_get_px_color(img, xs_int, yn, color); + + lv_color_t x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + lv_color_t y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); + *res_color = lv_color_mix(x_dest, y_dest, LV_OPA_50); + + /*Get result pixel opacity*/ + if(lv_img_color_format_has_alpha(img->header.cf)) { + lv_opa_t opa_int = lv_img_buf_get_px_alpha(img, xs_int, ys_int); + lv_opa_t opa_xn = lv_img_buf_get_px_alpha(img, xn, ys_int); + lv_opa_t opa_yn = lv_img_buf_get_px_alpha(img, xs_int, yn); + lv_opa_t opa_x = (opa_int * xr + (opa_xn * (255 - xr))) >> 8; + lv_opa_t opa_y = (opa_int * yr + (opa_yn * (255 - yr))) >> 8; + + *res_opa = (opa_x + opa_y) / 2; + if(*res_opa <= LV_OPA_MIN) return false; + } + + return true; +} + /** * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` * @param dsc pointer to an image descriptor @@ -350,7 +444,7 @@ void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_ void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c) { if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) || - (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) { + (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) { LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'"); return; } @@ -371,20 +465,20 @@ uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf) uint8_t px_size = 0; switch(cf) { - case LV_IMG_CF_UNKNOWN: - case LV_IMG_CF_RAW: px_size = 0; break; - case LV_IMG_CF_TRUE_COLOR: - case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: px_size = LV_COLOR_SIZE; break; - case LV_IMG_CF_TRUE_COLOR_ALPHA: px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3; break; - case LV_IMG_CF_INDEXED_1BIT: - case LV_IMG_CF_ALPHA_1BIT: px_size = 1; break; - case LV_IMG_CF_INDEXED_2BIT: - case LV_IMG_CF_ALPHA_2BIT: px_size = 2; break; - case LV_IMG_CF_INDEXED_4BIT: - case LV_IMG_CF_ALPHA_4BIT: px_size = 4; break; - case LV_IMG_CF_INDEXED_8BIT: - case LV_IMG_CF_ALPHA_8BIT: px_size = 8; break; - default: px_size = 0; break; + case LV_IMG_CF_UNKNOWN: + case LV_IMG_CF_RAW: px_size = 0; break; + case LV_IMG_CF_TRUE_COLOR: + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: px_size = LV_COLOR_SIZE; break; + case LV_IMG_CF_TRUE_COLOR_ALPHA: px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3; break; + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_ALPHA_1BIT: px_size = 1; break; + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_ALPHA_2BIT: px_size = 2; break; + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_ALPHA_4BIT: px_size = 4; break; + case LV_IMG_CF_INDEXED_8BIT: + case LV_IMG_CF_ALPHA_8BIT: px_size = 8; break; + default: px_size = 0; break; } return px_size; @@ -400,17 +494,17 @@ bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) bool is_chroma_keyed = false; switch(cf) { - case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: - case LV_IMG_CF_RAW_CHROMA_KEYED: + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: + case LV_IMG_CF_RAW_CHROMA_KEYED: #if LV_INDEXED_CHROMA - case LV_IMG_CF_INDEXED_1BIT: - case LV_IMG_CF_INDEXED_2BIT: - case LV_IMG_CF_INDEXED_4BIT: - case LV_IMG_CF_INDEXED_8BIT: + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_INDEXED_8BIT: #endif - is_chroma_keyed = true; break; + is_chroma_keyed = true; break; - default: is_chroma_keyed = false; break; + default: is_chroma_keyed = false; break; } return is_chroma_keyed; @@ -426,17 +520,17 @@ bool lv_img_color_format_has_alpha(lv_img_cf_t cf) bool has_alpha = false; switch(cf) { - case LV_IMG_CF_TRUE_COLOR_ALPHA: - case LV_IMG_CF_RAW_ALPHA: - case LV_IMG_CF_INDEXED_1BIT: - case LV_IMG_CF_INDEXED_2BIT: - case LV_IMG_CF_INDEXED_4BIT: - case LV_IMG_CF_INDEXED_8BIT: - case LV_IMG_CF_ALPHA_1BIT: - case LV_IMG_CF_ALPHA_2BIT: - case LV_IMG_CF_ALPHA_4BIT: - case LV_IMG_CF_ALPHA_8BIT: has_alpha = true; break; - default: has_alpha = false; break; + case LV_IMG_CF_TRUE_COLOR_ALPHA: + case LV_IMG_CF_RAW_ALPHA: + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_INDEXED_8BIT: + case LV_IMG_CF_ALPHA_1BIT: + case LV_IMG_CF_ALPHA_2BIT: + case LV_IMG_CF_ALPHA_4BIT: + case LV_IMG_CF_ALPHA_8BIT: has_alpha = true; break; + default: has_alpha = false; break; } return has_alpha; @@ -479,16 +573,16 @@ lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t)); if(dsc == NULL) return NULL; - + memset(dsc, 0, sizeof(lv_img_dsc_t)); - + /* Get image data size */ dsc->data_size = lv_img_buf_get_img_size(w, h, cf); if(dsc->data_size == 0) { lv_mem_free(dsc); return NULL; } - + /* Allocate raw buffer */ dsc->data = lv_mem_alloc(dsc->data_size); if(dsc->data == NULL) { @@ -496,7 +590,7 @@ lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) return NULL; } memset((uint8_t *)dsc->data, 0, dsc->data_size); - + /* Fill in header */ dsc->header.always_zero = 0; dsc->header.w = w; @@ -510,7 +604,7 @@ void lv_img_buf_free(lv_img_dsc_t *dsc) if(dsc != NULL) { if(dsc->data != NULL) lv_mem_free(dsc->data); - + lv_mem_free(dsc); } } @@ -518,18 +612,18 @@ void lv_img_buf_free(lv_img_dsc_t *dsc) uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) { switch(cf) { - case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); - case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); - case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); - case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); - case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); - case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); - case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); - case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); - case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); - case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); - case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); - default: return 0; + case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); + case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); + case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); + case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); + case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); + case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); + case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); + case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); + case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); + case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); + default: return 0; } } @@ -538,7 +632,7 @@ uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) **********************/ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, - const lv_style_t * style, lv_opa_t opa_scale) + const lv_style_t * style, lv_opa_t opa_scale) { lv_area_t mask_com; /*Common area of mask and coords*/ @@ -550,7 +644,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas } lv_opa_t opa = - opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t)style->image.opa * opa_scale) >> 8; + opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t)style->image.opa * opa_scale) >> 8; lv_img_cache_entry_t * cdsc = lv_img_cache_open(src, style); @@ -568,7 +662,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas * Just draw it!*/ else if(cdsc->dec_dsc.img_data) { lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style->image.color, - style->image.intense); + style->image.intense); } /* The whole uncompressed image is not available. Try to read it line-by-line*/ else { diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 794dd79e6..8e8088b00 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -69,17 +69,19 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * */ lv_img_src_t lv_img_src_get_type(const void * src); + /** * Get the color of an image's pixel * @param dsc an image descriptor * @param x x coordinate of the point to get * @param y x coordinate of the point to get - * @param style style of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` `style->image.color` shows - * the color. Can be `NULL` but for `ALPHA` images black will be returned. In other cases it is not - * used. + * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. + * Not used in other cases. * @return color of the point */ -lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, const lv_style_t * style); +lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color); + + /** * Get the alpha value of an image's pixel * @param dsc pointer to an image descriptor @@ -89,6 +91,9 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t */ lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y); + +bool lv_img_get_px_rotated(lv_img_dsc_t * img, uint16_t angle, lv_color_t color, lv_point_t * point, lv_point_t * pivot, lv_color_t * res_color, lv_opa_t * res_opa); + /** * Set the color of a pixel of an image. The alpha channel won't be affected. * @param dsc pointer to an image descriptor diff --git a/src/lv_objx/lv_canvas.c b/src/lv_objx/lv_canvas.c index 453b06a86..28924f41f 100644 --- a/src/lv_objx/lv_canvas.c +++ b/src/lv_objx/lv_canvas.c @@ -197,7 +197,9 @@ lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y) lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); const lv_style_t * style = lv_canvas_get_style(canvas, LV_CANVAS_STYLE_MAIN); - return lv_img_buf_get_px_color(&ext->dsc, x, y, style); + if(style == NULL) style = &lv_style_scr; + + return lv_img_buf_get_px_color(&ext->dsc, x, y, style->image.color); } /** @@ -291,115 +293,37 @@ void lv_canvas_rotate(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, lv_c lv_canvas_ext_t * ext_dst = lv_obj_get_ext_attr(canvas); const lv_style_t * style = lv_canvas_get_style(canvas, LV_CANVAS_STYLE_MAIN); - int32_t sinma = lv_trigo_sin(-angle); - int32_t cosma = lv_trigo_sin(-angle + 90); /* cos */ - int32_t img_width = img->header.w; - int32_t img_height = img->header.h; int32_t dest_width = ext_dst->dsc.header.w; int32_t dest_height = ext_dst->dsc.header.h; int32_t x; int32_t y; + lv_point_t point_p; + + lv_point_t pivot_p; + pivot_p.x = pivot_x; + pivot_p.y = pivot_y; + + lv_color_t color_res; + lv_opa_t opa_res; + + bool ret; + for(x = -offset_x; x < dest_width - offset_x; x++) { for(y = -offset_y; y < dest_height - offset_y; y++) { - /*Get the target point relative coordinates to the pivot*/ - int32_t xt = x - pivot_x; - int32_t yt = y - pivot_y; + point_p.x = x; + point_p.y = y; - /*Get the source pixel from the upscaled image*/ - int32_t xs = ((cosma * xt - sinma * yt) >> (LV_TRIGO_SHIFT - 8)) + pivot_x * 256; - int32_t ys = ((sinma * xt + cosma * yt) >> (LV_TRIGO_SHIFT - 8)) + pivot_y * 256; - - /*Get the integer part of the source pixel*/ - int xs_int = xs >> 8; - int ys_int = ys >> 8; - - if(xs_int >= img_width) - continue; - else if(xs_int < 0) - continue; - - if(ys_int >= img_height) - continue; - else if(ys_int < 0) - continue; - - /*Get the fractional part of the source pixel*/ - int xs_fract = xs & 0xff; - int ys_fract = ys & 0xff; - - /* If the fractional < 0x70 mix the source pixel with the left/top pixel - * If the fractional > 0x90 mix the source pixel with the right/bottom pixel - * In the 0x70..0x90 range use the unchanged source pixel */ - - int xn; /*x neightboor*/ - lv_opa_t xr; /*x mix ratio*/ - if(xs_fract < 0x70) { - xn = xs_int - 1; - xr = xs_fract * 2; - } else if(xs_fract > 0x90) { - xn = xs_int + 1; - xr = (0xFF - xs_fract) * 2; - } else { - xn = xs_int; - xr = 0xFF; - } - - /*Handle under/overflow*/ - if(xn >= img_width) - continue; - else if(xn < 0) - continue; - - int yn; /*y neightboor*/ - lv_opa_t yr; /*y mix ratio*/ - if(ys_fract < 0x70) { - yn = ys_int - 1; - yr = ys_fract * 2; - } else if(ys_fract > 0x90) { - yn = ys_int + 1; - yr = (0xFF - ys_fract) * 2; - } else { - yn = ys_int; - yr = 0xFF; - } - - /*Handle under/overflow*/ - if(yn >= img_height) - continue; - else if(yn < 0) - continue; - - /*Get the mixture of the original source and the neightboor pixels in both directions*/ - lv_color_t c_dest_int = lv_img_buf_get_px_color(img, xs_int, ys_int, style); - - if(lv_img_color_format_is_chroma_keyed(img->header.cf)) { - lv_color_t ct = LV_COLOR_TRANSP; - if(c_dest_int.full == ct.full) continue; - } - - lv_color_t c_dest_xn = lv_img_buf_get_px_color(img, xn, ys_int, style); - lv_color_t c_dest_yn = lv_img_buf_get_px_color(img, xs_int, yn, style); - lv_color_t x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); - lv_color_t y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); - lv_color_t color_res = lv_color_mix(x_dest, y_dest, LV_OPA_50); + ret = lv_img_get_px_rotated(img, angle, style->image.color, &point_p, &pivot_p, &color_res, &opa_res); + if(ret == false) continue; if(x + offset_x >= 0 && x + offset_x < dest_width && y + offset_y >= 0 && y + offset_y < dest_height) { /*If the image has no alpha channel just simple set the result color on the canvas*/ if(lv_img_color_format_has_alpha(img->header.cf) == false) { lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, color_res); } else { - /*Get result pixel opacity*/ - lv_opa_t opa_int = lv_img_buf_get_px_alpha(img, xs_int, ys_int); - lv_opa_t opa_xn = lv_img_buf_get_px_alpha(img, xn, ys_int); - lv_opa_t opa_yn = lv_img_buf_get_px_alpha(img, xs_int, yn); - lv_opa_t opa_x = (opa_int * xr + (opa_xn * (255 - xr))) >> 8; - lv_opa_t opa_y = (opa_int * yr + (opa_yn * (255 - yr))) >> 8; - lv_opa_t opa_res = (opa_x + opa_y) / 2; - if(opa_res <= LV_OPA_MIN) continue; - - lv_color_t bg_color = lv_img_buf_get_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, style); + lv_color_t bg_color = lv_img_buf_get_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, style->image.color); /*If the canvas has no alpha but the image has mix the image's color with * canvas*/ From 40f2586a5433d986ba5cf29af87f63941f432bfa Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 1 Nov 2019 11:09:56 +0100 Subject: [PATCH 02/12] add lv_api_map.h and rename lv_chart_get_point_cnt to lv_chart_get_point_count --- src/lv_api_map.h | 43 ++++++++++++++++++++++++++++++++++++++++++ src/lv_objx/lv_chart.c | 2 +- src/lv_objx/lv_chart.h | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/lv_api_map.h diff --git a/src/lv_api_map.h b/src/lv_api_map.h new file mode 100644 index 000000000..b1b638093 --- /dev/null +++ b/src/lv_api_map.h @@ -0,0 +1,43 @@ +/** + * @file lv_api_map.h + * + */ + +#ifndef LV_API_MAP_H +#define LV_API_MAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*--------------------- + * V6.0 COMPATIBILITY + *--------------------*/ +#define lv_chart_get_point_count lv_chart_get_point_cnt + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_API_MAP_H*/ diff --git a/src/lv_objx/lv_chart.c b/src/lv_objx/lv_chart.c index 2782ba68f..8d5ffaad0 100644 --- a/src/lv_objx/lv_chart.c +++ b/src/lv_objx/lv_chart.c @@ -633,7 +633,7 @@ lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart) * @param chart pointer to chart object * @return point number on each data line */ -uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart) +uint16_t lv_chart_get_point_count(const lv_obj_t * chart) { LV_ASSERT_OBJ(chart, LV_OBJX_NAME); diff --git a/src/lv_objx/lv_chart.h b/src/lv_objx/lv_chart.h index fc611f811..e775970f9 100644 --- a/src/lv_objx/lv_chart.h +++ b/src/lv_objx/lv_chart.h @@ -331,7 +331,7 @@ lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart); * @param chart pointer to chart object * @return point number on each data line */ -uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart); +uint16_t lv_chart_get_point_count(const lv_obj_t * chart); /** * Get the opacity of the data series From 82e2d53763361b42daf07e4c922fee5c50024205 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 1 Nov 2019 11:10:26 +0100 Subject: [PATCH 03/12] img_draw angle testing --- src/lv_draw/lv_draw_img.c | 28 ++++++++++++++++++++-------- src/lv_objx/lv_img.c | 3 ++- src/lv_objx/lv_img.h | 1 + 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 8156f8bd9..d8a57b477 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -740,7 +740,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, uint8_t other_mask_cnt = lv_draw_mask_get_cnt(); /*The simplest case just copy the pixels into the VDB*/ - if(other_mask_cnt == 0 && chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && style->image.intense == LV_OPA_TRANSP) { + if(0 && other_mask_cnt == 0 && chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && style->image.intense == LV_OPA_TRANSP) { lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, LV_OPA_COVER, style->image.blend_mode); } /*In the other cases every pixel need to be checked one-by-one*/ @@ -748,10 +748,8 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, /*The pixel size in byte is different if an alpha byte is added too*/ uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t); - - /*Build the image and a mask line-by-line*/ - uint32_t mask_buf_size = lv_area_get_size(&draw_area) > LV_HOR_RES_MAX ? lv_area_get_size(&draw_area) : LV_HOR_RES_MAX; + uint32_t mask_buf_size = lv_area_get_size(&draw_area) > LV_HOR_RES_MAX ? LV_HOR_RES_MAX : lv_area_get_size(&draw_area); lv_color_t * map2 = lv_draw_buf_get(mask_buf_size * sizeof(lv_color_t)); lv_opa_t * mask_buf = lv_draw_buf_get(mask_buf_size); @@ -779,8 +777,10 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, memset(mask_buf, 0xFF, mask_buf_size); } + uint16_t angle = 30; + lv_draw_mask_res_t mask_res; - mask_res = (alpha_byte || chroma_key) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; + mask_res = (alpha_byte || chroma_key || angle) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; lv_coord_t x; lv_coord_t y; for(y = 0; y < lv_area_get_height(&draw_area); y++) { @@ -804,6 +804,20 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, c.full = *((uint32_t*)map_px); #endif + lv_img_dsc_t img; + img.data = map_p; + img.header.w = lv_area_get_width(map_area); + img.header.h = lv_area_get_height(map_area); + img.header.cf = LV_IMG_CF_TRUE_COLOR; + lv_point_t p = {x + disp_area->x1 - map_area->x1 ,y + disp_area->y1 - map_area->y1}; + lv_point_t piv = {img.header.w / 2 ,img.header.h / 2}; + bool ret; + ret = lv_img_get_px_rotated(&img, angle, LV_COLOR_BLACK, &p, &piv, &c, NULL); + if(ret == false) { + mask_buf[px_i] = LV_OPA_TRANSP; + continue; + } + if (chroma_key) { if(c.full == chroma_keyed_color.full) { mask_buf[px_i] = LV_OPA_TRANSP; @@ -840,7 +854,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, blend_area.y2 = blend_area.y1; px_i = 0; - mask_res = (alpha_byte || chroma_key) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; + mask_res = (alpha_byte || chroma_key || angle) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; /*Prepare the `mask_buf`if there are other masks*/ if(other_mask_cnt) { @@ -857,6 +871,4 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, lv_draw_buf_release(mask_buf); lv_draw_buf_release(map2); } - - } diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index 05912a511..817cc0fe1 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -78,6 +78,7 @@ lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy) ext->cf = LV_IMG_CF_UNKNOWN; ext->w = lv_obj_get_width(new_img); ext->h = lv_obj_get_height(new_img); + ext->angle = 30; ext->auto_size = 1; ext->offset.x = 0; ext->offset.y = 0; @@ -351,7 +352,7 @@ static lv_design_res_t lv_img_design(lv_obj_t * img, const lv_area_t * clip_area if(mode == LV_DESIGN_COVER_CHK) { lv_design_res_t cover = LV_DESIGN_RES_NOT_COVER; - if(ext->src_type == LV_IMG_SRC_UNKNOWN || ext->src_type == LV_IMG_SRC_SYMBOL) return LV_DESIGN_RES_NOT_COVER; + if(ext->src_type == LV_IMG_SRC_UNKNOWN || ext->src_type == LV_IMG_SRC_SYMBOL || ext->angle != 0) return LV_DESIGN_RES_NOT_COVER; if(ext->cf == LV_IMG_CF_TRUE_COLOR || ext->cf == LV_IMG_CF_RAW) { cover = lv_area_is_in(clip_area, &img->coords) ? LV_DESIGN_RES_COVER : LV_DESIGN_RES_NOT_COVER; diff --git a/src/lv_objx/lv_img.h b/src/lv_objx/lv_img.h index d1e14d209..8417ad72d 100644 --- a/src/lv_objx/lv_img.h +++ b/src/lv_objx/lv_img.h @@ -42,6 +42,7 @@ typedef struct lv_point_t offset; lv_coord_t w; /*Width of the image (Handled by the library)*/ lv_coord_t h; /*Height of the image (Handled by the library)*/ + uint16_t angle; uint8_t src_type : 2; /*See: lv_img_src_t*/ uint8_t auto_size : 1; /*1: automatically set the object size to the image size*/ uint8_t cf : 5; /*Color format from `lv_img_color_format_t`*/ From 1ae214a2ded8d2ef5ce6cd8addd8a9c7cb7478aa Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 1 Nov 2019 20:17:11 +0100 Subject: [PATCH 04/12] img rotate optimization --- src/lv_draw/lv_draw_img.c | 126 +++++++++++++++++++++++--------------- src/lv_draw/lv_draw_img.h | 26 +++++++- src/lv_objx/lv_canvas.c | 34 +++++----- 3 files changed, 116 insertions(+), 70 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index d8a57b477..4457ecc9f 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -339,28 +339,49 @@ void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_ } } -bool lv_img_get_px_rotated(lv_img_dsc_t * img, uint16_t angle, lv_color_t color, lv_point_t * point, lv_point_t * pivot, lv_color_t * res_color, lv_opa_t * res_opa) -{ - int32_t sinma = lv_trigo_sin(-angle); - int32_t cosma = lv_trigo_sin(-angle + 90); /* cos */ +void lv_img_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * src, lv_coord_t src_w, lv_coord_t src_h, + lv_img_cf_t cf, lv_coord_t pivot_x, lv_coord_t pivot_y, lv_color_t color) +{ + memset(dsc, 0x00, sizeof(lv_img_rotate_dsc_t)); + + dsc->angle = angle; + dsc->src = src; + dsc->src_w = src_w; + dsc->src_h = src_h; + dsc->cf = cf; + dsc->color = color; + dsc->pivot_x = pivot_x; + dsc->pivot_y = pivot_y; + dsc->pivot_x_256 = pivot_x * 256; + dsc->pivot_y_256 = pivot_y * 256; + dsc->sinma = lv_trigo_sin(-angle); + dsc->cosma = lv_trigo_sin(-angle + 90); + + dsc->chroma_keyed = lv_img_color_format_is_chroma_keyed(cf) ? 1 : 0; + dsc->has_alpha = lv_img_color_format_has_alpha(cf) ? 1 : 0; +} + +bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y) +{ + const uint8_t * src_u8 = dsc->src; /*Get the target point relative coordinates to the pivot*/ - int32_t xt = point->x - pivot->x; - int32_t yt = point->y - pivot->y; + int32_t xt = x - dsc->pivot_x; + int32_t yt = y - dsc->pivot_y; /*Get the source pixel from the upscaled image*/ - int32_t xs = ((cosma * xt - sinma * yt) >> (LV_TRIGO_SHIFT - 8)) + pivot->x * 256; - int32_t ys = ((sinma * xt + cosma * yt) >> (LV_TRIGO_SHIFT - 8)) + pivot->y * 256; + int32_t xs = ((dsc->cosma * xt - dsc->sinma * yt) >> (LV_TRIGO_SHIFT - 8)) + dsc->pivot_x_256; + int32_t ys = ((dsc->sinma * xt + dsc->cosma * yt) >> (LV_TRIGO_SHIFT - 8)) + dsc->pivot_y_256; /*Get the integer part of the source pixel*/ int xs_int = xs >> 8; int ys_int = ys >> 8; - if(xs_int >= img->header.w) return false; + if(xs_int >= dsc->src_w) return false; else if(xs_int < 0) return false; - if(ys_int >= img->header.h) return false; + if(ys_int >= dsc->src_h) return false; else if(ys_int < 0) return false; /*Get the fractional part of the source pixel*/ @@ -371,66 +392,73 @@ bool lv_img_get_px_rotated(lv_img_dsc_t * img, uint16_t angle, lv_color_t color, * If the fractional > 0x90 mix the source pixel with the right/bottom pixel * In the 0x70..0x90 range use the unchanged source pixel */ + lv_color_t c_dest_int; + lv_color_t c_dest_xn; + lv_color_t c_dest_yn; + + uint8_t px_size = LV_COLOR_SIZE >> 3; + uint32_t px = dsc->src_w * ys_int * px_size + xs_int * px_size; + memcpy(&c_dest_int, &src_u8[px], px_size); + int xn; /*x neightboor*/ lv_opa_t xr; /*x mix ratio*/ if(xs_fract < 0x70) { xn = xs_int - 1; - xr = xs_fract * 2; + if(xn < 0) return false; + memcpy(&c_dest_xn, &src_u8[px - px_size], px_size); + xr = xs_fract + 0x80; } else if(xs_fract > 0x90) { xn = xs_int + 1; - xr = (0xFF - xs_fract) * 2; + if(xn >= dsc->src_w) return false; + memcpy(&c_dest_xn, &src_u8[px + px_size], px_size); + + xr = (0xFF - xs_fract) + 0x80; } else { xn = xs_int; xr = 0xFF; } - /*Handle under/overflow*/ - if(xn >= img->header.w) return false; - else if(xn < 0) return false; - int yn; /*y neightboor*/ lv_opa_t yr; /*y mix ratio*/ if(ys_fract < 0x70) { yn = ys_int - 1; - yr = ys_fract * 2; + if(yn < 0) return false; + memcpy(&c_dest_yn, &src_u8[px - px_size * dsc->src_w], px_size); + + yr = ys_fract + 0x80; } else if(ys_fract > 0x90) { yn = ys_int + 1; - yr = (0xFF - ys_fract) * 2; + if(yn >= dsc->src_h) return false; + memcpy(&c_dest_yn, &src_u8[px + px_size * dsc->src_w], px_size); + yr = (0xFF - ys_fract) + 0x80; } else { yn = ys_int; yr = 0xFF; } - /*Handle under/overflow*/ - if(yn >= img->header.h) return false; - else if(yn < 0) return false; /*Get the mixture of the original source and the neightboor pixels in both directions*/ - /*Get the mixture of the original source and the neightboor pixels in both directions*/ - lv_color_t c_dest_int = lv_img_buf_get_px_color(img, xs_int, ys_int, color); - if(lv_img_color_format_is_chroma_keyed(img->header.cf)) { + if(dsc->chroma_keyed) { lv_color_t ct = LV_COLOR_TRANSP; if(c_dest_int.full == ct.full) return false; } - lv_color_t c_dest_xn = lv_img_buf_get_px_color(img, xn, ys_int, color); - lv_color_t c_dest_yn = lv_img_buf_get_px_color(img, xs_int, yn, color); lv_color_t x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); lv_color_t y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); - *res_color = lv_color_mix(x_dest, y_dest, LV_OPA_50); + dsc->res_color = lv_color_mix(x_dest, y_dest, LV_OPA_50); /*Get result pixel opacity*/ - if(lv_img_color_format_has_alpha(img->header.cf)) { - lv_opa_t opa_int = lv_img_buf_get_px_alpha(img, xs_int, ys_int); - lv_opa_t opa_xn = lv_img_buf_get_px_alpha(img, xn, ys_int); - lv_opa_t opa_yn = lv_img_buf_get_px_alpha(img, xs_int, yn); - lv_opa_t opa_x = (opa_int * xr + (opa_xn * (255 - xr))) >> 8; - lv_opa_t opa_y = (opa_int * yr + (opa_yn * (255 - yr))) >> 8; - - *res_opa = (opa_x + opa_y) / 2; - if(*res_opa <= LV_OPA_MIN) return false; + if(dsc->has_alpha) { +// lv_opa_t opa_int = lv_img_buf_get_px_alpha(img, xs_int, ys_int); +// lv_opa_t opa_xn = lv_img_buf_get_px_alpha(img, xn, ys_int); +// lv_opa_t opa_yn = lv_img_buf_get_px_alpha(img, xs_int, yn); +// lv_opa_t opa_x = (opa_int * xr + (opa_xn * (255 - xr))) >> 8; +// lv_opa_t opa_y = (opa_int * yr + (opa_yn * (255 - yr))) >> 8; +// +// dsc->res_opa = (opa_x + opa_y) / 2; +// if(dsc->res_opa <= LV_OPA_MIN) return false; } return true; @@ -804,19 +832,19 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, c.full = *((uint32_t*)map_px); #endif - lv_img_dsc_t img; - img.data = map_p; - img.header.w = lv_area_get_width(map_area); - img.header.h = lv_area_get_height(map_area); - img.header.cf = LV_IMG_CF_TRUE_COLOR; - lv_point_t p = {x + disp_area->x1 - map_area->x1 ,y + disp_area->y1 - map_area->y1}; - lv_point_t piv = {img.header.w / 2 ,img.header.h / 2}; - bool ret; - ret = lv_img_get_px_rotated(&img, angle, LV_COLOR_BLACK, &p, &piv, &c, NULL); - if(ret == false) { - mask_buf[px_i] = LV_OPA_TRANSP; - continue; - } +// lv_img_dsc_t img; +// img.data = map_p; +// img.header.w = lv_area_get_width(map_area); +// img.header.h = lv_area_get_height(map_area); +// img.header.cf = LV_IMG_CF_TRUE_COLOR; +// lv_point_t p = {x + disp_area->x1 - map_area->x1 ,y + disp_area->y1 - map_area->y1}; +// lv_point_t piv = {img.header.w / 2 ,img.header.h / 2}; +// bool ret; +// ret = lv_img_get_px_rotated(&img, angle, LV_COLOR_BLACK, &p, &piv, &c, NULL); +// if(ret == false) { +// mask_buf[px_i] = LV_OPA_TRANSP; +// continue; +// } if (chroma_key) { if(c.full == chroma_keyed_color.full) { diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 8e8088b00..c2ebc371f 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -43,6 +43,27 @@ extern "C" { /********************** * TYPEDEFS **********************/ +typedef struct { + lv_color_t res_color; + lv_opa_t res_opa; + + const void * src; + lv_coord_t src_w; + lv_coord_t src_h; + lv_coord_t pivot_x; + lv_coord_t pivot_y; + lv_coord_t pivot_x_256; + lv_coord_t pivot_y_256; + int32_t sinma; + int32_t cosma; + int16_t angle; + lv_color_t color; + lv_img_cf_t cf; + + uint8_t chroma_keyed :1; + uint8_t has_alpha :1; + +}lv_img_rotate_dsc_t; /********************** * GLOBAL PROTOTYPES @@ -92,7 +113,10 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y); -bool lv_img_get_px_rotated(lv_img_dsc_t * img, uint16_t angle, lv_color_t color, lv_point_t * point, lv_point_t * pivot, lv_color_t * res_color, lv_opa_t * res_opa); +void lv_img_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * src, lv_coord_t src_w, lv_coord_t src_h, + lv_img_cf_t cf, lv_coord_t pivot_x, lv_coord_t pivot_y, lv_color_t color); + +bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y); /** * Set the color of a pixel of an image. The alpha channel won't be affected. diff --git a/src/lv_objx/lv_canvas.c b/src/lv_objx/lv_canvas.c index 73e0ea92f..613fdf2e6 100644 --- a/src/lv_objx/lv_canvas.c +++ b/src/lv_objx/lv_canvas.c @@ -322,35 +322,29 @@ void lv_canvas_rotate(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, lv_c int32_t y; lv_point_t point_p; - lv_point_t pivot_p; - pivot_p.x = pivot_x; - pivot_p.y = pivot_y; - - lv_color_t color_res; - lv_opa_t opa_res; - bool ret; + lv_img_rotate_dsc_t dsc; + lv_img_rotate_init(&dsc, angle, img->data, img->header.w, img->header.h, img->header.cf, pivot_x, pivot_y, style->image.color); + for(x = -offset_x; x < dest_width - offset_x; x++) { for(y = -offset_y; y < dest_height - offset_y; y++) { - point_p.x = x; - point_p.y = y; - ret = lv_img_get_px_rotated(img, angle, style->image.color, &point_p, &pivot_p, &color_res, &opa_res); + ret = lv_img_get_px_rotated(&dsc, x, y); if(ret == false) continue; if(x + offset_x >= 0 && x + offset_x < dest_width && y + offset_y >= 0 && y + offset_y < dest_height) { /*If the image has no alpha channel just simple set the result color on the canvas*/ if(lv_img_color_format_has_alpha(img->header.cf) == false) { - lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, color_res); + lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, dsc.res_color); } else { lv_color_t bg_color = lv_img_buf_get_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, style->image.color); /*If the canvas has no alpha but the image has mix the image's color with * canvas*/ if(lv_img_color_format_has_alpha(ext_dst->dsc.header.cf) == false) { - if(opa_res < LV_OPA_MAX) color_res = lv_color_mix(color_res, bg_color, opa_res); - lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, color_res); + if(dsc.res_opa < LV_OPA_MAX) dsc.res_color = lv_color_mix(dsc.res_color, bg_color, dsc.res_opa); + lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, dsc.res_color); } /*Both the image and canvas has alpha channel. Some extra calculation is required*/ @@ -358,28 +352,28 @@ void lv_canvas_rotate(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, lv_c lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&ext_dst->dsc, x + offset_x, y + offset_y); /* Pick the foreground if it's fully opaque or the Background is fully * transparent*/ - if(opa_res >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) { - lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, color_res); - lv_img_buf_set_px_alpha(&ext_dst->dsc, x + offset_x, y + offset_y, opa_res); + if(dsc.res_opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) { + lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, dsc.res_color); + lv_img_buf_set_px_alpha(&ext_dst->dsc, x + offset_x, y + offset_y, dsc.res_opa); } /*Opaque background: use simple mix*/ else if(bg_opa >= LV_OPA_MAX) { lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, - lv_color_mix(color_res, bg_color, opa_res)); + lv_color_mix(dsc.res_color, bg_color, dsc.res_opa)); } /*Both colors have alpha. Expensive calculation need to be applied*/ else { /*Info: * https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/ - lv_opa_t opa_res_2 = 255 - ((uint16_t)((uint16_t)(255 - opa_res) * (255 - bg_opa)) >> 8); + lv_opa_t opa_res_2 = 255 - ((uint16_t)((uint16_t)(255 - dsc.res_opa) * (255 - bg_opa)) >> 8); if(opa_res_2 == 0) { opa_res_2 = 1; /*never happens, just to be sure*/ } - lv_opa_t ratio = (uint16_t)((uint16_t)opa_res * 255) / opa_res_2; + lv_opa_t ratio = (uint16_t)((uint16_t)dsc.res_opa * 255) / opa_res_2; lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, - lv_color_mix(color_res, bg_color, ratio)); + lv_color_mix(dsc.res_color, bg_color, ratio)); lv_img_buf_set_px_alpha(&ext_dst->dsc, x + offset_x, y + offset_y, opa_res_2); } } From 1458828b97fdcbbda7bd1168ba62db18e4333c90 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 1 Nov 2019 20:26:39 +0100 Subject: [PATCH 05/12] img rotation fixes --- src/lv_draw/lv_draw_img.c | 42 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 4457ecc9f..a6cbf42f4 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -393,47 +393,66 @@ bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y * In the 0x70..0x90 range use the unchanged source pixel */ lv_color_t c_dest_int; - lv_color_t c_dest_xn; - lv_color_t c_dest_yn; uint8_t px_size = LV_COLOR_SIZE >> 3; uint32_t px = dsc->src_w * ys_int * px_size + xs_int * px_size; memcpy(&c_dest_int, &src_u8[px], px_size); - int xn; /*x neightboor*/ - lv_opa_t xr; /*x mix ratio*/ + + lv_color_t x_dest; + lv_color_t y_dest; + if(xs_fract < 0x70) { + int32_t xn; /*x neightboor*/ xn = xs_int - 1; if(xn < 0) return false; + + lv_color_t c_dest_xn; memcpy(&c_dest_xn, &src_u8[px - px_size], px_size); + + lv_opa_t xr; /*x mix ratio*/ xr = xs_fract + 0x80; + x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + } else if(xs_fract > 0x90) { + int32_t xn; /*x neightboor*/ xn = xs_int + 1; if(xn >= dsc->src_w) return false; + + lv_color_t c_dest_xn; memcpy(&c_dest_xn, &src_u8[px + px_size], px_size); + lv_opa_t xr; /*x mix ratio*/ xr = (0xFF - xs_fract) + 0x80; + x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); } else { - xn = xs_int; - xr = 0xFF; + x_dest.full = c_dest_int.full; } - int yn; /*y neightboor*/ - lv_opa_t yr; /*y mix ratio*/ if(ys_fract < 0x70) { + int32_t yn; /*y neightboor*/ yn = ys_int - 1; if(yn < 0) return false; + lv_color_t c_dest_yn; memcpy(&c_dest_yn, &src_u8[px - px_size * dsc->src_w], px_size); + lv_opa_t yr; /*y mix ratio*/ yr = ys_fract + 0x80; + y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); + } else if(ys_fract > 0x90) { + int32_t yn; /*y neightboor*/ yn = ys_int + 1; if(yn >= dsc->src_h) return false; + + lv_color_t c_dest_yn; memcpy(&c_dest_yn, &src_u8[px + px_size * dsc->src_w], px_size); + + lv_opa_t yr; /*y mix ratio*/ yr = (0xFF - ys_fract) + 0x80; + y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); } else { - yn = ys_int; - yr = 0xFF; + y_dest.full = c_dest_int.full; } @@ -444,9 +463,6 @@ bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y if(c_dest_int.full == ct.full) return false; } - - lv_color_t x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); - lv_color_t y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); dsc->res_color = lv_color_mix(x_dest, y_dest, LV_OPA_50); /*Get result pixel opacity*/ From a1d84e579244820cf6438a06d3c9114f3af4b15e Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 1 Nov 2019 20:32:16 +0100 Subject: [PATCH 06/12] img rotate further optimiziation --- src/lv_draw/lv_draw_img.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 4457ecc9f..e0599b403 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -416,6 +416,7 @@ bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y } else { xn = xs_int; xr = 0xFF; + c_dest_xn.full = c_dest_int.full; } int yn; /*y neightboor*/ @@ -434,6 +435,7 @@ bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y } else { yn = ys_int; yr = 0xFF; + c_dest_yn.full = c_dest_int.full; } From 2b955ac8b67952bbfa93a77c1c61cb8161a66b9a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 2 Nov 2019 08:51:38 +0100 Subject: [PATCH 07/12] img run-time rotate functionally working --- src/lv_draw/lv_draw_img.c | 43 ++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index a6cbf42f4..0fcd9781c 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -757,15 +757,25 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, const lv_style_t * style) { + + uint16_t angle = 30; if(opa < LV_OPA_MIN) return; if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; lv_area_t draw_area; bool union_ok; + lv_area_t map_area_rot; + lv_area_copy(&map_area_rot, map_area); + if(angle) { + map_area_rot.x1 -= 50; + map_area_rot.y1 -= 50; + map_area_rot.x2 += 50; + map_area_rot.y2 += 50; + } /* Get clipped map area which is the real draw area. * It is always the same or inside `map_area` */ - union_ok = lv_area_intersect(&draw_area, map_area, clip_area); + union_ok = lv_area_intersect(&draw_area, &map_area_rot, clip_area); /*If there are common part of the three area then draw to the vdb*/ if(union_ok == false) return; @@ -784,7 +794,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, uint8_t other_mask_cnt = lv_draw_mask_get_cnt(); /*The simplest case just copy the pixels into the VDB*/ - if(0 && other_mask_cnt == 0 && chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && style->image.intense == LV_OPA_TRANSP) { + if(angle == 0 && other_mask_cnt == 0 && chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && style->image.intense == LV_OPA_TRANSP) { lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, LV_OPA_COVER, style->image.blend_mode); } /*In the other cases every pixel need to be checked one-by-one*/ @@ -799,6 +809,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, /*Go to the first displayed pixel of the map*/ lv_coord_t map_w = lv_area_get_width(map_area); + lv_coord_t map_h = lv_area_get_height(map_area); const uint8_t * map_buf_tmp = map_p; map_buf_tmp += map_w * (draw_area.y1 - (map_area->y1 - disp_area->y1)) * px_size_byte; map_buf_tmp += (draw_area.x1 - (map_area->x1 - disp_area->x1)) * px_size_byte; @@ -821,7 +832,9 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, memset(mask_buf, 0xFF, mask_buf_size); } - uint16_t angle = 30; + + lv_img_rotate_dsc_t rotate_dsc; + lv_img_rotate_init(&rotate_dsc, angle, map_p, map_w, map_h, LV_IMG_CF_TRUE_COLOR, map_w/2, map_h / 2, LV_COLOR_BLACK); lv_draw_mask_res_t mask_res; mask_res = (alpha_byte || chroma_key || angle) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; @@ -848,19 +861,17 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, c.full = *((uint32_t*)map_px); #endif -// lv_img_dsc_t img; -// img.data = map_p; -// img.header.w = lv_area_get_width(map_area); -// img.header.h = lv_area_get_height(map_area); -// img.header.cf = LV_IMG_CF_TRUE_COLOR; -// lv_point_t p = {x + disp_area->x1 - map_area->x1 ,y + disp_area->y1 - map_area->y1}; -// lv_point_t piv = {img.header.w / 2 ,img.header.h / 2}; -// bool ret; -// ret = lv_img_get_px_rotated(&img, angle, LV_COLOR_BLACK, &p, &piv, &c, NULL); -// if(ret == false) { -// mask_buf[px_i] = LV_OPA_TRANSP; -// continue; -// } + bool ret; + lv_coord_t rot_x = x + (disp_area->x1 + draw_area.x1) - map_area->x1; + lv_coord_t rot_y = y + (disp_area->y1 + draw_area.y1) - map_area->y1; + ret = lv_img_get_px_rotated(&rotate_dsc, rot_x, rot_y); + if(ret == false) { + mask_buf[px_i] = LV_OPA_TRANSP; + continue; + } else { +// mask_buf[px_i] = rotate_dsc.res_opa; + c.full = rotate_dsc.res_color.full; + } if (chroma_key) { if(c.full == chroma_keyed_color.full) { From abfe2f63a1687995c379a8db19f08c2d2916880f Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 2 Nov 2019 21:30:51 +0100 Subject: [PATCH 08/12] img rotate auto set ext draw pad --- src/lv_core/lv_refr.c | 7 ++++++- src/lv_objx/lv_img.c | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/lv_core/lv_refr.c b/src/lv_core/lv_refr.c index 45fd0bf05..f9ae21504 100644 --- a/src/lv_core/lv_refr.c +++ b/src/lv_core/lv_refr.c @@ -525,7 +525,12 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) #if MASK_AREA_DEBUG static lv_color_t debug_color = LV_COLOR_RED; - lv_draw_fill(&obj_ext_mask, &obj_ext_mask, debug_color, LV_OPA_50); + LV_STYLE_CREATE(style_debug, &lv_style_plain); + style_debug.body.main_color = debug_color; + style_debug.body.grad_color = debug_color; + style_debug.body.border.width = 2; + style_debug.body.border.color.full = (debug_color.full + 0x13) * 9; + lv_draw_rect(&obj_ext_mask, &obj_ext_mask, &style_debug, LV_OPA_50); debug_color.full *= 17; debug_color.full += 0xA1; #endif diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index 817cc0fe1..d3505125a 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -19,6 +19,7 @@ #include "../lv_draw/lv_img_decoder.h" #include "../lv_misc/lv_fs.h" #include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" #include "../lv_misc/lv_log.h" /********************* @@ -200,6 +201,9 @@ void lv_img_set_src(lv_obj_t * img, const void * src_img) lv_obj_set_size(img, ext->w, ext->h); } + /*Provide enough room for the rotated corners*/ + if(ext->angle) lv_obj_refresh_ext_draw_pad(img); + lv_obj_invalidate(img); } @@ -254,6 +258,17 @@ void lv_img_set_offset_y(lv_obj_t * img, lv_coord_t y) } } +void lv_img_set_angle(lv_obj_t * img, int16_t angle) +{ + if(angle < 0 || angle >= 360) angle = angle % 360; + + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + ext->angle = angle; + lv_obj_refresh_ext_draw_pad(img); + lv_obj_invalidate(img); + +} + /*===================== * Getter functions *====================*/ @@ -427,6 +442,17 @@ static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param) if(ext->src_type == LV_IMG_SRC_SYMBOL) { lv_img_set_src(img, ext->src); } + } else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) { + /*If the image has angle provide enough room for the rotated corners */ + if(ext->angle) { + lv_sqrt_res_t ds; + lv_sqrt(ext->w * ext->w + ext->h * ext->h, &ds); + printf("%d %d %d\n", ext->w, ext->h, ds.i); + + lv_coord_t d = (ds.i - LV_MATH_MIN(ext->w, ext->h)) / 2; + + img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, d); + } } return res; From 722820ee5638902b77c75b56e7161195d054d41a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sun, 3 Nov 2019 07:13:14 +0100 Subject: [PATCH 09/12] img rotate: add support all color formats --- src/lv_draw/lv_draw_img.c | 288 +++++++++++++++++++++++--------------- src/lv_draw/lv_draw_img.h | 4 +- src/lv_objx/lv_canvas.c | 2 +- src/lv_objx/lv_img.c | 4 +- src/lv_objx/lv_imgbtn.c | 2 +- 5 files changed, 185 insertions(+), 115 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 0fcd9781c..0876b7316 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -26,10 +26,10 @@ * STATIC PROTOTYPES **********************/ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, - const lv_style_t * style, lv_opa_t opa_scale); + const lv_style_t * style, uint16_t angle, lv_opa_t opa_scale); static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, const uint8_t * map_p, lv_opa_t opa, - bool chroma_key, bool alpha_byte, const lv_style_t * style); + bool chroma_key, bool alpha_byte, const lv_style_t * style, uint16_t angle); /********************** * STATIC VARIABLES @@ -52,7 +52,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, * @param opa_scale scale down all opacities by the factor */ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, - lv_opa_t opa_scale) + uint16_t angle, lv_opa_t opa_scale) { if(src == NULL) { LV_LOG_WARN("Image draw: src is NULL"); @@ -62,7 +62,7 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * } lv_res_t res; - res = lv_img_draw_core(coords, mask, src, style, opa_scale); + res = lv_img_draw_core(coords, mask, src, style, angle, opa_scale); if(res == LV_RES_INV) { LV_LOG_WARN("Image draw error"); @@ -360,6 +360,17 @@ void lv_img_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * s dsc->chroma_keyed = lv_img_color_format_is_chroma_keyed(cf) ? 1 : 0; dsc->has_alpha = lv_img_color_format_has_alpha(cf) ? 1 : 0; + if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + dsc->native_color = 1; + } + + dsc->img_dsc.data = src; + dsc->img_dsc.header.always_zero = 0; + dsc->img_dsc.header.cf = cf; + dsc->img_dsc.header.w = src_w; + dsc->img_dsc.header.h = src_h; + + dsc->res_opa = LV_OPA_COVER; } bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y) @@ -393,90 +404,131 @@ bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y * In the 0x70..0x90 range use the unchanged source pixel */ lv_color_t c_dest_int; + lv_opa_t opa_dest_int; - uint8_t px_size = LV_COLOR_SIZE >> 3; - uint32_t px = dsc->src_w * ys_int * px_size + xs_int * px_size; - memcpy(&c_dest_int, &src_u8[px], px_size); + uint8_t px_size; + uint32_t px; + if(dsc->native_color) { + if(dsc->has_alpha == 0) { + px_size = LV_COLOR_SIZE >> 3; - - lv_color_t x_dest; - lv_color_t y_dest; - - if(xs_fract < 0x70) { - int32_t xn; /*x neightboor*/ - xn = xs_int - 1; - if(xn < 0) return false; - - lv_color_t c_dest_xn; - memcpy(&c_dest_xn, &src_u8[px - px_size], px_size); - - lv_opa_t xr; /*x mix ratio*/ - xr = xs_fract + 0x80; - x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); - - } else if(xs_fract > 0x90) { - int32_t xn; /*x neightboor*/ - xn = xs_int + 1; - if(xn >= dsc->src_w) return false; - - lv_color_t c_dest_xn; - memcpy(&c_dest_xn, &src_u8[px + px_size], px_size); - - lv_opa_t xr; /*x mix ratio*/ - xr = (0xFF - xs_fract) + 0x80; - x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + px = dsc->src_w * ys_int * px_size + xs_int * px_size; + memcpy(&c_dest_int, &src_u8[px], px_size); + } else { + px_size = LV_IMG_PX_SIZE_ALPHA_BYTE; + px = dsc->src_w * ys_int * px_size + xs_int * px_size; + memcpy(&c_dest_int, &src_u8[px], px_size - 1); + opa_dest_int = src_u8[px + px_size - 1]; + } } else { - x_dest.full = c_dest_int.full; + c_dest_int = lv_img_buf_get_px_color(&dsc->img_dsc, x, y, dsc->color); + opa_dest_int = lv_img_buf_get_px_alpha(&dsc->img_dsc, x, y); } - if(ys_fract < 0x70) { - int32_t yn; /*y neightboor*/ - yn = ys_int - 1; - if(yn < 0) return false; - lv_color_t c_dest_yn; - memcpy(&c_dest_yn, &src_u8[px - px_size * dsc->src_w], px_size); - - lv_opa_t yr; /*y mix ratio*/ - yr = ys_fract + 0x80; - y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); - - } else if(ys_fract > 0x90) { - int32_t yn; /*y neightboor*/ - yn = ys_int + 1; - if(yn >= dsc->src_h) return false; - - lv_color_t c_dest_yn; - memcpy(&c_dest_yn, &src_u8[px + px_size * dsc->src_w], px_size); - - lv_opa_t yr; /*y mix ratio*/ - yr = (0xFF - ys_fract) + 0x80; - y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); - } else { - y_dest.full = c_dest_int.full; - } - - - /*Get the mixture of the original source and the neightboor pixels in both directions*/ if(dsc->chroma_keyed) { lv_color_t ct = LV_COLOR_TRANSP; if(c_dest_int.full == ct.full) return false; } - dsc->res_color = lv_color_mix(x_dest, y_dest, LV_OPA_50); + /*Get the mixture of the original source and the neightboor pixels in both directions*/ + lv_color_t c_x_dest; + lv_color_t c_y_dest; + lv_opa_t opa_x_dest; + lv_opa_t opa_y_dest; - /*Get result pixel opacity*/ - if(dsc->has_alpha) { -// lv_opa_t opa_int = lv_img_buf_get_px_alpha(img, xs_int, ys_int); -// lv_opa_t opa_xn = lv_img_buf_get_px_alpha(img, xn, ys_int); -// lv_opa_t opa_yn = lv_img_buf_get_px_alpha(img, xs_int, yn); -// lv_opa_t opa_x = (opa_int * xr + (opa_xn * (255 - xr))) >> 8; -// lv_opa_t opa_y = (opa_int * yr + (opa_yn * (255 - yr))) >> 8; -// -// dsc->res_opa = (opa_x + opa_y) / 2; -// if(dsc->res_opa <= LV_OPA_MIN) return false; + int32_t xn; /*x neightboor*/ + lv_opa_t xr; /*x mix ratio*/ + lv_color_t c_dest_xn; + lv_opa_t opa_dest_xn; + + if(xs_fract < 0x70) { + xn = xs_int - 1; + if(xn < 0) return false; + + xr = xs_fract + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_xn, &src_u8[px - px_size], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_xn = src_u8[px - 1]; + } else { + c_dest_xn = lv_img_buf_get_px_color(&dsc->img_dsc, xn, y, dsc->color); + if(dsc->has_alpha) opa_dest_xn = lv_img_buf_get_px_alpha(&dsc->img_dsc, xn, y); + } + + c_x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + if(dsc->has_alpha) opa_x_dest = (opa_dest_int * xr + (opa_dest_xn * (255 - xr))) >> 8; + + } else if(xs_fract > 0x90) { + xn = xs_int + 1; + if(xn >= dsc->src_w) return false; + + xr = (0xFF - xs_fract) + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_xn, &src_u8[px + px_size], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_xn = src_u8[px + 2 * px_size - 1]; + } else { + c_dest_xn = lv_img_buf_get_px_color(&dsc->img_dsc, xn, y, dsc->color); + if(dsc->has_alpha) opa_dest_xn = lv_img_buf_get_px_alpha(&dsc->img_dsc, xn, y); + } + + c_x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + if(dsc->has_alpha) opa_x_dest = (opa_dest_int * xr + (opa_dest_xn * (255 - xr))) >> 8; + + } else { + c_x_dest.full = c_dest_int.full; + opa_x_dest = opa_dest_int; } + + int32_t yn; /*x neightboor*/ + lv_opa_t yr; /*x mix ratio*/ + lv_color_t c_dest_yn; + lv_opa_t opa_dest_yn; + + if(ys_fract < 0x70) { + yn = ys_int - 1; + if(yn < 0) return false; + + lv_opa_t yr; /*y mix ratio*/ + yr = ys_fract + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_yn, &src_u8[px - px_size * dsc->src_w], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_yn = src_u8[px - px_size * dsc->src_w - 1]; + } else { + c_dest_yn = lv_img_buf_get_px_color(&dsc->img_dsc, yn, y, dsc->color); + if(dsc->has_alpha) opa_dest_yn = lv_img_buf_get_px_alpha(&dsc->img_dsc, yn, y); + } + + c_y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); + if(dsc->has_alpha) opa_y_dest = (opa_dest_int * yr + (opa_dest_yn * (255 - yr))) >> 8; + + } else if(ys_fract > 0x90) { + yn = ys_int + 1; + if(yn >= dsc->src_h) return false; + + yr = (0xFF - ys_fract) + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_yn, &src_u8[px + px_size * dsc->src_w], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_yn = src_u8[px + px_size * dsc->src_w + 2 * px_size - 1]; + } else { + c_dest_yn = lv_img_buf_get_px_color(&dsc->img_dsc, yn, y, dsc->color); + if(dsc->has_alpha) opa_dest_yn = lv_img_buf_get_px_alpha(&dsc->img_dsc, yn, y); + } + + c_y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); + if(dsc->has_alpha) opa_y_dest = (opa_dest_int * yr + (opa_dest_yn * (255 - yr))) >> 8; + } else { + c_y_dest.full = c_dest_int.full; + opa_y_dest = opa_dest_int; + } + + dsc->res_color = lv_color_mix(c_x_dest, c_y_dest, LV_OPA_50); + if(dsc->has_alpha) dsc->res_opa = (opa_x_dest + opa_y_dest) >> 1; + return true; } @@ -681,12 +733,21 @@ uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) **********************/ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, - const lv_style_t * style, lv_opa_t opa_scale) + const lv_style_t * style, uint16_t angle, lv_opa_t opa_scale) { + lv_area_t map_area_rot; + lv_area_copy(&map_area_rot, coords); + if(angle) { + map_area_rot.x1 -= 50; + map_area_rot.y1 -= 50; + map_area_rot.x2 += 50; + map_area_rot.y2 += 50; + } + lv_area_t mask_com; /*Common area of mask and coords*/ bool union_ok; - union_ok = lv_area_intersect(&mask_com, mask, coords); + union_ok = lv_area_intersect(&mask_com, mask, &map_area_rot); if(union_ok == false) { return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ @@ -710,7 +771,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas /* The decoder open could open the image and gave the entire uncompressed image. * Just draw it!*/ else if(cdsc->dec_dsc.img_data) { - lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style); + lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style, angle); } /* The whole uncompressed image is not available. Try to read it line-by-line*/ else { @@ -733,7 +794,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas lv_draw_buf_release(buf); return LV_RES_INV; } - lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style); + lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style, 0); line.y1++; line.y2++; y++; @@ -755,16 +816,12 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas * @param style style of the image */ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, const uint8_t * map_p, lv_opa_t opa, - bool chroma_key, bool alpha_byte, const lv_style_t * style) + bool chroma_key, bool alpha_byte, const lv_style_t * style, uint16_t angle) { - uint16_t angle = 30; if(opa < LV_OPA_MIN) return; if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; - lv_area_t draw_area; - bool union_ok; - lv_area_t map_area_rot; lv_area_copy(&map_area_rot, map_area); if(angle) { @@ -773,6 +830,10 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, map_area_rot.x2 += 50; map_area_rot.y2 += 50; } + + lv_area_t draw_area; + bool union_ok; + /* Get clipped map area which is the real draw area. * It is always the same or inside `map_area` */ union_ok = lv_area_intersect(&draw_area, &map_area_rot, clip_area); @@ -833,9 +894,13 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, } - lv_img_rotate_dsc_t rotate_dsc; - lv_img_rotate_init(&rotate_dsc, angle, map_p, map_w, map_h, LV_IMG_CF_TRUE_COLOR, map_w/2, map_h / 2, LV_COLOR_BLACK); - + lv_img_rotate_dsc_t rotate_dsc = {}; + if(angle) { + lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR; + if(alpha_byte) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; + else if(chroma_key) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; + lv_img_rotate_init(&rotate_dsc, angle, map_p, map_w, map_h, cf, map_w/2, map_h / 2, LV_COLOR_BLACK); + } lv_draw_mask_res_t mask_res; mask_res = (alpha_byte || chroma_key || angle) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; lv_coord_t x; @@ -845,38 +910,41 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, px_i_start = px_i; for(x = 0; x < lv_area_get_width(&draw_area); x++, map_px += px_size_byte, px_i++) { - if(alpha_byte) { - lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1]; - mask_buf[px_i] = px_opa; - if(px_opa < LV_OPA_MIN) continue; - } else { - mask_buf[px_i] = LV_OPA_COVER; - } + + if(angle == 0) { + if(alpha_byte) { + lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1]; + mask_buf[px_i] = px_opa; + if(px_opa < LV_OPA_MIN) continue; + } else { + mask_buf[px_i] = LV_OPA_COVER; + } #if LV_COLOR_DEPTH == 8 - c.full = map_px[0]; + c.full = map_px[0]; #elif LV_COLOR_DEPTH == 16 - c.full = map_px[0] + (map_px[1] << 8); + c.full = map_px[0] + (map_px[1] << 8); #elif LV_COLOR_DEPTH == 32 - c.full = *((uint32_t*)map_px); + c.full = *((uint32_t*)map_px); #endif - - bool ret; - lv_coord_t rot_x = x + (disp_area->x1 + draw_area.x1) - map_area->x1; - lv_coord_t rot_y = y + (disp_area->y1 + draw_area.y1) - map_area->y1; - ret = lv_img_get_px_rotated(&rotate_dsc, rot_x, rot_y); - if(ret == false) { - mask_buf[px_i] = LV_OPA_TRANSP; - continue; + if (chroma_key) { + if(c.full == chroma_keyed_color.full) { + mask_buf[px_i] = LV_OPA_TRANSP; + continue; + } + } } else { -// mask_buf[px_i] = rotate_dsc.res_opa; - c.full = rotate_dsc.res_color.full; - } - - if (chroma_key) { - if(c.full == chroma_keyed_color.full) { + /*Rotate*/ + bool ret; + lv_coord_t rot_x = x + (disp_area->x1 + draw_area.x1) - map_area->x1; + lv_coord_t rot_y = y + (disp_area->y1 + draw_area.y1) - map_area->y1; + ret = lv_img_get_px_rotated(&rotate_dsc, rot_x, rot_y); + if(ret == false) { mask_buf[px_i] = LV_OPA_TRANSP; continue; + } else { + mask_buf[px_i] = rotate_dsc.res_opa; + c.full = rotate_dsc.res_color.full; } } diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index c2ebc371f..ece2e5a6a 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -54,6 +54,7 @@ typedef struct { lv_coord_t pivot_y; lv_coord_t pivot_x_256; lv_coord_t pivot_y_256; + lv_img_dsc_t img_dsc; int32_t sinma; int32_t cosma; int16_t angle; @@ -62,6 +63,7 @@ typedef struct { uint8_t chroma_keyed :1; uint8_t has_alpha :1; + uint8_t native_color :1; }lv_img_rotate_dsc_t; @@ -78,7 +80,7 @@ typedef struct { * @param opa_scale scale down all opacities by the factor */ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, - lv_opa_t opa_scale); + uint16_t angle, lv_opa_t opa_scale); /** * Get the type of an image source diff --git a/src/lv_objx/lv_canvas.c b/src/lv_objx/lv_canvas.c index 613fdf2e6..d19bf7ce1 100644 --- a/src/lv_objx/lv_canvas.c +++ b/src/lv_objx/lv_canvas.c @@ -586,7 +586,7 @@ void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const voi lv_disp_t * refr_ori = lv_refr_get_disp_refreshing(); lv_refr_set_disp_refreshing(&disp); - lv_draw_img(&coords, &mask, src, style, LV_OPA_COVER); + lv_draw_img(&coords, &mask, src, style, 0, LV_OPA_COVER); lv_refr_set_disp_refreshing(refr_ori); } diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index d3505125a..7a05868d5 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -394,7 +394,7 @@ static lv_design_res_t lv_img_design(lv_obj_t * img, const lv_area_t * clip_area cords_tmp.x1 = coords.x1; cords_tmp.x2 = coords.x1 + ext->w - 1; for(; cords_tmp.x1 < coords.x2; cords_tmp.x1 += ext->w, cords_tmp.x2 += ext->w) { - lv_draw_img(&cords_tmp, clip_area, ext->src, style, opa_scale); + lv_draw_img(&cords_tmp, clip_area, ext->src, style, ext->angle, opa_scale); } } } else if(ext->src_type == LV_IMG_SRC_SYMBOL) { @@ -406,7 +406,7 @@ static lv_design_res_t lv_img_design(lv_obj_t * img, const lv_area_t * clip_area } else { /*Trigger the error handler of image drawer*/ LV_LOG_WARN("lv_img_design: image source type is unknown"); - lv_draw_img(&img->coords, clip_area, NULL, style, opa_scale); + lv_draw_img(&img->coords, clip_area, NULL, style, 0, opa_scale); } } diff --git a/src/lv_objx/lv_imgbtn.c b/src/lv_objx/lv_imgbtn.c index 15c23d395..958b042be 100644 --- a/src/lv_objx/lv_imgbtn.c +++ b/src/lv_objx/lv_imgbtn.c @@ -303,7 +303,7 @@ static lv_design_res_t lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * cli if(lv_img_src_get_type(src) == LV_IMG_SRC_SYMBOL) { lv_draw_label(&imgbtn->coords, clip_area, style, opa_scale, src, LV_TXT_FLAG_NONE, NULL, NULL, NULL); } else { - lv_draw_img(&imgbtn->coords, clip_area, src, style, opa_scale); + lv_draw_img(&imgbtn->coords, clip_area, src, style, 0, opa_scale); } #else const void * src = ext->img_src_left[state]; From 2199b30132445c6f6c7c9e556448fa1d342b3e20 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sun, 3 Nov 2019 10:08:15 +0100 Subject: [PATCH 10/12] optimize clip area with image rotation --- src/lv_draw/lv_draw_img.c | 65 +++++++++++++++++++++++---------------- src/lv_draw/lv_draw_img.h | 4 +-- src/lv_objx/lv_img.c | 2 +- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 0876b7316..4ec7d533e 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -735,14 +735,42 @@ uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, uint16_t angle, lv_opa_t opa_scale) { - lv_area_t map_area_rot; lv_area_copy(&map_area_rot, coords); if(angle) { - map_area_rot.x1 -= 50; - map_area_rot.y1 -= 50; - map_area_rot.x2 += 50; - map_area_rot.y2 += 50; + /*Get the exact area which is required to show the rotated image*/ + lv_coord_t pivot_x = lv_area_get_width(coords) / 2 + coords->x1; + lv_coord_t pivot_y = lv_area_get_height(coords) / 2 + coords->y1; + + lv_area_t norm; + norm.x1 = + coords->x1 - pivot_x; + norm.y1 = + coords->y1 - pivot_y; + norm.x2 = + coords->x2 - pivot_x; + norm.y2 = + coords->y2 - pivot_y; + + int16_t sinma = lv_trigo_sin(-angle); + int16_t cosma = lv_trigo_sin(-angle + 90); + + lv_point_t lt; + lv_point_t rt; + lv_point_t lb; + lv_point_t rb; + lt.x = ((cosma * norm.x1 - sinma * norm.y1) >> (LV_TRIGO_SHIFT)) + pivot_x; + lt.y = ((sinma * norm.x1 + cosma * norm.y1) >> (LV_TRIGO_SHIFT)) + pivot_y; + + rt.x = ((cosma * norm.x2 - sinma * norm.y1) >> (LV_TRIGO_SHIFT)) + pivot_x; + rt.y = ((sinma * norm.x2 + cosma * norm.y1) >> (LV_TRIGO_SHIFT)) + pivot_y; + + lb.x = ((cosma * norm.x1 - sinma * norm.y2) >> (LV_TRIGO_SHIFT)) + pivot_x; + lb.y = ((sinma * norm.x1 + cosma * norm.y2) >> (LV_TRIGO_SHIFT)) + pivot_y; + + rb.x = ((cosma * norm.x2 - sinma * norm.y2) >> (LV_TRIGO_SHIFT)) + pivot_x; + rb.y = ((sinma * norm.x2 + cosma * norm.y2) >> (LV_TRIGO_SHIFT)) + pivot_y; + + map_area_rot.x1 = LV_MATH_MIN(LV_MATH_MIN(LV_MATH_MIN(lb.x, lt.x), rb.x), rt.x); + map_area_rot.x2 = LV_MATH_MAX(LV_MATH_MAX(LV_MATH_MAX(lb.x, lt.x), rb.x), rt.x); + map_area_rot.y1 = LV_MATH_MIN(LV_MATH_MIN(LV_MATH_MIN(lb.y, lt.y), rb.y), rt.y); + map_area_rot.y2 = LV_MATH_MAX(LV_MATH_MAX(LV_MATH_MAX(lb.y, lt.y), rb.y), rt.y); } lv_area_t mask_com; /*Common area of mask and coords*/ @@ -765,13 +793,13 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas if(cdsc->dec_dsc.error_msg != NULL) { LV_LOG_WARN("Image draw error"); - lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER); - lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_rect(coords, &mask_com, &lv_style_plain, LV_OPA_COVER); + lv_draw_label(coords, &mask_com, &lv_style_plain, LV_OPA_COVER, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, NULL, NULL); } /* The decoder open could open the image and gave the entire uncompressed image. * Just draw it!*/ else if(cdsc->dec_dsc.img_data) { - lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style, angle); + lv_draw_map(coords, &mask_com, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style, angle); } /* The whole uncompressed image is not available. Try to read it line-by-line*/ else { @@ -794,7 +822,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas lv_draw_buf_release(buf); return LV_RES_INV; } - lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style, 0); + lv_draw_map(&line, &mask_com, buf, opa, chroma_keyed, alpha_byte, style, 0); line.y1++; line.y2++; y++; @@ -822,24 +850,9 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, if(opa < LV_OPA_MIN) return; if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; - lv_area_t map_area_rot; - lv_area_copy(&map_area_rot, map_area); - if(angle) { - map_area_rot.x1 -= 50; - map_area_rot.y1 -= 50; - map_area_rot.x2 += 50; - map_area_rot.y2 += 50; - } - + /* Use the clip area as draw area*/ lv_area_t draw_area; - bool union_ok; - - /* Get clipped map area which is the real draw area. - * It is always the same or inside `map_area` */ - union_ok = lv_area_intersect(&draw_area, &map_area_rot, clip_area); - - /*If there are common part of the three area then draw to the vdb*/ - if(union_ok == false) return; + lv_area_copy(&draw_area, clip_area); lv_disp_t * disp = lv_refr_get_disp_refreshing(); lv_disp_buf_t * vdb = lv_disp_get_buf(disp); diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index ece2e5a6a..6da8025fd 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -52,8 +52,8 @@ typedef struct { lv_coord_t src_h; lv_coord_t pivot_x; lv_coord_t pivot_y; - lv_coord_t pivot_x_256; - lv_coord_t pivot_y_256; + int32_t pivot_x_256; + int32_t pivot_y_256; lv_img_dsc_t img_dsc; int32_t sinma; int32_t cosma; diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index 7a05868d5..1875b1d78 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -79,7 +79,7 @@ lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy) ext->cf = LV_IMG_CF_UNKNOWN; ext->w = lv_obj_get_width(new_img); ext->h = lv_obj_get_height(new_img); - ext->angle = 30; + ext->angle = 0; ext->auto_size = 1; ext->offset.x = 0; ext->offset.y = 0; From 23b2a2810c431941e5203331b9e6c967f0ddaabe Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sun, 3 Nov 2019 15:45:24 +0100 Subject: [PATCH 11/12] drag fixes Even in case of LV_DRAG_DIR_BOTH only one dir drag was possible if x or y havn't changed during the first movement. --- src/lv_core/lv_indev.c | 21 +++++++++++++++------ src/lv_core/lv_obj.c | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 7bec119a2..623a667b8 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -1100,10 +1100,8 @@ static void indev_drag(lv_indev_proc_t * proc) if(proc->types.pointer.drag_limit_out == 0) { proc->types.pointer.drag_sum.x += proc->types.pointer.vect.x; proc->types.pointer.drag_sum.y += proc->types.pointer.vect.y; - } - /*Enough move?*/ - if(proc->types.pointer.drag_limit_out == 0) { + /*Enough move?*/ bool hor_en = false; bool ver_en = false; if(allowed_dirs == LV_DRAG_DIR_HOR || allowed_dirs == LV_DRAG_DIR_BOTH) { @@ -1182,9 +1180,20 @@ static void indev_drag(lv_indev_proc_t * proc) } } - /*In the inactive direction `drag_sum` is kept zero*/ - if(proc->types.pointer.drag_sum.x) act_x += proc->types.pointer.vect.x; - if(proc->types.pointer.drag_sum.y) act_y += proc->types.pointer.vect.y; + /*Move the object*/ + if(allowed_dirs == LV_DRAG_DIR_HOR || + allowed_dirs == LV_DRAG_DIR_BOTH || + (allowed_dirs == LV_DRAG_DIR_ONE && + LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y))) { + act_x += proc->types.pointer.vect.x; + } + if(allowed_dirs == LV_DRAG_DIR_VER || + allowed_dirs == LV_DRAG_DIR_BOTH || + (allowed_dirs == LV_DRAG_DIR_ONE && + LV_MATH_ABS(proc->types.pointer.drag_sum.x) < LV_MATH_ABS(proc->types.pointer.drag_sum.y))) { + act_y += proc->types.pointer.vect.y; + } + lv_obj_set_pos(drag_obj, act_x, act_y); proc->types.pointer.drag_in_prog = 1; diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index cb60c95ac..b03e8a347 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -204,6 +204,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->drag = 0; new_obj->drag_throw = 0; new_obj->drag_parent = 0; + new_obj->drag_dir = 0; new_obj->hidden = 0; new_obj->top = 0; new_obj->protect = LV_PROTECT_NONE; From a69d75c3d2bb9d75ea4c4cd1328b68e22b083d51 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sun, 3 Nov 2019 15:48:07 +0100 Subject: [PATCH 12/12] add lv_img_buf.c/h for better mosularity --- src/lv_draw/lv_draw_img.c | 557 +------------------------------- src/lv_draw/lv_draw_img.h | 115 +------ src/lv_draw/lv_img_buf.c | 602 +++++++++++++++++++++++++++++++++++ src/lv_draw/lv_img_buf.h | 241 ++++++++++++++ src/lv_draw/lv_img_decoder.c | 8 +- src/lv_draw/lv_img_decoder.h | 81 +---- src/lv_objx/lv_canvas.c | 12 +- src/lv_objx/lv_img.c | 2 - 8 files changed, 865 insertions(+), 753 deletions(-) create mode 100644 src/lv_draw/lv_img_buf.c create mode 100644 src/lv_draw/lv_img_buf.h diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 4ec7d533e..f3f3fefb0 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -72,496 +72,13 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * } } -/** - * Get the color of an image's pixel - * @param dsc an image descriptor - * @param x x coordinate of the point to get - * @param y x coordinate of the point to get - * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. - * Not used in other cases. - * @return color of the point - */ -lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color) -{ - lv_color_t p_color = LV_COLOR_BLACK; - if(x >= dsc->header.w) { - x = dsc->header.w - 1; - LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)"); - } else if(x < 0) { - x = 0; - LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)"); - } - - if(y >= dsc->header.h) { - y = dsc->header.h - 1; - LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)"); - } else if(y < 0) { - y = 0; - LV_LOG_WARN("lv_canvas_get_px: y is < 0 (out of canvas)"); - } - - uint8_t * buf_u8 = (uint8_t *)dsc->data; - - if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED || - dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3; - uint32_t px = dsc->header.w * y * px_size + x * px_size; - memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t)); -#if LV_COLOR_SIZE == 32 - p_color.ch.alpha = 0xFF; /*Only the color should be get so use a deafult alpha value*/ -#endif - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) { - buf_u8 += 4 * 2; - uint8_t bit = x & 0x7; - x = x >> 3; - - /* Get the current pixel. - * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 8, 16, 24 ...*/ - uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; - p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit); - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) { - buf_u8 += 4 * 4; - uint8_t bit = (x & 0x3) * 2; - x = x >> 2; - - /* Get the current pixel. - * dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned - * so the possible real width are 4, 8, 12 ...*/ - uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; - p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit); - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) { - buf_u8 += 4 * 16; - uint8_t bit = (x & 0x1) * 4; - x = x >> 1; - - /* Get the current pixel. - * dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned - * so the possible real width are 2, 4, 6 ...*/ - uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; - p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit); - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { - buf_u8 += 4 * 256; - uint32_t px = dsc->header.w * y + x; - p_color.full = buf_u8[px]; - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || - dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { - p_color = color; - } - return p_color; -} - -/** - * Get the alpha value of an image's pixel - * @param dsc pointer to an image descriptor - * @param x x coordinate of the point to set - * @param y x coordinate of the point to set - * @return alpha value of the point - */ -lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y) -{ - if(x >= dsc->header.w) { - x = dsc->header.w - 1; - LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)"); - } else if(x < 0) { - x = 0; - LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)"); - } - - if(y >= dsc->header.h) { - y = dsc->header.h - 1; - LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)"); - } else if(y < 0) { - y = 0; - LV_LOG_WARN("lv_canvas_get_px: y is < 0 (out of canvas)"); - } - - uint8_t * buf_u8 = (uint8_t *)dsc->data; - - if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { - uint32_t px = dsc->header.w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE; - return buf_u8[px + LV_IMG_PX_SIZE_ALPHA_BYTE - 1]; - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) { - uint8_t bit = x & 0x7; - x = x >> 3; - - /* Get the current pixel. - * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 8 ,16, 24 ...*/ - uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; - uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit); - return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER; - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) { - const uint8_t opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ - - uint8_t bit = (x & 0x3) * 2; - x = x >> 2; - - /* Get the current pixel. - * dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 4 ,8, 12 ...*/ - uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; - uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit); - return opa_table[px_opa]; - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) { - const uint8_t opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ - 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255}; - - uint8_t bit = (x & 0x1) * 4; - x = x >> 1; - - /* Get the current pixel. - * dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 2 ,4, 6 ...*/ - uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; - uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit); - return opa_table[px_opa]; - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { - uint32_t px = dsc->header.w * y + x; - return buf_u8[px]; - } - - return LV_OPA_COVER; -} - -/** - * Set the color of a pixel of an image. The alpha channel won't be affected. - * @param dsc pointer to an image descriptor - * @param x x coordinate of the point to set - * @param y x coordinate of the point to set - * @param c color of the point - */ -void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c) -{ - uint8_t * buf_u8 = (uint8_t *)dsc->data; - - if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3; - uint32_t px = dsc->header.w * y * px_size + x * px_size; - memcpy(&buf_u8[px], &c, px_size); - } else if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3; - uint32_t px = dsc->header.w * y * px_size + x * px_size; - memcpy(&buf_u8[px], &c, px_size - 1); /*-1 to not overwrite the alpha value*/ - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) { - buf_u8 += sizeof(lv_color32_t) * 2; /*Skip the palette*/ - - uint8_t bit = x & 0x7; - x = x >> 3; - - /* Get the current pixel. - * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 8 ,16, 24 ...*/ - uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; - buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit)); - buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit)); - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) { - buf_u8 += sizeof(lv_color32_t) * 4; /*Skip the palette*/ - uint8_t bit = (x & 0x3) * 2; - x = x >> 2; - - /* Get the current pixel. - * dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned - * so the possible real width are 4, 8 ,12 ...*/ - uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; - - buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit)); - buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit)); - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) { - buf_u8 += sizeof(lv_color32_t) * 16; /*Skip the palette*/ - uint8_t bit = (x & 0x1) * 4; - x = x >> 1; - - /* Get the current pixel. - * dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned - * so the possible real width are 2 ,4, 6 ...*/ - uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; - buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit)); - buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit)); - } else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { - buf_u8 += sizeof(lv_color32_t) * 256; /*Skip the palette*/ - uint32_t px = dsc->header.w * y + x; - buf_u8[px] = c.full; - } -} - -/** - * Set the alpha value of a pixel of an image. The color won't be affected - * @param dsc pointer to an image descriptor - * @param x x coordinate of the point to set - * @param y x coordinate of the point to set - * @param opa the desired opacity - */ -void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa) -{ - uint8_t * buf_u8 = (uint8_t *)dsc->data; - - if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3; - uint32_t px = dsc->header.w * y * px_size + x * px_size; - buf_u8[px + px_size - 1] = opa; - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) { - opa = opa >> 7; /*opa -> [0,1]*/ - uint8_t bit = x & 0x7; - x = x >> 3; - - /* Get the current pixel. - * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 8 ,16, 24 ...*/ - uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; - buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit)); - buf_u8[px] = buf_u8[px] | ((opa & 0x1) << (7 - bit)); - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) { - opa = opa >> 6; /*opa -> [0,3]*/ - uint8_t bit = (x & 0x3) * 2; - x = x >> 2; - - /* Get the current pixel. - * dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 4 ,8, 12 ...*/ - uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; - buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit)); - buf_u8[px] = buf_u8[px] | ((opa & 0x3) << (6 - bit)); - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) { - opa = opa >> 4; /*opa -> [0,15]*/ - uint8_t bit = (x & 0x1) * 4; - x = x >> 1; - - /* Get the current pixel. - * dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned - * so the possible real width are 2 ,4, 6 ...*/ - uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; - buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit)); - buf_u8[px] = buf_u8[px] | ((opa & 0xF) << (4 - bit)); - } else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { - uint32_t px = dsc->header.w * y + x; - buf_u8[px] = opa; - } -} - - -void lv_img_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * src, lv_coord_t src_w, lv_coord_t src_h, - lv_img_cf_t cf, lv_coord_t pivot_x, lv_coord_t pivot_y, lv_color_t color) -{ - memset(dsc, 0x00, sizeof(lv_img_rotate_dsc_t)); - - dsc->angle = angle; - dsc->src = src; - dsc->src_w = src_w; - dsc->src_h = src_h; - dsc->cf = cf; - dsc->color = color; - dsc->pivot_x = pivot_x; - dsc->pivot_y = pivot_y; - dsc->pivot_x_256 = pivot_x * 256; - dsc->pivot_y_256 = pivot_y * 256; - dsc->sinma = lv_trigo_sin(-angle); - dsc->cosma = lv_trigo_sin(-angle + 90); - - dsc->chroma_keyed = lv_img_color_format_is_chroma_keyed(cf) ? 1 : 0; - dsc->has_alpha = lv_img_color_format_has_alpha(cf) ? 1 : 0; - if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { - dsc->native_color = 1; - } - - dsc->img_dsc.data = src; - dsc->img_dsc.header.always_zero = 0; - dsc->img_dsc.header.cf = cf; - dsc->img_dsc.header.w = src_w; - dsc->img_dsc.header.h = src_h; - - dsc->res_opa = LV_OPA_COVER; -} - -bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y) -{ - const uint8_t * src_u8 = dsc->src; - - /*Get the target point relative coordinates to the pivot*/ - int32_t xt = x - dsc->pivot_x; - int32_t yt = y - dsc->pivot_y; - - /*Get the source pixel from the upscaled image*/ - int32_t xs = ((dsc->cosma * xt - dsc->sinma * yt) >> (LV_TRIGO_SHIFT - 8)) + dsc->pivot_x_256; - int32_t ys = ((dsc->sinma * xt + dsc->cosma * yt) >> (LV_TRIGO_SHIFT - 8)) + dsc->pivot_y_256; - - /*Get the integer part of the source pixel*/ - int xs_int = xs >> 8; - int ys_int = ys >> 8; - - if(xs_int >= dsc->src_w) return false; - else if(xs_int < 0) return false; - - if(ys_int >= dsc->src_h) return false; - else if(ys_int < 0) return false; - - /*Get the fractional part of the source pixel*/ - int xs_fract = xs & 0xff; - int ys_fract = ys & 0xff; - - /* If the fractional < 0x70 mix the source pixel with the left/top pixel - * If the fractional > 0x90 mix the source pixel with the right/bottom pixel - * In the 0x70..0x90 range use the unchanged source pixel */ - - lv_color_t c_dest_int; - lv_opa_t opa_dest_int; - - uint8_t px_size; - uint32_t px; - if(dsc->native_color) { - if(dsc->has_alpha == 0) { - px_size = LV_COLOR_SIZE >> 3; - - px = dsc->src_w * ys_int * px_size + xs_int * px_size; - memcpy(&c_dest_int, &src_u8[px], px_size); - } else { - px_size = LV_IMG_PX_SIZE_ALPHA_BYTE; - px = dsc->src_w * ys_int * px_size + xs_int * px_size; - memcpy(&c_dest_int, &src_u8[px], px_size - 1); - opa_dest_int = src_u8[px + px_size - 1]; - } - } else { - c_dest_int = lv_img_buf_get_px_color(&dsc->img_dsc, x, y, dsc->color); - opa_dest_int = lv_img_buf_get_px_alpha(&dsc->img_dsc, x, y); - } - - - if(dsc->chroma_keyed) { - lv_color_t ct = LV_COLOR_TRANSP; - if(c_dest_int.full == ct.full) return false; - } - - /*Get the mixture of the original source and the neightboor pixels in both directions*/ - lv_color_t c_x_dest; - lv_color_t c_y_dest; - lv_opa_t opa_x_dest; - lv_opa_t opa_y_dest; - - int32_t xn; /*x neightboor*/ - lv_opa_t xr; /*x mix ratio*/ - lv_color_t c_dest_xn; - lv_opa_t opa_dest_xn; - - if(xs_fract < 0x70) { - xn = xs_int - 1; - if(xn < 0) return false; - - xr = xs_fract + 0x80; - - if(dsc->native_color) { - memcpy(&c_dest_xn, &src_u8[px - px_size], sizeof(lv_color_t)); - if(dsc->has_alpha) opa_dest_xn = src_u8[px - 1]; - } else { - c_dest_xn = lv_img_buf_get_px_color(&dsc->img_dsc, xn, y, dsc->color); - if(dsc->has_alpha) opa_dest_xn = lv_img_buf_get_px_alpha(&dsc->img_dsc, xn, y); - } - - c_x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); - if(dsc->has_alpha) opa_x_dest = (opa_dest_int * xr + (opa_dest_xn * (255 - xr))) >> 8; - - } else if(xs_fract > 0x90) { - xn = xs_int + 1; - if(xn >= dsc->src_w) return false; - - xr = (0xFF - xs_fract) + 0x80; - - if(dsc->native_color) { - memcpy(&c_dest_xn, &src_u8[px + px_size], sizeof(lv_color_t)); - if(dsc->has_alpha) opa_dest_xn = src_u8[px + 2 * px_size - 1]; - } else { - c_dest_xn = lv_img_buf_get_px_color(&dsc->img_dsc, xn, y, dsc->color); - if(dsc->has_alpha) opa_dest_xn = lv_img_buf_get_px_alpha(&dsc->img_dsc, xn, y); - } - - c_x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); - if(dsc->has_alpha) opa_x_dest = (opa_dest_int * xr + (opa_dest_xn * (255 - xr))) >> 8; - - } else { - c_x_dest.full = c_dest_int.full; - opa_x_dest = opa_dest_int; - } - - - int32_t yn; /*x neightboor*/ - lv_opa_t yr; /*x mix ratio*/ - lv_color_t c_dest_yn; - lv_opa_t opa_dest_yn; - - if(ys_fract < 0x70) { - yn = ys_int - 1; - if(yn < 0) return false; - - lv_opa_t yr; /*y mix ratio*/ - yr = ys_fract + 0x80; - - if(dsc->native_color) { - memcpy(&c_dest_yn, &src_u8[px - px_size * dsc->src_w], sizeof(lv_color_t)); - if(dsc->has_alpha) opa_dest_yn = src_u8[px - px_size * dsc->src_w - 1]; - } else { - c_dest_yn = lv_img_buf_get_px_color(&dsc->img_dsc, yn, y, dsc->color); - if(dsc->has_alpha) opa_dest_yn = lv_img_buf_get_px_alpha(&dsc->img_dsc, yn, y); - } - - c_y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); - if(dsc->has_alpha) opa_y_dest = (opa_dest_int * yr + (opa_dest_yn * (255 - yr))) >> 8; - - } else if(ys_fract > 0x90) { - yn = ys_int + 1; - if(yn >= dsc->src_h) return false; - - yr = (0xFF - ys_fract) + 0x80; - - if(dsc->native_color) { - memcpy(&c_dest_yn, &src_u8[px + px_size * dsc->src_w], sizeof(lv_color_t)); - if(dsc->has_alpha) opa_dest_yn = src_u8[px + px_size * dsc->src_w + 2 * px_size - 1]; - } else { - c_dest_yn = lv_img_buf_get_px_color(&dsc->img_dsc, yn, y, dsc->color); - if(dsc->has_alpha) opa_dest_yn = lv_img_buf_get_px_alpha(&dsc->img_dsc, yn, y); - } - - c_y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); - if(dsc->has_alpha) opa_y_dest = (opa_dest_int * yr + (opa_dest_yn * (255 - yr))) >> 8; - } else { - c_y_dest.full = c_dest_int.full; - opa_y_dest = opa_dest_int; - } - - dsc->res_color = lv_color_mix(c_x_dest, c_y_dest, LV_OPA_50); - if(dsc->has_alpha) dsc->res_opa = (opa_x_dest + opa_y_dest) >> 1; - - return true; -} - -/** - * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` - * @param dsc pointer to an image descriptor - * @param id the palette color to set: - * - for `LV_IMG_CF_INDEXED1`: 0..1 - * - for `LV_IMG_CF_INDEXED2`: 0..3 - * - for `LV_IMG_CF_INDEXED4`: 0..15 - * - for `LV_IMG_CF_INDEXED8`: 0..255 - * @param c the color to set - */ -void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c) -{ - if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) || - (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) { - LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'"); - return; - } - - lv_color32_t c32; - c32.full = lv_color_to32(c); - uint8_t * buf = (uint8_t *)dsc->data; - memcpy(&buf[id * sizeof(c32)], &c32, sizeof(c32)); -} /** * Get the pixel size of a color format in bits * @param cf a color format (`LV_IMG_CF_...`) * @return the pixel size in bits */ -uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf) +uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf) { uint8_t px_size = 0; @@ -590,7 +107,7 @@ uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf) * @param cf a color format (`LV_IMG_CF_...`) * @return true: chroma keyed; false: not chroma keyed */ -bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) +bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf) { bool is_chroma_keyed = false; @@ -616,7 +133,7 @@ bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) * @param cf a color format (`LV_IMG_CF_...`) * @return true: has alpha channel; false: doesn't have alpha channel */ -bool lv_img_color_format_has_alpha(lv_img_cf_t cf) +bool lv_img_cf_has_alpha(lv_img_cf_t cf) { bool has_alpha = false; @@ -668,66 +185,6 @@ lv_img_src_t lv_img_src_get_type(const void * src) return img_src_type; } -lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) -{ - /* Allocate image descriptor */ - lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t)); - if(dsc == NULL) - return NULL; - - memset(dsc, 0, sizeof(lv_img_dsc_t)); - - /* Get image data size */ - dsc->data_size = lv_img_buf_get_img_size(w, h, cf); - if(dsc->data_size == 0) { - lv_mem_free(dsc); - return NULL; - } - - /* Allocate raw buffer */ - dsc->data = lv_mem_alloc(dsc->data_size); - if(dsc->data == NULL) { - lv_mem_free(dsc); - return NULL; - } - memset((uint8_t *)dsc->data, 0, dsc->data_size); - - /* Fill in header */ - dsc->header.always_zero = 0; - dsc->header.w = w; - dsc->header.h = h; - dsc->header.cf = cf; - return dsc; -} - -void lv_img_buf_free(lv_img_dsc_t *dsc) -{ - if(dsc != NULL) { - if(dsc->data != NULL) - lv_mem_free(dsc->data); - - lv_mem_free(dsc); - } -} - -uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) -{ - switch(cf) { - case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); - case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); - case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); - case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); - case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); - case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); - case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); - case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); - case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); - case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); - case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); - default: return 0; - } -} - /********************** * STATIC FUNCTIONS **********************/ @@ -788,8 +245,8 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas if(cdsc == NULL) return LV_RES_INV; - bool chroma_keyed = lv_img_color_format_is_chroma_keyed(cdsc->dec_dsc.header.cf); - bool alpha_byte = lv_img_color_format_has_alpha(cdsc->dec_dsc.header.cf); + bool chroma_keyed = lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf); + bool alpha_byte = lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf); if(cdsc->dec_dsc.error_msg != NULL) { LV_LOG_WARN("Image draw error"); @@ -912,7 +369,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR; if(alpha_byte) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; else if(chroma_key) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; - lv_img_rotate_init(&rotate_dsc, angle, map_p, map_w, map_h, cf, map_w/2, map_h / 2, LV_COLOR_BLACK); + lv_img_buf_rotate_init(&rotate_dsc, angle, map_p, map_w, map_h, cf, map_w/2, map_h / 2, LV_COLOR_BLACK); } lv_draw_mask_res_t mask_res; mask_res = (alpha_byte || chroma_key || angle) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; @@ -951,7 +408,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, bool ret; lv_coord_t rot_x = x + (disp_area->x1 + draw_area.x1) - map_area->x1; lv_coord_t rot_y = y + (disp_area->y1 + draw_area.y1) - map_area->y1; - ret = lv_img_get_px_rotated(&rotate_dsc, rot_x, rot_y); + ret = lv_img_buf_get_px_rotated(&rotate_dsc, rot_x, rot_y); if(ret == false) { mask_buf[px_i] = LV_OPA_TRANSP; continue; diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 6da8025fd..7c0c71605 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -15,6 +15,7 @@ extern "C" { *********************/ #include "lv_draw.h" #include "lv_img_decoder.h" +#include "lv_img_buf.h" /********************* * DEFINES @@ -24,48 +25,10 @@ extern "C" { * MACROS **********************/ -#define LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h) -#define LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h) -#define LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h) - -/*+ 1: to be sure no fractional row*/ -#define LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h)) -#define LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h)) -#define LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h)) -#define LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h)) - -/*4 * X: for palette*/ -#define LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2) -#define LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4) -#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16) -#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256) - /********************** * TYPEDEFS **********************/ -typedef struct { - lv_color_t res_color; - lv_opa_t res_opa; - const void * src; - lv_coord_t src_w; - lv_coord_t src_h; - lv_coord_t pivot_x; - lv_coord_t pivot_y; - int32_t pivot_x_256; - int32_t pivot_y_256; - lv_img_dsc_t img_dsc; - int32_t sinma; - int32_t cosma; - int16_t angle; - lv_color_t color; - lv_img_cf_t cf; - - uint8_t chroma_keyed :1; - uint8_t has_alpha :1; - uint8_t native_color :1; - -}lv_img_rotate_dsc_t; /********************** * GLOBAL PROTOTYPES @@ -93,83 +56,26 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * lv_img_src_t lv_img_src_get_type(const void * src); -/** - * Get the color of an image's pixel - * @param dsc an image descriptor - * @param x x coordinate of the point to get - * @param y x coordinate of the point to get - * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. - * Not used in other cases. - * @return color of the point - */ -lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color); - - -/** - * Get the alpha value of an image's pixel - * @param dsc pointer to an image descriptor - * @param x x coordinate of the point to set - * @param y x coordinate of the point to set - * @return alpha value of the point - */ -lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y); - - -void lv_img_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * src, lv_coord_t src_w, lv_coord_t src_h, - lv_img_cf_t cf, lv_coord_t pivot_x, lv_coord_t pivot_y, lv_color_t color); - -bool lv_img_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y); - -/** - * Set the color of a pixel of an image. The alpha channel won't be affected. - * @param dsc pointer to an image descriptor - * @param x x coordinate of the point to set - * @param y x coordinate of the point to set - * @param c color of the point - */ -void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c); - -/** - * Set the alpha value of a pixel of an image. The color won't be affected - * @param dsc pointer to an image descriptor - * @param x x coordinate of the point to set - * @param y x coordinate of the point to set - * @param opa the desired opacity - */ -void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa); - -/** - * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` - * @param dsc pointer to an image descriptor - * @param id the palette color to set: - * - for `LV_IMG_CF_INDEXED1`: 0..1 - * - for `LV_IMG_CF_INDEXED2`: 0..3 - * - for `LV_IMG_CF_INDEXED4`: 0..15 - * - for `LV_IMG_CF_INDEXED8`: 0..255 - * @param c the color to set - */ -void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c); - /** * Get the pixel size of a color format in bits * @param cf a color format (`LV_IMG_CF_...`) * @return the pixel size in bits */ -uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf); +uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf); /** * Check if a color format is chroma keyed or not * @param cf a color format (`LV_IMG_CF_...`) * @return true: chroma keyed; false: not chroma keyed */ -bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); +bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf); /** * Check if a color format has alpha channel or not * @param cf a color format (`LV_IMG_CF_...`) * @return true: has alpha channel; false: doesn't have alpha channel */ -bool lv_img_color_format_has_alpha(lv_img_cf_t cf); +bool lv_img_cf_has_alpha(lv_img_cf_t cf); /** * Allocate an image buffer in RAM @@ -180,20 +86,7 @@ bool lv_img_color_format_has_alpha(lv_img_cf_t cf); */ lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); -/** - * Free an allocated image buffer - * @param dsc image buffer to free - */ -void lv_img_buf_free(lv_img_dsc_t *dsc); -/** - * Get the memory consumption of a raw bitmap, given color format and dimensions. - * @param w width - * @param h height - * @param cf color format - * @return size in bytes - */ -uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); #ifdef __cplusplus diff --git a/src/lv_draw/lv_img_buf.c b/src/lv_draw/lv_img_buf.c new file mode 100644 index 000000000..fdde8922f --- /dev/null +++ b/src/lv_draw/lv_img_buf.c @@ -0,0 +1,602 @@ +/** + * @file lv_img_buf.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_img_buf.h" +#include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Get the color of an image's pixel + * @param dsc an image descriptor + * @param x x coordinate of the point to get + * @param y x coordinate of the point to get + * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. + * Not used in other cases. + * @return color of the point + */ +lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color) +{ + lv_color_t p_color = LV_COLOR_BLACK; + if(x >= dsc->header.w) { + x = dsc->header.w - 1; + LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)"); + } else if(x < 0) { + x = 0; + LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)"); + } + + if(y >= dsc->header.h) { + y = dsc->header.h - 1; + LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)"); + } else if(y < 0) { + y = 0; + LV_LOG_WARN("lv_canvas_get_px: y is < 0 (out of canvas)"); + } + + uint8_t * buf_u8 = (uint8_t *)dsc->data; + + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED || + dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3; + uint32_t px = dsc->header.w * y * px_size + x * px_size; + memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t)); +#if LV_COLOR_SIZE == 32 + p_color.ch.alpha = 0xFF; /*Only the color should be get so use a deafult alpha value*/ +#endif + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) { + buf_u8 += 4 * 2; + uint8_t bit = x & 0x7; + x = x >> 3; + + /* Get the current pixel. + * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 8, 16, 24 ...*/ + uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; + p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) { + buf_u8 += 4 * 4; + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + /* Get the current pixel. + * dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned + * so the possible real width are 4, 8, 12 ...*/ + uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; + p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) { + buf_u8 += 4 * 16; + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + /* Get the current pixel. + * dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned + * so the possible real width are 2, 4, 6 ...*/ + uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; + p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { + buf_u8 += 4 * 256; + uint32_t px = dsc->header.w * y + x; + p_color.full = buf_u8[px]; + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || + dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + p_color = color; + } + return p_color; +} + +/** + * Get the alpha value of an image's pixel + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return alpha value of the point + */ +lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y) +{ + if(x >= dsc->header.w) { + x = dsc->header.w - 1; + LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)"); + } else if(x < 0) { + x = 0; + LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)"); + } + + if(y >= dsc->header.h) { + y = dsc->header.h - 1; + LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)"); + } else if(y < 0) { + y = 0; + LV_LOG_WARN("lv_canvas_get_px: y is < 0 (out of canvas)"); + } + + uint8_t * buf_u8 = (uint8_t *)dsc->data; + + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + uint32_t px = dsc->header.w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE; + return buf_u8[px + LV_IMG_PX_SIZE_ALPHA_BYTE - 1]; + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) { + uint8_t bit = x & 0x7; + x = x >> 3; + + /* Get the current pixel. + * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 8 ,16, 24 ...*/ + uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; + uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit); + return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER; + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) { + const uint8_t opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + /* Get the current pixel. + * dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 4 ,8, 12 ...*/ + uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; + uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit); + return opa_table[px_opa]; + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) { + const uint8_t opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255}; + + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + /* Get the current pixel. + * dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 2 ,4, 6 ...*/ + uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; + uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit); + return opa_table[px_opa]; + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + uint32_t px = dsc->header.w * y + x; + return buf_u8[px]; + } + + return LV_OPA_COVER; +} + +/** + * Set the color of a pixel of an image. The alpha channel won't be affected. + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c) +{ + uint8_t * buf_u8 = (uint8_t *)dsc->data; + + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3; + uint32_t px = dsc->header.w * y * px_size + x * px_size; + memcpy(&buf_u8[px], &c, px_size); + } else if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3; + uint32_t px = dsc->header.w * y * px_size + x * px_size; + memcpy(&buf_u8[px], &c, px_size - 1); /*-1 to not overwrite the alpha value*/ + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) { + buf_u8 += sizeof(lv_color32_t) * 2; /*Skip the palette*/ + + uint8_t bit = x & 0x7; + x = x >> 3; + + /* Get the current pixel. + * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 8 ,16, 24 ...*/ + uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; + buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit)); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) { + buf_u8 += sizeof(lv_color32_t) * 4; /*Skip the palette*/ + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + /* Get the current pixel. + * dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned + * so the possible real width are 4, 8 ,12 ...*/ + uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; + + buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit)); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) { + buf_u8 += sizeof(lv_color32_t) * 16; /*Skip the palette*/ + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + /* Get the current pixel. + * dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned + * so the possible real width are 2 ,4, 6 ...*/ + uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; + buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit)); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { + buf_u8 += sizeof(lv_color32_t) * 256; /*Skip the palette*/ + uint32_t px = dsc->header.w * y + x; + buf_u8[px] = c.full; + } +} + +/** + * Set the alpha value of a pixel of an image. The color won't be affected + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param opa the desired opacity + */ +void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa) +{ + uint8_t * buf_u8 = (uint8_t *)dsc->data; + + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3; + uint32_t px = dsc->header.w * y * px_size + x * px_size; + buf_u8[px + px_size - 1] = opa; + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) { + opa = opa >> 7; /*opa -> [0,1]*/ + uint8_t bit = x & 0x7; + x = x >> 3; + + /* Get the current pixel. + * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 8 ,16, 24 ...*/ + uint32_t px = ((dsc->header.w + 7) >> 3) * y + x; + buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit)); + buf_u8[px] = buf_u8[px] | ((opa & 0x1) << (7 - bit)); + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) { + opa = opa >> 6; /*opa -> [0,3]*/ + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + /* Get the current pixel. + * dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 4 ,8, 12 ...*/ + uint32_t px = ((dsc->header.w + 3) >> 2) * y + x; + buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit)); + buf_u8[px] = buf_u8[px] | ((opa & 0x3) << (6 - bit)); + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) { + opa = opa >> 4; /*opa -> [0,15]*/ + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + /* Get the current pixel. + * dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned + * so the possible real width are 2 ,4, 6 ...*/ + uint32_t px = ((dsc->header.w + 1) >> 1) * y + x; + buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit)); + buf_u8[px] = buf_u8[px] | ((opa & 0xF) << (4 - bit)); + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + uint32_t px = dsc->header.w * y + x; + buf_u8[px] = opa; + } +} + + +void lv_img_buf_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * src, lv_coord_t src_w, lv_coord_t src_h, + lv_img_cf_t cf, lv_coord_t pivot_x, lv_coord_t pivot_y, lv_color_t color) +{ + memset(dsc, 0x00, sizeof(lv_img_rotate_dsc_t)); + + dsc->angle = angle; + dsc->src = src; + dsc->src_w = src_w; + dsc->src_h = src_h; + dsc->cf = cf; + dsc->color = color; + dsc->pivot_x = pivot_x; + dsc->pivot_y = pivot_y; + dsc->pivot_x_256 = pivot_x * 256; + dsc->pivot_y_256 = pivot_y * 256; + dsc->sinma = lv_trigo_sin(-angle); + dsc->cosma = lv_trigo_sin(-angle + 90); + + dsc->chroma_keyed = lv_img_cf_is_chroma_keyed(cf) ? 1 : 0; + dsc->has_alpha = lv_img_cf_has_alpha(cf) ? 1 : 0; + if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + dsc->native_color = 1; + } + + dsc->img_dsc.data = src; + dsc->img_dsc.header.always_zero = 0; + dsc->img_dsc.header.cf = cf; + dsc->img_dsc.header.w = src_w; + dsc->img_dsc.header.h = src_h; + + dsc->res_opa = LV_OPA_COVER; +} + +bool lv_img_buf_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y) +{ + const uint8_t * src_u8 = dsc->src; + + /*Get the target point relative coordinates to the pivot*/ + int32_t xt = x - dsc->pivot_x; + int32_t yt = y - dsc->pivot_y; + + /*Get the source pixel from the upscaled image*/ + int32_t xs = ((dsc->cosma * xt - dsc->sinma * yt) >> (LV_TRIGO_SHIFT - 8)) + dsc->pivot_x_256; + int32_t ys = ((dsc->sinma * xt + dsc->cosma * yt) >> (LV_TRIGO_SHIFT - 8)) + dsc->pivot_y_256; + + /*Get the integer part of the source pixel*/ + int xs_int = xs >> 8; + int ys_int = ys >> 8; + + if(xs_int >= dsc->src_w) return false; + else if(xs_int < 0) return false; + + if(ys_int >= dsc->src_h) return false; + else if(ys_int < 0) return false; + + /*Get the fractional part of the source pixel*/ + int xs_fract = xs & 0xff; + int ys_fract = ys & 0xff; + + /* If the fractional < 0x70 mix the source pixel with the left/top pixel + * If the fractional > 0x90 mix the source pixel with the right/bottom pixel + * In the 0x70..0x90 range use the unchanged source pixel */ + + lv_color_t c_dest_int; + lv_opa_t opa_dest_int; + + uint8_t px_size; + uint32_t px; + if(dsc->native_color) { + if(dsc->has_alpha == 0) { + px_size = LV_COLOR_SIZE >> 3; + + px = dsc->src_w * ys_int * px_size + xs_int * px_size; + memcpy(&c_dest_int, &src_u8[px], px_size); + } else { + px_size = LV_IMG_PX_SIZE_ALPHA_BYTE; + px = dsc->src_w * ys_int * px_size + xs_int * px_size; + memcpy(&c_dest_int, &src_u8[px], px_size - 1); + opa_dest_int = src_u8[px + px_size - 1]; + } + } else { + c_dest_int = lv_img_buf_get_px_color(&dsc->img_dsc, x, y, dsc->color); + opa_dest_int = lv_img_buf_get_px_alpha(&dsc->img_dsc, x, y); + } + + + if(dsc->chroma_keyed) { + lv_color_t ct = LV_COLOR_TRANSP; + if(c_dest_int.full == ct.full) return false; + } + + /*Get the mixture of the original source and the neightboor pixels in both directions*/ + lv_color_t c_x_dest; + lv_color_t c_y_dest; + lv_opa_t opa_x_dest; + lv_opa_t opa_y_dest; + + int32_t xn; /*x neightboor*/ + lv_opa_t xr; /*x mix ratio*/ + lv_color_t c_dest_xn; + lv_opa_t opa_dest_xn; + + if(xs_fract < 0x70) { + xn = xs_int - 1; + if(xn < 0) return false; + + xr = xs_fract + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_xn, &src_u8[px - px_size], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_xn = src_u8[px - 1]; + } else { + c_dest_xn = lv_img_buf_get_px_color(&dsc->img_dsc, xn, y, dsc->color); + if(dsc->has_alpha) opa_dest_xn = lv_img_buf_get_px_alpha(&dsc->img_dsc, xn, y); + } + + c_x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + if(dsc->has_alpha) opa_x_dest = (opa_dest_int * xr + (opa_dest_xn * (255 - xr))) >> 8; + + } else if(xs_fract > 0x90) { + xn = xs_int + 1; + if(xn >= dsc->src_w) return false; + + xr = (0xFF - xs_fract) + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_xn, &src_u8[px + px_size], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_xn = src_u8[px + 2 * px_size - 1]; + } else { + c_dest_xn = lv_img_buf_get_px_color(&dsc->img_dsc, xn, y, dsc->color); + if(dsc->has_alpha) opa_dest_xn = lv_img_buf_get_px_alpha(&dsc->img_dsc, xn, y); + } + + c_x_dest = lv_color_mix(c_dest_int, c_dest_xn, xr); + if(dsc->has_alpha) opa_x_dest = (opa_dest_int * xr + (opa_dest_xn * (255 - xr))) >> 8; + + } else { + c_x_dest.full = c_dest_int.full; + opa_x_dest = opa_dest_int; + } + + + int32_t yn; /*x neightboor*/ + lv_opa_t yr; /*x mix ratio*/ + lv_color_t c_dest_yn; + lv_opa_t opa_dest_yn; + + if(ys_fract < 0x70) { + yn = ys_int - 1; + if(yn < 0) return false; + + lv_opa_t yr; /*y mix ratio*/ + yr = ys_fract + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_yn, &src_u8[px - px_size * dsc->src_w], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_yn = src_u8[px - px_size * dsc->src_w - 1]; + } else { + c_dest_yn = lv_img_buf_get_px_color(&dsc->img_dsc, yn, y, dsc->color); + if(dsc->has_alpha) opa_dest_yn = lv_img_buf_get_px_alpha(&dsc->img_dsc, yn, y); + } + + c_y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); + if(dsc->has_alpha) opa_y_dest = (opa_dest_int * yr + (opa_dest_yn * (255 - yr))) >> 8; + + } else if(ys_fract > 0x90) { + yn = ys_int + 1; + if(yn >= dsc->src_h) return false; + + yr = (0xFF - ys_fract) + 0x80; + + if(dsc->native_color) { + memcpy(&c_dest_yn, &src_u8[px + px_size * dsc->src_w], sizeof(lv_color_t)); + if(dsc->has_alpha) opa_dest_yn = src_u8[px + px_size * dsc->src_w + 2 * px_size - 1]; + } else { + c_dest_yn = lv_img_buf_get_px_color(&dsc->img_dsc, yn, y, dsc->color); + if(dsc->has_alpha) opa_dest_yn = lv_img_buf_get_px_alpha(&dsc->img_dsc, yn, y); + } + + c_y_dest = lv_color_mix(c_dest_int, c_dest_yn, yr); + if(dsc->has_alpha) opa_y_dest = (opa_dest_int * yr + (opa_dest_yn * (255 - yr))) >> 8; + } else { + c_y_dest.full = c_dest_int.full; + opa_y_dest = opa_dest_int; + } + + dsc->res_color = lv_color_mix(c_x_dest, c_y_dest, LV_OPA_50); + if(dsc->has_alpha) dsc->res_opa = (opa_x_dest + opa_y_dest) >> 1; + + return true; +} + +/** + * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` + * @param dsc pointer to an image descriptor + * @param id the palette color to set: + * - for `LV_IMG_CF_INDEXED1`: 0..1 + * - for `LV_IMG_CF_INDEXED2`: 0..3 + * - for `LV_IMG_CF_INDEXED4`: 0..15 + * - for `LV_IMG_CF_INDEXED8`: 0..255 + * @param c the color to set + */ +void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c) +{ + if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) || + (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) { + LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'"); + return; + } + + lv_color32_t c32; + c32.full = lv_color_to32(c); + uint8_t * buf = (uint8_t *)dsc->data; + memcpy(&buf[id * sizeof(c32)], &c32, sizeof(c32)); +} + +/** + * Allocate an image buffer in RAM + * @param w width of image + * @param h height of image + * @param cf a color format (`LV_IMG_CF_...`) + * @return an allocated image, or NULL on failure + */ +lv_img_dsc_t *lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + /* Allocate image descriptor */ + lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t)); + if(dsc == NULL) + return NULL; + + memset(dsc, 0, sizeof(lv_img_dsc_t)); + + /* Get image data size */ + dsc->data_size = lv_img_buf_get_img_size(w, h, cf); + if(dsc->data_size == 0) { + lv_mem_free(dsc); + return NULL; + } + + /* Allocate raw buffer */ + dsc->data = lv_mem_alloc(dsc->data_size); + if(dsc->data == NULL) { + lv_mem_free(dsc); + return NULL; + } + memset((uint8_t *)dsc->data, 0, dsc->data_size); + + /* Fill in header */ + dsc->header.always_zero = 0; + dsc->header.w = w; + dsc->header.h = h; + dsc->header.cf = cf; + return dsc; +} + +/** + * Free an allocated image buffer + * @param dsc image buffer to free + */ +void lv_img_buf_free(lv_img_dsc_t *dsc) +{ + if(dsc != NULL) { + if(dsc->data != NULL) + lv_mem_free(dsc->data); + + lv_mem_free(dsc); + } +} + +/** + * Get the memory consumption of a raw bitmap, given color format and dimensions. + * @param w width + * @param h height + * @param cf color format + * @return size in bytes + */ +uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + switch(cf) { + case LV_IMG_CF_TRUE_COLOR: return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h); + case LV_IMG_CF_TRUE_COLOR_ALPHA: return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h); + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h); + case LV_IMG_CF_ALPHA_1BIT: return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h); + case LV_IMG_CF_ALPHA_2BIT: return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h); + case LV_IMG_CF_ALPHA_4BIT: return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h); + case LV_IMG_CF_ALPHA_8BIT: return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h); + case LV_IMG_CF_INDEXED_1BIT: return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h); + case LV_IMG_CF_INDEXED_2BIT: return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h); + case LV_IMG_CF_INDEXED_4BIT: return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h); + case LV_IMG_CF_INDEXED_8BIT: return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h); + default: return 0; + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/src/lv_draw/lv_img_buf.h b/src/lv_draw/lv_img_buf.h new file mode 100644 index 000000000..ec8f42671 --- /dev/null +++ b/src/lv_draw/lv_img_buf.h @@ -0,0 +1,241 @@ +/** + * @file lv_img_buf.h + * + */ + +#ifndef LV_IMG_BUF_H +#define LV_IMG_BUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "../lv_misc/lv_color.h" + + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + + +#define LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h) +#define LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h) +#define LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h) + +/*+ 1: to be sure no fractional row*/ +#define LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h)) + +/*4 * X: for palette*/ +#define LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2) +#define LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4) +#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16) +#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256) + +/********************** + * TYPEDEFS + **********************/ + +/*Image color format*/ +enum { + LV_IMG_CF_UNKNOWN = 0, + + LV_IMG_CF_RAW, /**< Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /**< Contains the file as it is. The image has alpha. Needs custom decoder + function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /**< Contains the file as it is. The image is chroma keyed. Needs + custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /**< Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /**< Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /**< Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels + will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /**< Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /**< Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /**< Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /**< Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /**< Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /**< Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/ + + LV_IMG_CF_RESERVED_15, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_16, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_17, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_18, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_19, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_20, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_21, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_22, /**< Reserved for further use. */ + LV_IMG_CF_RESERVED_23, /**< Reserved for further use. */ + + LV_IMG_CF_USER_ENCODED_0, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_1, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_2, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_3, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_4, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_5, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_6, /**< User holder encoding format. */ + LV_IMG_CF_USER_ENCODED_7, /**< User holder encoding format. */ +}; +typedef uint8_t lv_img_cf_t; + + +/** + * LittlevGL image header + */ +typedef struct +{ + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a + non-printable character*/ + + uint32_t reserved : 2; /*Reserved to be used later*/ + + uint32_t w : 11; /*Width of the image map*/ + uint32_t h : 11; /*Height of the image map*/ +} lv_img_header_t; + + +/** Image header it is compatible with + * the result from image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + + +typedef struct { + lv_color_t res_color; + lv_opa_t res_opa; + + const void * src; + lv_coord_t src_w; + lv_coord_t src_h; + lv_coord_t pivot_x; + lv_coord_t pivot_y; + int32_t pivot_x_256; + int32_t pivot_y_256; + lv_img_dsc_t img_dsc; + int32_t sinma; + int32_t cosma; + int16_t angle; + lv_color_t color; + lv_img_cf_t cf; + + uint8_t chroma_keyed :1; + uint8_t has_alpha :1; + uint8_t native_color :1; + +}lv_img_rotate_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + + +/** + * Get the color of an image's pixel + * @param dsc an image descriptor + * @param x x coordinate of the point to get + * @param y x coordinate of the point to get + * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. + * Not used in other cases. + * @return color of the point + */ +lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color); + + +/** + * Get the alpha value of an image's pixel + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return alpha value of the point + */ +lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y); + + +void lv_img_buf_rotate_init(lv_img_rotate_dsc_t * dsc, int16_t angle, const void * src, lv_coord_t src_w, lv_coord_t src_h, + lv_img_cf_t cf, lv_coord_t pivot_x, lv_coord_t pivot_y, lv_color_t color); + +bool lv_img_buf_get_px_rotated(lv_img_rotate_dsc_t * dsc, lv_coord_t x, lv_coord_t y); + +/** + * Set the color of a pixel of an image. The alpha channel won't be affected. + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set the alpha value of a pixel of an image. The color won't be affected + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param opa the desired opacity + */ +void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa); + +/** + * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` + * @param dsc pointer to an image descriptor + * @param id the palette color to set: + * - for `LV_IMG_CF_INDEXED1`: 0..1 + * - for `LV_IMG_CF_INDEXED2`: 0..3 + * - for `LV_IMG_CF_INDEXED4`: 0..15 + * - for `LV_IMG_CF_INDEXED8`: 0..255 + * @param c the color to set + */ +void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c); + +/** + * Free an allocated image buffer + * @param dsc image buffer to free + */ +void lv_img_buf_free(lv_img_dsc_t *dsc); + +/** + * Get the memory consumption of a raw bitmap, given color format and dimensions. + * @param w width + * @param h height + * @param cf color format + * @return size in bytes + */ +uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMG_BUF_H*/ diff --git a/src/lv_draw/lv_img_decoder.c b/src/lv_draw/lv_img_decoder.c index 9de06d5ea..e97afd805 100644 --- a/src/lv_draw/lv_img_decoder.c +++ b/src/lv_draw/lv_img_decoder.c @@ -374,7 +374,7 @@ lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder cf == LV_IMG_CF_INDEXED_8BIT) { #if LV_IMG_CF_INDEXED - uint8_t px_size = lv_img_color_format_get_px_size(cf); + uint8_t px_size = lv_img_cf_get_px_size(cf); uint32_t palette_size = 1 << px_size; /*Allocate the palette*/ @@ -527,7 +527,7 @@ static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * d #if LV_USE_FILESYSTEM lv_img_decoder_built_in_data_t * user_data = dsc->user_data; lv_fs_res_t res; - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf); uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3; pos += 4; /*Skip the header*/ @@ -579,7 +579,7 @@ static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, l } const lv_opa_t * opa_table = NULL; - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf); uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ lv_coord_t w = 0; @@ -665,7 +665,7 @@ static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, { #if LV_IMG_CF_INDEXED - uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf); uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ lv_coord_t w = 0; diff --git a/src/lv_draw/lv_img_decoder.h b/src/lv_draw/lv_img_decoder.h index fb7af8324..a1713e0c0 100644 --- a/src/lv_draw/lv_img_decoder.h +++ b/src/lv_draw/lv_img_decoder.h @@ -20,6 +20,7 @@ extern "C" { #endif #include +#include "lv_img_buf.h" #include "../lv_misc/lv_fs.h" #include "../lv_misc/lv_types.h" #include "../lv_misc/lv_area.h" @@ -28,14 +29,6 @@ extern "C" { /********************* * DEFINES *********************/ -/*If image pixels contains alpha we need to know how much byte is a pixel*/ -#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 -#define LV_IMG_PX_SIZE_ALPHA_BYTE 2 -#elif LV_COLOR_DEPTH == 16 -#define LV_IMG_PX_SIZE_ALPHA_BYTE 3 -#elif LV_COLOR_DEPTH == 32 -#define LV_IMG_PX_SIZE_ALPHA_BYTE 4 -#endif /********************** * TYPEDEFS @@ -51,78 +44,6 @@ enum { }; typedef uint8_t lv_img_src_t; -/** - * LittlevGL image header - */ -typedef struct -{ - - /* The first 8 bit is very important to distinguish the different source types. - * For more info see `lv_img_get_src_type()` in lv_img.c */ - uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/ - uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a - non-printable character*/ - - uint32_t reserved : 2; /*Reserved to be used later*/ - - uint32_t w : 11; /*Width of the image map*/ - uint32_t h : 11; /*Height of the image map*/ -} lv_img_header_t; - -/*Image color format*/ -enum { - LV_IMG_CF_UNKNOWN = 0, - - LV_IMG_CF_RAW, /**< Contains the file as it is. Needs custom decoder function*/ - LV_IMG_CF_RAW_ALPHA, /**< Contains the file as it is. The image has alpha. Needs custom decoder - function*/ - LV_IMG_CF_RAW_CHROMA_KEYED, /**< Contains the file as it is. The image is chroma keyed. Needs - custom decoder function*/ - - LV_IMG_CF_TRUE_COLOR, /**< Color format and depth should match with LV_COLOR settings*/ - LV_IMG_CF_TRUE_COLOR_ALPHA, /**< Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ - LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /**< Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels - will be transparent*/ - - LV_IMG_CF_INDEXED_1BIT, /**< Can have 2 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_2BIT, /**< Can have 4 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_4BIT, /**< Can have 16 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_8BIT, /**< Can have 256 different colors in a palette (always chroma keyed)*/ - - LV_IMG_CF_ALPHA_1BIT, /**< Can have one color and it can be drawn or not*/ - LV_IMG_CF_ALPHA_2BIT, /**< Can have one color but 4 different alpha value*/ - LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/ - LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/ - - LV_IMG_CF_RESERVED_15, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_16, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_17, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_18, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_19, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_20, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_21, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_22, /**< Reserved for further use. */ - LV_IMG_CF_RESERVED_23, /**< Reserved for further use. */ - - LV_IMG_CF_USER_ENCODED_0, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_1, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_2, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_3, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_4, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_5, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_6, /**< User holder encoding format. */ - LV_IMG_CF_USER_ENCODED_7, /**< User holder encoding format. */ -}; -typedef uint8_t lv_img_cf_t; - -/** Image header it is compatible with - * the result from image converter utility*/ -typedef struct -{ - lv_img_header_t header; - uint32_t data_size; - const uint8_t * data; -} lv_img_dsc_t; /* Decoder function definitions */ diff --git a/src/lv_objx/lv_canvas.c b/src/lv_objx/lv_canvas.c index d19bf7ce1..2011b1929 100644 --- a/src/lv_objx/lv_canvas.c +++ b/src/lv_objx/lv_canvas.c @@ -143,7 +143,7 @@ void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_ ext->dsc.header.w = w; ext->dsc.header.h = h; ext->dsc.data = buf; - ext->dsc.data_size = (lv_img_color_format_get_px_size(cf) * w * h) / 8; + ext->dsc.data_size = (lv_img_cf_get_px_size(cf) * w * h) / 8; lv_img_set_src(canvas, &ext->dsc); } @@ -282,7 +282,7 @@ void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t x, l return; } - uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3; + uint32_t px_size = lv_img_cf_get_px_size(ext->dsc.header.cf) >> 3; uint32_t px = ext->dsc.header.w * y * px_size + x * px_size; uint8_t * to_copy8 = (uint8_t *)to_copy; lv_coord_t i; @@ -325,24 +325,24 @@ void lv_canvas_rotate(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, lv_c bool ret; lv_img_rotate_dsc_t dsc; - lv_img_rotate_init(&dsc, angle, img->data, img->header.w, img->header.h, img->header.cf, pivot_x, pivot_y, style->image.color); + lv_img_buf_rotate_init(&dsc, angle, img->data, img->header.w, img->header.h, img->header.cf, pivot_x, pivot_y, style->image.color); for(x = -offset_x; x < dest_width - offset_x; x++) { for(y = -offset_y; y < dest_height - offset_y; y++) { - ret = lv_img_get_px_rotated(&dsc, x, y); + ret = lv_img_buf_get_px_rotated(&dsc, x, y); if(ret == false) continue; if(x + offset_x >= 0 && x + offset_x < dest_width && y + offset_y >= 0 && y + offset_y < dest_height) { /*If the image has no alpha channel just simple set the result color on the canvas*/ - if(lv_img_color_format_has_alpha(img->header.cf) == false) { + if(lv_img_cf_has_alpha(img->header.cf) == false) { lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, dsc.res_color); } else { lv_color_t bg_color = lv_img_buf_get_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, style->image.color); /*If the canvas has no alpha but the image has mix the image's color with * canvas*/ - if(lv_img_color_format_has_alpha(ext_dst->dsc.header.cf) == false) { + if(lv_img_cf_has_alpha(ext_dst->dsc.header.cf) == false) { if(dsc.res_opa < LV_OPA_MAX) dsc.res_color = lv_color_mix(dsc.res_color, bg_color, dsc.res_opa); lv_img_buf_set_px_color(&ext_dst->dsc, x + offset_x, y + offset_y, dsc.res_color); } diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index 1875b1d78..6349f9eb4 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -447,10 +447,8 @@ static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param) if(ext->angle) { lv_sqrt_res_t ds; lv_sqrt(ext->w * ext->w + ext->h * ext->h, &ds); - printf("%d %d %d\n", ext->w, ext->h, ds.i); lv_coord_t d = (ds.i - LV_MATH_MIN(ext->w, ext->h)) / 2; - img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, d); } }