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

feat(snapshot) add API to take snapshot for object (#2353)

* Fix image zooming causes unexpected object size.

Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>

* add lv_snapshot_take API.

* fix(img) invalidate size and layout on zoom and angle change

* fix(img) not self-repeating under some zoom level.

* fix(snapshot) fix to keep the original position

* Move various set_px_cb_xx functions to lv_hal_disp.c

* add snapshot API to store image to provided buffer

* minor fixes and refactoring

* Move snapshot source to extra/others/snapshot.

1. Update parameter buff to buf.
2. Add macro to disable lv_snapshot, enabled by default.

* docs(others) add the others folder with snapshot.md

* docs(snapshot) added doc and example for snapshot.

1. Update doc snapshot.md
2. Add example lv_example_snapshot_1 to folder examples/others/snapshot
3. Update lv_conf_template.h and lv_conf_internal.h
4. Remove lv_snapshot.c from lv_misc.mk
5. Add others to index.md

Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>

* add micropython example for snapshot

Co-authored-by: Xu Xingliang <xuxingliang@xiaomi.com>
Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
Neo 2021-07-19 20:46:28 +08:00 committed by GitHub
parent 690b3546d6
commit c98c8252ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 791 additions and 144 deletions

View File

@ -34,6 +34,7 @@ PDF version: :download:`LVGL.pdf <LVGL.pdf>`
overview/index
widgets/index
layouts/index
others/index
CONTRIBUTING
CHANGELOG
ROADMAP

16
docs/others/index.md Normal file
View File

@ -0,0 +1,16 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/others/index.md
```
# Others
```eval_rst
.. toctree::
:maxdepth: 1
snapshot
```

67
docs/others/snapshot.md Normal file
View File

@ -0,0 +1,67 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/others/snapshot.md
```
# Snapshot
Snapshot provides APIs to take snapshot image for LVGL object together with its children. The image will look exactly like the object.
## Usage
Simply call API `lv_snapshot_take` to generate the image descriptor which can be set as image object src using `lv_img_set_src`.
Note, only below color formats are supported for now:
- LV_IMG_CF_TRUE_COLOR_ALPHA
- LV_IMG_CF_ALPHA_1BIT
- LV_IMG_CF_ALPHA_2BIT
- LV_IMG_CF_ALPHA_4BIT
- LV_IMG_CF_ALPHA_8BIT
### Free the Image
The memory `lv_snapshot_take` uses are dynamically allocated using `lv_mem_alloc`. Use API `lv_snapshot_free` to free the memory it takes. This will firstly free memory the image data takes, then the image descriptor.
Take caution to free the snapshot but not delete the image object. Before free the memory, be sure to firstly unlink it from image object, using `lv_img_set_src(NULL)` and `lv_img_cache_invalidate_src(src)`.
Below code snippet explains usage of this API.
```c
void update_snapshot(lv_obj_t * obj, lv_obj_t * img_snapshot)
{
lv_img_dsc_t* snapshot = (void*)lv_img_get_src(img_snapshot);
if(snapshot) {
lv_snapshot_free(snapshot);
}
snapshot = lv_snapshot_take(obj, LV_IMG_CF_TRUE_COLOR_ALPHA);
lv_img_set_src(img_snapshot, snapshot);
}
```
### Use Existing Buffer
If the snapshot needs update now and then, or simply caller provides memory, use API `lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * dsc, void * buf, uint32_t buff_size);` for this case. It's caller's responsibility to alloc/free the memory.
If snapshot is generated successfully, the image descriptor is updated and image data will be stored to provided `buf`.
Note that snapshot may fail if provided buffer is not enough, which may happen when object size changes. It's recommended to use API `lv_snapshot_buf_size_needed` to check the needed buffer size in byte firstly and resize the buffer accordingly.
## Example
```eval_rst
.. include:: ../../examples/others/snapshot/index.rst
```
## API
```eval_rst
.. doxygenfile:: lv_snapshot.h
:project: lvgl
```

View File

@ -218,3 +218,5 @@ In both cases ORed state values can be used as well. E.g. `lv_obj_add_state(obj,
To learn more about the states read the related section of the [Style overview](/overview/style).
## Snapshot
A snapshot image could be generated for object together with its children. Check details in [Snapshot](/others/snapshot).

View File

@ -23,6 +23,7 @@ extern "C" {
#include "anim/lv_example_anim.h"
#include "event/lv_example_event.h"
#include "styles/lv_example_style.h"
#include "others/lv_example_others.h"
/*********************
* DEFINES

View File

@ -0,0 +1,37 @@
/**
* @file lv_example_others.h
*
*/
#ifndef LV_EXAMPLE_OTHERS_H
#define LV_EXAMPLE_OTHERS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "snapshot/lv_example_snapshot.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EX_OTHERS_H*/

View File

@ -0,0 +1,8 @@
Simple snapshot example
"""""""""""""""""""
.. lv_example:: others/snapshot/lv_example_snapshot_1
:language: c

View File

@ -0,0 +1,38 @@
/**
* @file lv_example_snapshot.h
*
*/
#ifndef LV_EX_SNAPSHOT_H
#define LV_EX_SNAPSHOT_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_snapshot_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EX_GET_STARTED_H*/

View File

@ -0,0 +1,57 @@
#include "../../lv_examples.h"
#if LV_USE_SNAPSHOT && LV_BUILD_EXAMPLES
static void event_cb(lv_event_t* e)
{
lv_obj_t * snapshot_obj = lv_event_get_user_data(e);
lv_obj_t * img = lv_event_get_target(e);
if(snapshot_obj) {
lv_img_dsc_t* snapshot = (void*)lv_img_get_src(snapshot_obj);
if(snapshot){
lv_snapshot_free(snapshot);
}
/*Update the snapshot, we know parent of object is the container.*/
snapshot = lv_snapshot_take(img->parent, LV_IMG_CF_TRUE_COLOR_ALPHA);
if(snapshot == NULL)
return;
lv_img_set_src(snapshot_obj, snapshot);
}
}
void lv_example_snapshot_1(void)
{
LV_IMG_DECLARE(img_star);
lv_obj_t * root = lv_scr_act();
lv_obj_set_style_bg_color(root, lv_palette_main(LV_PALETTE_LIGHT_BLUE), 0);
/*Create an image object to show snapshot*/
lv_obj_t * snapshot_obj = lv_img_create(root);
lv_obj_set_style_bg_color(snapshot_obj, lv_palette_main(LV_PALETTE_PURPLE), 0);
lv_obj_set_style_bg_opa(snapshot_obj, LV_OPA_100, 0);
lv_img_set_zoom(snapshot_obj, 128);
/*Create the container and its children*/
lv_obj_t * container = lv_obj_create(root);
lv_obj_align(container, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_size(container, 180, 180);
lv_obj_set_flex_flow(container, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_flex_align(container, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_radius(container, 50, 0);
lv_obj_t * img;
int i;
for(i = 0; i < 4; i++) {
img = lv_img_create(container);
lv_img_set_src(img, &img_star);
lv_obj_set_style_bg_color(img, lv_color_black(), 0);
lv_obj_set_style_bg_opa(img, LV_OPA_COVER, 0);
lv_obj_set_style_transform_zoom(img, 400, LV_STATE_PRESSED);
lv_obj_add_flag(img, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_event_cb(img, event_cb, LV_EVENT_PRESSED, snapshot_obj);
lv_obj_add_event_cb(img, event_cb, LV_EVENT_RELEASED, snapshot_obj);
}
}
#endif

View File

@ -0,0 +1,70 @@
import lvgl as lv
from imagetools import get_png_info, open_png
# Register PNG image decoder
decoder = lv.img.decoder_create()
decoder.info_cb = get_png_info
decoder.open_cb = open_png
# Measure memory usage
gc.enable()
gc.collect()
mem_free = gc.mem_free()
label = lv.label(lv.scr_act())
label.align(lv.ALIGN.BOTTOM_MID, 0, -10)
label.set_text(" memory free:" + str(mem_free/1024) + " kB")
# Create an image from the png file
try:
with open('../../assets/img_star.png','rb') as f:
png_data = f.read()
except:
print("Could not find img_star.png")
sys.exit()
img_star = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
def event_cb(e, snapshot_obj):
img = e.get_target()
if snapshot_obj:
# no need to free the old source for snapshot_obj, gc will free it for us.
# take a new snapshot, overwrite the old one
dsc = lv.snapshot_take(img.get_parent(), lv.img.CF.TRUE_COLOR_ALPHA)
snapshot_obj.set_src(dsc)
gc.collect()
mem_used = mem_free - gc.mem_free()
label.set_text("memory used:" + str(mem_used/1024) + " kB")
root = lv.scr_act()
root.set_style_bg_color(lv.palette_main(lv.PALETTE.LIGHT_BLUE), 0)
# Create an image object to show snapshot
snapshot_obj = lv.img(root)
snapshot_obj.set_style_bg_color(lv.palette_main(lv.PALETTE.PURPLE), 0)
snapshot_obj.set_style_bg_opa(lv.OPA.COVER, 0)
snapshot_obj.set_zoom(128)
# Create the container and its children
container = lv.obj(root)
container.align(lv.ALIGN.CENTER, 0, 0)
container.set_size(180, 180)
container.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
container.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
container.set_style_radius(50, 0)
for i in range(4):
img = lv.img(container)
img.set_src(img_star)
img.set_style_bg_color(lv.palette_main(lv.PALETTE.GREY), 0)
img.set_style_bg_opa(lv.OPA.COVER, 0)
img.set_style_transform_zoom(400, lv.STATE.PRESSED)
img.add_flag(img.FLAG.CLICKABLE)
img.add_event_cb(lambda e: event_cb(e, snapshot_obj), lv.EVENT.PRESSED, None)
img.add_event_cb(lambda e: event_cb(e, snapshot_obj), lv.EVENT.RELEASED, None)

View File

@ -214,6 +214,9 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
#endif /*LV_ENABLE_GC*/
/*1: Enable API to take snapshot for object*/
#define LV_USE_SNAPSHOT 1
/*=====================
* COMPILER SETTINGS
*====================*/

1
lvgl.h
View File

@ -70,6 +70,7 @@ extern "C" {
#include "src/extra/widgets/lv_widgets.h"
#include "src/extra/layouts/lv_layouts.h"
#include "src/extra/themes/lv_themes.h"
#include "src/extra/others/lv_others.h"
/*********************
* DEFINES

View File

@ -0,0 +1,38 @@
/**
* @file lv_others.h
*
*/
#ifndef LV_OTHERS_H
#define LV_OTHERS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "snapshot/lv_snapshot.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_OTHERS_H*/

View File

@ -0,0 +1,213 @@
/**
* @file lv_snapshot.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_snapshot.h"
#if LV_USE_SNAPSHOT
#include <stdbool.h>
#include "../../../core/lv_disp.h"
#include "../../../core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/** Get the buffer needed for object snapshot image.
*
* @param obj The object to generate snapshot.
* @param cf color format for generated image.
*
* @return the buffer size needed in bytes
*/
uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_img_cf_t cf)
{
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_ALPHA:
case LV_IMG_CF_ALPHA_1BIT:
case LV_IMG_CF_ALPHA_2BIT:
case LV_IMG_CF_ALPHA_4BIT:
case LV_IMG_CF_ALPHA_8BIT:
break;
default:
return 0;
}
lv_obj_update_layout(obj);
/*Width and height determine snapshot image size.*/
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
uint8_t px_size = lv_img_cf_get_px_size(cf);
return w * h * ((px_size + 7) >> 3);
}
/** Take snapshot for object with its children, save image info to provided buffer.
*
* @param obj The object to generate snapshot.
* @param cf color format for generated image.
* @param dsc image descriptor to store the image result.
* @param buf the buffer to store image data.
* @param buff_size provided buffer size in bytes.
*
* @return LV_RES_OK on success, LV_RES_INV on error.
*/
lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * dsc, void * buf, uint32_t buff_size)
{
LV_ASSERT(dsc);
LV_ASSERT(buf);
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_ALPHA:
case LV_IMG_CF_ALPHA_1BIT:
case LV_IMG_CF_ALPHA_2BIT:
case LV_IMG_CF_ALPHA_4BIT:
case LV_IMG_CF_ALPHA_8BIT:
break;
default:
return LV_RES_INV;
}
if(lv_snapshot_buf_size_needed(obj, cf) > buff_size)
return LV_RES_INV;
/*Width and height determine snapshot image size.*/
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
/*Backup obj original info.*/
lv_disp_t * disp_old = lv_obj_get_disp(obj);
lv_obj_t * parent_old = lv_obj_get_parent(obj);
lv_memset(buf, 0x00, buff_size);
lv_memset_00(dsc, sizeof(lv_img_dsc_t));
/*We are safe to use stack for below variables since disp will be
* unregistered when function returns. */
lv_disp_t * disp;
lv_disp_drv_t driver;
lv_disp_draw_buf_t draw_buf;
lv_disp_draw_buf_init(&draw_buf, buf, NULL, w * h);
lv_disp_drv_init(&driver);
driver.draw_buf = &draw_buf;
driver.hor_res = lv_disp_get_hor_res(disp_old);
driver.ver_res = lv_disp_get_ver_res(disp_old);
lv_disp_drv_use_generic_set_px_cb(&driver, cf);
disp = lv_disp_drv_register(&driver);
if(disp == NULL) {
return LV_RES_INV;
}
/*Make background transparent */
lv_disp_set_bg_opa(disp, LV_OPA_TRANSP);
/*Move obj to newly created disp and refresh it. */
lv_obj_t * screen = lv_disp_get_scr_act(disp);
lv_obj_remove_style_all(screen);
lv_obj_allocate_spec_attr(screen);
screen->spec_attr->child_cnt = 1;
screen->spec_attr->children = &obj;
obj->parent = screen;
disp->inv_p = 0;
lv_obj_invalidate(obj);
/*Don't call lv_refr_now to avoid animation disruption */
_lv_disp_refr_timer(disp->refr_timer);
/*Restore obj original parameters and clean up*/
obj->parent = parent_old;
screen->spec_attr->child_cnt = 0;
screen->spec_attr->children = NULL;
lv_disp_remove(disp);
dsc->data = buf;
dsc->header.w = w;
dsc->header.h = h;
dsc->header.cf = cf;
return LV_RES_OK;
}
/** Take snapshot for object with its children, alloc the memory needed.
*
* @param obj The object to generate snapshot.
* @param cf color format for generated image.
*
* @return a pointer to a image descriptor, or NULL if failed.
*/
lv_img_dsc_t * lv_snapshot_take(lv_obj_t * obj, lv_img_cf_t cf)
{
uint32_t buff_size = lv_snapshot_buf_size_needed(obj, cf);
void * buf = lv_mem_alloc(buff_size);
if(buf == NULL) {
return NULL;
}
lv_img_dsc_t * dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
if(dsc == NULL) {
lv_mem_free(buf);
return NULL;
}
if(lv_snapshot_take_to_buf(obj, cf, dsc, buf, buff_size) == LV_RES_INV) {
lv_mem_free(buf);
lv_mem_free(dsc);
return NULL;
}
return dsc;
}
/** Free the snapshot image returned by @ref lv_snapshot_take
*
* It will firstly free the data image takes, then the image descriptor.
*
* @param dsc The image descriptor generated by lv_snapshot_take.
*
*/
void lv_snapshot_free(lv_img_dsc_t * dsc)
{
if(!dsc)
return;
if(dsc->data)
lv_mem_free((void *)dsc->data);
lv_mem_free(dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_SNAPSHOT*/

View File

@ -0,0 +1,84 @@
/**
* @file lv_snapshot.h
*
*/
#ifndef LV_SNAPSHOT_H
#define LV_SNAPSHOT_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <stdint.h>
#include <stddef.h>
#include "../../../lv_conf_internal.h"
#include "../../../core/lv_obj.h"
/*********************
* DEFINES
*********************/
#if LV_USE_SNAPSHOT
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/** Take snapshot for object with its children.
*
* @param obj The object to generate snapshot.
* @param cf color format for generated image.
*
* @return a pointer to a image descriptor, or NULL if failed.
*/
lv_img_dsc_t * lv_snapshot_take(lv_obj_t * obj, lv_img_cf_t cf);
/** Free the snapshot image returned by @ref lv_snapshot_take
*
* It will firstly free the data image takes, then the image descriptor.
*
* @param dsc The image descriptor generated by lv_snapshot_take.
*
*/
void lv_snapshot_free(lv_img_dsc_t * dsc);
/** Get the buffer needed for object snapshot image.
*
* @param obj The object to generate snapshot.
* @param cf color format for generated image.
*
* @return the buffer size needed in bytes
*/
uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_img_cf_t cf);
/** Take snapshot for object with its children, save image info to provided buffer.
*
* @param obj The object to generate snapshot.
* @param cf color format for generated image.
* @param dsc image descriptor to store the image result.
* @param buff the buffer to store image data.
* @param buff_size provided buffer size in bytes.
*
* @return LV_RES_OK on success, LV_RES_INV on error.
*/
lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * dsc, void * buf, uint32_t buff_size);
/**********************
* MACROS
**********************/
#endif /*LV_USE_SNAPSHOT*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif

View File

@ -34,6 +34,24 @@
**********************/
static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data);
static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x,
lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
/**********************
* STATIC VARIABLES
**********************/
@ -403,6 +421,29 @@ lv_disp_rot_t lv_disp_get_rotation(lv_disp_t * disp)
return disp->driver->rotated;
}
void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf)
{
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_ALPHA:
disp_drv->set_px_cb = set_px_true_color_alpha;
break;
case LV_IMG_CF_ALPHA_1BIT:
disp_drv->set_px_cb = set_px_cb_alpha1;
break;
case LV_IMG_CF_ALPHA_2BIT:
disp_drv->set_px_cb = set_px_cb_alpha2;
break;
case LV_IMG_CF_ALPHA_4BIT:
disp_drv->set_px_cb = set_px_cb_alpha4;
break;
case LV_IMG_CF_ALPHA_8BIT:
disp_drv->set_px_cb = set_px_cb_alpha8;
break;
default:
disp_drv->set_px_cb = NULL;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
@ -413,3 +454,99 @@ static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_d
lv_obj_mark_layout_as_dirty(obj);
return LV_OBJ_TREE_WALK_NEXT;
}
static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_1BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_2BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_4BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_8BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
{
d->header.always_zero = 0;
d->header.h = 1; /*Doesn't matter*/
uint8_t br = lv_color_brightness(color);
if(opa < LV_OPA_MAX) {
uint8_t bg = lv_img_buf_get_px_alpha(d, x, y);
br = (uint16_t)((uint16_t)br * opa + (bg * (255 - opa))) >> 8;
}
lv_img_buf_set_px_alpha(d, x, y, br);
}
static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x,
lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.always_zero = 0;
d.header.h = 1; /*Doesn't matter*/;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
lv_color_t bg_color = lv_img_buf_get_px_color(&d, x, y, lv_color_black());
lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&d, x, y);
lv_opa_t res_opa;
lv_color_t res_color;
lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &res_opa);
lv_img_buf_set_px_alpha(&d, x, y, res_opa);
lv_img_buf_set_px_color(&d, x, y, res_color);
}

View File

@ -18,6 +18,7 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include "lv_hal.h"
#include "../draw/lv_img_buf.h"
#include "../misc/lv_color.h"
#include "../misc/lv_area.h"
#include "../misc/lv_ll.h"
@ -312,6 +313,8 @@ lv_disp_t * lv_disp_get_next(lv_disp_t * disp);
*/
lv_disp_draw_buf_t * lv_disp_get_draw_buf(lv_disp_t * disp);
void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf);
/**********************
* MACROS
**********************/

View File

@ -585,6 +585,15 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
#endif
#endif /*LV_ENABLE_GC*/
/*1: Enable API to take snapshot for object*/
#ifndef LV_USE_SNAPSHOT
# ifdef CONFIG_LV_USE_SNAPSHOT
# define LV_USE_SNAPSHOT CONFIG_LV_USE_SNAPSHOT
# else
# define LV_USE_SNAPSHOT 1
# endif
#endif
/*=====================
* COMPILER SETTINGS
*====================*/

View File

@ -27,25 +27,6 @@
* STATIC PROTOTYPES
**********************/
static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void set_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf);
static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x,
lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
/**********************
* STATIC VARIABLES
@ -595,7 +576,7 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
disp.driver->hor_res = dsc->header.w;
disp.driver->ver_res = dsc->header.h;
set_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf);
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
@ -656,7 +637,7 @@ void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord
disp.driver->hor_res = dsc->header.w;
disp.driver->ver_res = dsc->header.h;
set_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
_lv_refr_set_disp_refreshing(&disp);
@ -717,7 +698,7 @@ void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const voi
disp.driver->hor_res = dsc->header.w;
disp.driver->ver_res = dsc->header.h;
set_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
_lv_refr_set_disp_refreshing(&disp);
@ -764,7 +745,7 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t points[], uint32_t
disp.driver->hor_res = dsc->header.w;
disp.driver->ver_res = dsc->header.h;
set_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf);
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
@ -822,7 +803,7 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t points[], uint32
disp.driver->hor_res = dsc->header.w;
disp.driver->ver_res = dsc->header.h;
set_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf);
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
@ -878,7 +859,7 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_
disp.driver->hor_res = dsc->header.w;
disp.driver->ver_res = dsc->header.h;
set_set_px_cb(disp.driver, dsc->header.cf);
lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf);
/*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
@ -930,123 +911,4 @@ static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj
LV_TRACE_OBJ_CREATE("finished");
}
static void set_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf)
{
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_ALPHA:
disp_drv->set_px_cb = set_px_true_color_alpha;
break;
case LV_IMG_CF_ALPHA_1BIT:
disp_drv->set_px_cb = set_px_cb_alpha1;
break;
case LV_IMG_CF_ALPHA_2BIT:
disp_drv->set_px_cb = set_px_cb_alpha2;
break;
case LV_IMG_CF_ALPHA_4BIT:
disp_drv->set_px_cb = set_px_cb_alpha4;
break;
case LV_IMG_CF_ALPHA_8BIT:
disp_drv->set_px_cb = set_px_cb_alpha8;
break;
default:
disp_drv->set_px_cb = NULL;
}
}
static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_1BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_2BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_4BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_ALPHA_8BIT;
set_px_alpha_generic(&d, x, y, color, opa);
}
static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
{
d->header.always_zero = 0;
d->header.h = 1; /*Doesn't matter*/
uint8_t br = lv_color_brightness(color);
if(opa < LV_OPA_MAX) {
uint8_t bg = lv_img_buf_get_px_alpha(d, x, y);
br = (uint16_t)((uint16_t)br * opa + (bg * (255 - opa))) >> 8;
}
lv_img_buf_set_px_alpha(d, x, y, br);
}
static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x,
lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
if(opa <= LV_OPA_MIN) return;
lv_img_dsc_t d;
d.data = buf;
d.header.always_zero = 0;
d.header.h = 1; /*Doesn't matter*/;
d.header.w = buf_w;
d.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
lv_color_t bg_color = lv_img_buf_get_px_color(&d, x, y, lv_color_black());
lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&d, x, y);
lv_opa_t res_opa;
lv_color_t res_color;
lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &res_opa);
lv_img_buf_set_px_alpha(&d, x, y, res_opa);
lv_img_buf_set_px_color(&d, x, y, res_color);
}
#endif