diff --git a/docs/index.md b/docs/index.md index 5e4be2f44..1d8afd841 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,6 +34,7 @@ PDF version: :download:`LVGL.pdf ` overview/index widgets/index layouts/index + others/index CONTRIBUTING CHANGELOG ROADMAP diff --git a/docs/others/index.md b/docs/others/index.md new file mode 100644 index 000000000..2746af7f1 --- /dev/null +++ b/docs/others/index.md @@ -0,0 +1,16 @@ +```eval_rst +.. include:: /header.rst +:github_url: |github_link_base|/others/index.md +``` +# Others + + +```eval_rst + +.. toctree:: + :maxdepth: 1 + + snapshot + +``` + diff --git a/docs/others/snapshot.md b/docs/others/snapshot.md new file mode 100644 index 000000000..149b90c4b --- /dev/null +++ b/docs/others/snapshot.md @@ -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 + +``` diff --git a/docs/overview/object.md b/docs/overview/object.md index 97d355c7c..ffa7c7bf7 100644 --- a/docs/overview/object.md +++ b/docs/overview/object.md @@ -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). diff --git a/examples/lv_examples.h b/examples/lv_examples.h index 1e8c8b842..3ecc5d775 100644 --- a/examples/lv_examples.h +++ b/examples/lv_examples.h @@ -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 diff --git a/examples/others/lv_example_others.h b/examples/others/lv_example_others.h new file mode 100644 index 000000000..bec23c5fb --- /dev/null +++ b/examples/others/lv_example_others.h @@ -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*/ diff --git a/examples/others/snapshot/index.rst b/examples/others/snapshot/index.rst new file mode 100644 index 000000000..e6e54af8c --- /dev/null +++ b/examples/others/snapshot/index.rst @@ -0,0 +1,8 @@ + +Simple snapshot example +""""""""""""""""""" + +.. lv_example:: others/snapshot/lv_example_snapshot_1 + :language: c + + diff --git a/examples/others/snapshot/lv_example_snapshot.h b/examples/others/snapshot/lv_example_snapshot.h new file mode 100644 index 000000000..0cf74c5a5 --- /dev/null +++ b/examples/others/snapshot/lv_example_snapshot.h @@ -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*/ diff --git a/examples/others/snapshot/lv_example_snapshot_1.c b/examples/others/snapshot/lv_example_snapshot_1.c new file mode 100644 index 000000000..c13fc1cac --- /dev/null +++ b/examples/others/snapshot/lv_example_snapshot_1.c @@ -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 diff --git a/examples/others/snapshot/lv_example_snapshot_1.py b/examples/others/snapshot/lv_example_snapshot_1.py new file mode 100644 index 000000000..71bc724c4 --- /dev/null +++ b/examples/others/snapshot/lv_example_snapshot_1.py @@ -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) diff --git a/lv_conf_template.h b/lv_conf_template.h index 43bef7707..4de79ad98 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -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 *====================*/ diff --git a/lvgl.h b/lvgl.h index d413febc0..556cf88be 100644 --- a/lvgl.h +++ b/lvgl.h @@ -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 diff --git a/src/extra/others/lv_others.h b/src/extra/others/lv_others.h new file mode 100644 index 000000000..a95727146 --- /dev/null +++ b/src/extra/others/lv_others.h @@ -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*/ diff --git a/src/extra/others/snapshot/lv_snapshot.c b/src/extra/others/snapshot/lv_snapshot.c new file mode 100644 index 000000000..a16a51c49 --- /dev/null +++ b/src/extra/others/snapshot/lv_snapshot.c @@ -0,0 +1,213 @@ +/** + * @file lv_snapshot.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_snapshot.h" +#if LV_USE_SNAPSHOT + +#include +#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*/ diff --git a/src/extra/others/snapshot/lv_snapshot.h b/src/extra/others/snapshot/lv_snapshot.h new file mode 100644 index 000000000..b84973317 --- /dev/null +++ b/src/extra/others/snapshot/lv_snapshot.h @@ -0,0 +1,84 @@ +/** + * @file lv_snapshot.h + * + */ + +#ifndef LV_SNAPSHOT_H +#define LV_SNAPSHOT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include + +#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 diff --git a/src/hal/lv_hal_disp.c b/src/hal/lv_hal_disp.c index d64e0d30c..d0d489fa7 100644 --- a/src/hal/lv_hal_disp.c +++ b/src/hal/lv_hal_disp.c @@ -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); +} diff --git a/src/hal/lv_hal_disp.h b/src/hal/lv_hal_disp.h index 9a6315320..22344df3c 100644 --- a/src/hal/lv_hal_disp.h +++ b/src/hal/lv_hal_disp.h @@ -18,6 +18,7 @@ extern "C" { #include #include #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 **********************/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index c24fad8d8..74224d315 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -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 *====================*/ diff --git a/src/widgets/lv_canvas.c b/src/widgets/lv_canvas.c index 5101276fa..c0e7624cb 100644 --- a/src/widgets/lv_canvas.c +++ b/src/widgets/lv_canvas.c @@ -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