1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00

add lv_img_get_px_rotated

This commit is contained in:
Gabor Kiss-Vamosi 2019-11-01 06:00:04 +01:00
parent b8a156e0d4
commit b8f5cad89c
3 changed files with 191 additions and 167 deletions

View File

@ -12,6 +12,7 @@
#include "../lv_misc/lv_log.h"
#include "../lv_core/lv_refr.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
@ -76,12 +77,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) {
@ -146,10 +146,7 @@ lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t
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;
p_color = color;
}
return p_color;
}
@ -342,6 +339,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
@ -554,8 +648,8 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
successfully.*/
}
lv_opa_t opa = style->image.opa;
if(opa_scale != LV_OPA_COVER) opa = (opa * opa_scale) >> 8;
lv_opa_t opa =
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);
@ -572,7 +666,8 @@ 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->image.color,
style->image.intense);
}
/* The whole uncompressed image is not available. Try to read it line-by-line*/
else {

View File

@ -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

View File

@ -218,7 +218,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);
}
/**
@ -312,115 +314,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*/