1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

feat(draw): add generic draw image helpers (#5008)

This commit is contained in:
Gabor Kiss-Vamosi 2023-12-14 18:46:42 +01:00 committed by GitHub
parent 492a474f5f
commit 0d60129469
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 170 additions and 129 deletions

View File

@ -26,6 +26,11 @@
* STATIC PROTOTYPES
**********************/
static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
lv_image_decoder_dsc_t * decoder_dsc,
const lv_area_t * img_area, const lv_area_t * clipped_img_area,
lv_draw_image_core_cb draw_core_cb);
/**********************
* STATIC VARIABLES
**********************/
@ -116,6 +121,131 @@ lv_image_src_t lv_image_src_get_type(const void * src)
return img_src_type;
}
void _lv_draw_image_normal_helper(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb)
{
if(draw_core_cb == NULL) {
LV_LOG_WARN("draw_core_cb is NULL");
return;
}
lv_area_t draw_area;
lv_area_copy(&draw_area, coords);
if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) {
int32_t w = lv_area_get_width(coords);
int32_t h = lv_area_get_height(coords);
_lv_image_buf_get_transformed_area(&draw_area, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y,
&draw_dsc->pivot);
draw_area.x1 += coords->x1;
draw_area.y1 += coords->y1;
draw_area.x2 += coords->x1;
draw_area.y2 += coords->y1;
}
lv_area_t clipped_img_area;
if(!_lv_area_intersect(&clipped_img_area, &draw_area, draw_unit->clip_area)) {
return;
}
lv_image_decoder_dsc_t decoder_dsc;
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
if(res != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to open image");
return;
}
img_decode_and_draw(draw_unit, draw_dsc, &decoder_dsc, coords, &clipped_img_area, draw_core_cb);
lv_image_decoder_close(&decoder_dsc);
}
void _lv_draw_image_tiled_helper(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb)
{
if(draw_core_cb == NULL) {
LV_LOG_WARN("draw_core_cb is NULL");
return;
}
lv_image_decoder_dsc_t decoder_dsc;
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
if(res != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to open image");
return;
}
int32_t img_w = lv_area_get_width(coords);
int32_t img_h = lv_area_get_height(coords);
lv_area_t tile_area = *coords;
int32_t tile_x_start = tile_area.x1;
while(tile_area.y1 <= draw_unit->clip_area->y2) {
while(tile_area.x1 <= draw_unit->clip_area->x2) {
lv_area_t clipped_img_area;
if(_lv_area_intersect(&clipped_img_area, &tile_area, draw_unit->clip_area)) {
img_decode_and_draw(draw_unit, draw_dsc, &decoder_dsc, &tile_area, &clipped_img_area, draw_core_cb);
}
tile_area.x1 += img_w;
tile_area.x2 += img_w;
}
tile_area.y1 += img_h;
tile_area.y2 += img_h;
tile_area.x1 = tile_x_start;
tile_area.x2 = tile_x_start + img_w - 1;
}
lv_image_decoder_close(&decoder_dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
lv_image_decoder_dsc_t * decoder_dsc,
const lv_area_t * img_area, const lv_area_t * clipped_img_area,
lv_draw_image_core_cb draw_core_cb)
{
lv_draw_image_sup_t sup;
sup.alpha_color = draw_dsc->recolor;
sup.palette = decoder_dsc->palette;
sup.palette_size = decoder_dsc->palette_size;
/*The whole image is available, just draw it*/
if(decoder_dsc->decoded || decoder_dsc->img_data) {
draw_core_cb(draw_unit, draw_dsc, decoder_dsc, &sup, img_area, clipped_img_area);
}
/*Draw in smaller pieces*/
else {
lv_area_t relative_full_area_to_decode = *clipped_img_area;
lv_area_move(&relative_full_area_to_decode, -img_area->x1, -img_area->y1);
lv_area_t relative_decoded_area;
relative_decoded_area.x1 = LV_COORD_MIN;
relative_decoded_area.y1 = LV_COORD_MIN;
relative_decoded_area.x2 = LV_COORD_MIN;
relative_decoded_area.y2 = LV_COORD_MIN;
lv_result_t res = LV_RESULT_OK;
while(res == LV_RESULT_OK) {
res = lv_image_decoder_get_area(decoder_dsc, &relative_full_area_to_decode, &relative_decoded_area);
lv_area_t absolute_decoded_area = relative_decoded_area;
lv_area_move(&absolute_decoded_area, img_area->x1, img_area->y1);
if(res == LV_RESULT_OK) {
/*Limit draw area to the current decoded area and draw the image*/
lv_area_t clipped_img_area_sub;
if(_lv_area_intersect(&clipped_img_area_sub, clipped_img_area, &absolute_decoded_area)) {
draw_core_cb(draw_unit, draw_dsc, decoder_dsc, &sup,
&absolute_decoded_area, &clipped_img_area_sub);
}
}
}
}
}

View File

@ -60,6 +60,18 @@ typedef struct _lv_draw_image_dsc_t {
lv_draw_image_sup_t * sup;
} lv_draw_image_dsc_t;
/**
* PErform the actual rendering of a decoded image
* @param draw_unit pointer to a draw unit
* @param draw_dsc the draw descriptor of the image
* @param decoder_dsc pointer to the decoded image's descriptor
* @param sup supplementary data
* @param img_coords the absolute coordinates of the image
* @param clipped_img_area the absolute clip coordinates
*/
typedef void (*lv_draw_image_core_cb)(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup,
const lv_area_t * img_coords, const lv_area_t * clipped_img_area);
struct _lv_layer_t;
/**********************
@ -94,6 +106,28 @@ void lv_draw_layer(struct _lv_layer_t * layer, const lv_draw_image_dsc_t * dsc,
*/
lv_image_src_t lv_image_src_get_type(const void * src);
/**
* Can be used by draw units to handle the decoding and
* prepare everything for the actual image rendering
* @param draw_unit pointer to a draw unit
* @param draw_dsc the draw descriptor of the image
* @param coords the absolute coordinates of the image
* @param draw_core_cb a callback to perform the actual rendering
*/
void _lv_draw_image_normal_helper(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb);
/**
* Can be used by draw units for TILED images to handle the decoding and
* prepare everything for the actual image rendering
* @param draw_unit pointer to a draw unit
* @param draw_dsc the draw descriptor of the image
* @param coords the absolute coordinates of the image
* @param draw_core_cb a callback to perform the actual rendering
*/
void _lv_draw_image_tiled_helper(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb);
#ifdef __cplusplus
} /*extern "C"*/
#endif

View File

@ -22,6 +22,7 @@ extern "C" {
#include "../../osal/lv_os.h"
#include "../../draw/lv_draw_vector.h"
/*********************
* DEFINES
*********************/

View File

@ -33,16 +33,6 @@
* STATIC PROTOTYPES
**********************/
static void img_draw_normal(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords);
static void img_draw_tiled(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords);
static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
lv_image_decoder_dsc_t * decoder_dsc,
const lv_area_t * img_area, const lv_area_t * clipped_img_area);
static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup,
const lv_area_t * img_coords, const lv_area_t * clipped_img_area);
@ -164,126 +154,16 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_image(lv_draw_unit_t * draw_unit, const lv
const lv_area_t * coords)
{
if(!draw_dsc->tile) {
img_draw_normal(draw_unit, draw_dsc, coords);
_lv_draw_image_normal_helper(draw_unit, draw_dsc, coords, img_draw_core);
}
else {
img_draw_tiled(draw_unit, draw_dsc, coords);
_lv_draw_image_tiled_helper(draw_unit, draw_dsc, coords, img_draw_core);
}
}
static void img_draw_normal(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords)
{
lv_area_t draw_area;
lv_area_copy(&draw_area, coords);
if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) {
int32_t w = lv_area_get_width(coords);
int32_t h = lv_area_get_height(coords);
_lv_image_buf_get_transformed_area(&draw_area, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y,
&draw_dsc->pivot);
draw_area.x1 += coords->x1;
draw_area.y1 += coords->y1;
draw_area.x2 += coords->x1;
draw_area.y2 += coords->y1;
}
lv_area_t clipped_img_area;
if(!_lv_area_intersect(&clipped_img_area, &draw_area, draw_unit->clip_area)) {
return;
}
lv_image_decoder_dsc_t decoder_dsc;
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
if(res != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to open image");
return;
}
img_decode_and_draw(draw_unit, draw_dsc, &decoder_dsc, coords, &clipped_img_area);
lv_image_decoder_close(&decoder_dsc);
}
static void img_draw_tiled(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords)
{
lv_image_decoder_dsc_t decoder_dsc;
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
if(res != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to open image");
return;
}
int32_t img_w = lv_area_get_width(coords);
int32_t img_h = lv_area_get_height(coords);
lv_area_t tile_area = *coords;
int32_t tile_x_start = tile_area.x1;
while(tile_area.y1 <= draw_unit->clip_area->y2) {
while(tile_area.x1 <= draw_unit->clip_area->x2) {
lv_area_t clipped_img_area;
if(_lv_area_intersect(&clipped_img_area, &tile_area, draw_unit->clip_area)) {
img_decode_and_draw(draw_unit, draw_dsc, &decoder_dsc, &tile_area, &clipped_img_area);
}
tile_area.x1 += img_w;
tile_area.x2 += img_w;
}
tile_area.y1 += img_h;
tile_area.y2 += img_h;
tile_area.x1 = tile_x_start;
tile_area.x2 = tile_x_start + img_w - 1;
}
lv_image_decoder_close(&decoder_dsc);
}
static void img_decode_and_draw(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
lv_image_decoder_dsc_t * decoder_dsc,
const lv_area_t * img_area, const lv_area_t * clipped_img_area)
{
lv_draw_image_sup_t sup;
sup.alpha_color = draw_dsc->recolor;
sup.palette = decoder_dsc->palette;
sup.palette_size = decoder_dsc->palette_size;
/*The whole image is available, just draw it*/
if(decoder_dsc->decoded || decoder_dsc->img_data) {
img_draw_core(draw_unit, draw_dsc, decoder_dsc, &sup, img_area, clipped_img_area);
}
/*Draw in smaller pieces*/
else {
lv_area_t relative_full_area_to_decode = *clipped_img_area;
lv_area_move(&relative_full_area_to_decode, -img_area->x1, -img_area->y1);
lv_area_t relative_decoded_area;
relative_decoded_area.x1 = LV_COORD_MIN;
relative_decoded_area.y1 = LV_COORD_MIN;
relative_decoded_area.x2 = LV_COORD_MIN;
relative_decoded_area.y2 = LV_COORD_MIN;
lv_result_t res = LV_RESULT_OK;
while(res == LV_RESULT_OK) {
res = lv_image_decoder_get_area(decoder_dsc, &relative_full_area_to_decode, &relative_decoded_area);
lv_area_t absolute_decoded_area = relative_decoded_area;
lv_area_move(&absolute_decoded_area, img_area->x1, img_area->y1);
if(res == LV_RESULT_OK) {
/*Limit draw area to the current decoded area and draw the image*/
lv_area_t clipped_img_area_sub;
if(_lv_area_intersect(&clipped_img_area_sub, clipped_img_area, &absolute_decoded_area)) {
img_draw_core(draw_unit, draw_dsc, decoder_dsc, &sup,
&absolute_decoded_area, &clipped_img_area_sub);
}
}
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup,
@ -504,8 +384,4 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_SW*/