From a69d75c3d2bb9d75ea4c4cd1328b68e22b083d51 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sun, 3 Nov 2019 15:48:07 +0100 Subject: [PATCH] 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); } }