Draw Descriptors
Overview
Each Draw Task type has its own draw descriptor type. For
example, lv_draw_label_dsc_t is used for label drawing,
lv_draw_image_dsc_t is used for image drawing.
When an lv_draw_... function is called, it creates a Draw Task, copies the draw
descriptor into a malloced memory block, and frees it automatically when
needed. Therefore, local draw descriptor variables can be safely used.
Relation to Styles
In most cases, style properties map 1-to-1 to draw descriptor fields. For example:
label_dsc.colorcorresponds to thetext_colorstyle property.shadow_dsc.width,line_dsc.opa, andarc_dsc.widthmap toshadow_width,line_opa, andarc_widthin styles.
See Style Properties to see the list of style properties and what they mean.
Base Draw Descriptor
In each draw descriptor there is a generic "base descriptor" with
lv_draw_dsc_base_t type and with base in its name. For example
label_dsc.base. This struct stores useful information about which Widget
and part created the draw descriptor. See all the fields in
lv_draw_dsc_base_t.
In an LV_EVENT_DRAW_TASK_ADDED event, the elements of the base draw
descriptor are very useful to identify the Draw Task. For example:
/* In LV_EVENT_DRAW_TASK_ADDED */
lv_draw_task_t * t = lv_event_get_draw_task(e);
lv_draw_base_dsc_t * draw_dsc = lv_draw_task_get_draw_dsc(t);
draw_dsc.obj; /* The Widget for which the draw descriptor was created */
draw_dsc.part; /* The Widget part for which the draw descriptor was created
E.g. LV_PART_INDICATOR */
draw_dsc.id1; /* A Widget type specific ID (e.g. table row index).
See the docs of the given Widget. */
draw_dsc.id2;
draw_dsc.layer; /* The target layer.
Required when a new Draw Tasks are also created */Simple Initialization
Before using a draw descriptor it needs to be initialized with
the related function. For example, lv_draw_label_dsc_init(&my_label_draw_dsc).
After initialization, each field of the draw descriptor can be set. The default values are quite sane and reasonable, so usually only a few fields need modification. For example:
/* In LV_EVENT_DRAW_MAIN */
lv_draw_label_dsc_t my_label_draw_dsc;
lv_draw_label_dsc_init(&my_label_draw_dsc);
my_label_draw_dsc.font = &my_font;
my_label_draw_dsc.color = lv_color_hex(0xff0000);
my_label_draw_dsc.text = "Hello";
lv_area_t a = {10, 10, 200, 50}; /* Draw label here */
lv_draw_label(lv_event_get_layer(e), &my_label_draw_dsc, &a);Initialization for Widgets
When rendering a part of a Widget, helper functions can initialize draw descriptors based on the styles, and a specific Widget part in the current state.
For example:
/* In LV_EVENT_DRAW_MAIN */
lv_draw_rect_dsc_t cur_dsc;
lv_draw_rect_dsc_init(&cur_dsc);
lv_obj_init_draw_rect_dsc(obj, LV_PART_CURSOR, &cur_dsc);
cur_dsc.fill_color = lv_color_hex(0xff0000); /* Modify if needed */
lv_draw_rect(layer, &cur_dsc, &area);The lv_obj_init_draw_... functions automatically initialize the fields of
the base descriptor.
Modify the draw descriptors
In LV_EVENT_DRAW_TASK_ADDED, the draw descriptor of the draw_task can be
accessed (using lv_draw_task_get_label_dsc and similar functions)
and modified (to change color, text, font, etc.). This means that in
LV_EVENT_DRAW_TASK_ADDED, the draw_tasks and draw descriptors
are already initialized and it's enough to change only a few specific values.
For example:
/* In LV_EVENT_DRAW_TASK_ADDED */
lv_draw_task_t * t = lv_event_get_draw_task(e);
lv_draw_label_dsc_t * draw_dsc = lv_draw_task_get_label_dsc(t);
/* Check a few things in `draw_dsc->base` */
/* Make the color lighter for longer texts */
draw_dsc->color = lv_color_lighten(draw_dsc->color,
LV_MIN(lv_strlen(draw_dsc->text) * 5, 255));
/* Create new Draw Tasks if needed by calling
* `lv_draw_...(draw_dsc->base.layer, ...)` functions */Rectangle Draw Descriptor
lv_draw_rect_dsc_t is a helper descriptor that combines:
- Fill
- Border
- Outline (a border with its own styles)
- Shadow
- Background image (an image with its own styles)
into a single call.
lv_obj_init_draw_rect_dsc(obj, part, &dsc); initializes a draw descriptor
from a Widget, and lv_draw_rect(layer, &dsc, area) draws the rectangle in a
specified area.
Fill Draw Descriptor
The main fields of lv_draw_fill_dsc_t are straightforward. It has a
radius, opacity, and color to draw a rectangle. If opacity is 0, no draw task will
be created.
lv_draw_fill_dsc_init(&dsc)initializes a fill Draw Task.lv_draw_sw_fill(layer, &dsc, area)creates a Draw Task to fill an area.lv_draw_task_get_fill_dsc(draw_task)retrieves the fill descriptor from a Draw Task.
Gradients
The grad field of the fill descriptor (or lv_grad_dsc_t in general)
supports:
- Horizontal
- Vertical
- Skew
- Radial
- Conical
gradient types.
The following show some example gradients.
For each gradient type, multiple color and opacity values can be assigned. These are
called "stops". The maximum number of stops is limited to
LV_GRADIENT_MAX_STOPS.
A gradient is basically a transition of colors and opacities between stops.
Besides just setting the color and opacity of each stop, it is also possible to set where they start relative to the whole gradient area.
For example with 3 stops it can be set like this:
- 10% red: 0--10% fully red
- 60% green: 10--60% transition from red to green, 60% is fully green
- 65% blue: fast transition from green to blue between 60%--65%. After 65% fully blue.
The position of the stops are called fractions or offsets and are 8 bit values where 0 is 0% and 255 is 100% of the whole gradient area.
lv_grad_init_stops(grad_dsc, colors, opas, fracs, cnt) initializes
a gradient descriptor with stops containing the color, opacity and fraction of each
stop.
static const lv_color_t colors[2] = {
LV_COLOR_MAKE(0xe8, 0xe8, 0xe8),
LV_COLOR_MAKE(0x79, 0x79, 0x79),
};
static const lv_opa_t opas[2] = {
170,
255,
};
static const uint8_t fracs[2] = {
170,
255,
};
lv_grad_init_stops(&grad, colors, opas, fracs, sizeof(colors) / sizeof(lv_color_t));If the opacity array is NULL 255 will be used for each stop. If the fractions
array is NULL the colors will be distributed evenly. For example with 3 colors:
0%, 50%, 100%
Padding
Linear, radial, and conic gradients are defined between two points or angles. You can define how to pad the areas outside of the start and end points or angles:
LV_GRAD_EXTEND_PAD: Repeat the same colorLV_GRAD_EXTEND_REPEAT: Repeat the patternLV_GRAD_EXTEND_REFLECT: Repeat the pattern normally and mirrored alternately
Horizontal and Vertical Gradients
The simplest and usually fastest gradient types are horizontal and vertical gradients.
After initializing the stops with lv_grad_init_stops call either
lv_grad_horizontal_init(&grad_dsc) or
lv_grad_vertical_init(&grad_dsc) to get a horizontal or vertical gradient
descriptor.
Linear Gradients
The linear (or skew) gradient are similar to horizontal or vertical gradient but the angle of the gradient can be controlled.
The linear gradient will be rendered along a line defined by 2 points.
After initializing the stops with lv_grad_init_stops call
lv_grad_linear_init(&grad_dsc, from_x, from_y, to_x, to_y, LV_GRAD_EXTEND_...)
with your point values and extend pattern strategy to get a linear gradient descriptor.
Radial Gradients
The radial gradient is described by two circles: an outer circle and an inner circle (also called the focal point). The gradient will be calculated between the focal point's circle and the edge of the outer circle.
If the center of the focal point and the center of the main circle are the same, the gradient will spread evenly in all directions. If the center points are not the same, the gradient will have an egg shape.
The focal point's circle should be inside the main circle.
After initializing the stops with lv_grad_init_stops, the outer
circle can be set by:
lv_grad_radial_init(&grad_dsc, center_x, center_y, edge_x, edge_y, LV_GRAD_EXTEND_...)
For both the center and edge coordinates, px or lv_pct() values can be used.
The inner circle (focal point) can be set with:
lv_grad_radial_set_focal(&grad_dsc, center_x, center_y, radius)
Conic Gradients
The conic gradient is defined between two angles within a circle, and colors are mapped to each angle.
After initializing the stops with lv_grad_init_stops, the conic gradient
can be set up with:
lv_grad_conical_init(&grad, center_x, center_y, angle_start, angle_end, LV_GRAD_EXTEND_...)
For both the center and edge coordinates, px or lv_pct() values can be used.
The zero angle is on the right-hand side, and 90 degrees is at the bottom.
Border Draw Descriptor
The lv_draw_border_dsc_t border descriptor has radius, opacity,
width, color, and side fields. If the opacity or width is 0, no Draw Task will
be created.
side can contain ORed values of lv_border_side_t, such as
LV_BORDER_SIDE_BOTTOM. LV_BORDER_SIDE_ALL
applies to all sides, while LV_BORDER_SIDE_INTERNAL is used by
higher layers (e.g. a table Widget) to calculate border sides. However, the drawing
routine receives only simpler values.
The following functions are used for border drawing:
lv_draw_border_dsc_init(&dsc)initializes a border Draw Task.lv_draw_sw_border(layer, &dsc, area)creates a Draw Task to draw a border inward from its area.lv_draw_task_get_border_dsc(draw_task)retrieves the border descriptor from a Draw Task.
Outlines
The outline is similar to the border but is drawn outside the object's draw area.
In practice, there is no dedicated outline descriptor like
lv_draw_outline_dsc_t, because from the rendering perspective, the
outline is simply another border rendered outside the object's bounds.
The outline is used only in lv_draw_rect_dsc_t for convenience. The two
differences compared to borders in lv_draw_rect_dsc_t are:
- There is an
outline_padproperty to specify the gap between the target area and the inner side of the outline. It can be negative. For example, ifoutline_pad = -width, the outline will resemble a border. - There is no
border_sideproperty for the outline. It's always rendered as a full rectangle.
Box Shadow Draw Descriptor
The lv_draw_box_shadow_dsc_t box shadow descriptor describes a
rounded rectangle-shaped shadow. It cannot generate shadows for arbitrary
shapes, text, or images. It includes the following fields:
| Field | Description |
|---|---|
radius | Radius, LV_RADIUS_CIRCLE. |
color | Shadow color. |
width | Shadow width (blur radius). |
spread | Expands the rectangle in all directions; can be negative. |
ofs_x | Horizontal offset. |
ofs_y | Vertical offset. |
opa | Opacity (0--255 range). Values like LV_OPA_TRANSP, LV_OPA_10, etc., can also be used. |
bg_cover | Set to 1 if the background will cover the shadow (a hint for the renderer to skip masking). |
Note: Rendering large shadows may be slow or memory-intensive.
The following functions are used for box shadow drawing:
lv_draw_box_shadow_dsc_init(&dsc)initializes a box shadow Draw Task.lv_draw_sw_box_shadow(layer, &dsc, area)creates a Draw Task for a rectangle's shadow. The shadow's size and position depend on the width, spread, and offset.lv_draw_task_get_box_shadow_dsc(draw_task)retrieves the box shadow descriptor from a Draw Task.
Image Draw Descriptor
The lv_draw_image_dsc_t image descriptor defines the parameters for
image drawing. It is a complex descriptor with the following options:
| Field | Description |
|---|---|
src | The image source, either a pointer to lv_image_dsc_t or a file path. |
opa | Opacity in the 0--255 range. Options like LV_OPA_TRANSP, LV_OPA_10, etc., can also be used. |
clip_radius | Clips the corners of the image with this radius. Use LV_RADIUS_CIRCLE for the maximum radius. |
rotation | Image rotation in 0.1-degree units (e.g., 234 means 23.4°). |
scale_x | Horizontal scaling (zoom) of the image. 256 (LV_SCALE_NONE) means no zoom, 512 doubles the size, and 128 halves it. |
scale_y | Same as scale_x but for vertical scaling. |
skew_x | Horizontal skew (parallelogram-like transformation) in 0.1-degree units (e.g., 456 means 45.6°). |
skew_y | Vertical skew, similar to skew_x. |
pivot | The pivot point for transformations (scaling and rotation). (0,0) is the top-left corner of the image and can be set outside the image. |
bitmap_mask_src | Pointer to an A8 or L8 image descriptor used to mask the image. The mask is always center-aligned. |
recolor | Mixes this color with the image. For LV_COLOR_FORMAT_A8, this will be the visible pixels' color. |
recolor_opa | Intensity of recoloring (0 means no recoloring, 255 means full cover). |
blend_mode | Defines how to blend image pixels with the background. See lv_blend_mode_t for more details. |
antialias | Set to 1 to enable anti-aliasing for transformations. |
tile | Tiles the image (repeats it both horizontally and vertically) if the image is smaller than the image_area field in lv_draw_image_dsc_t. |
image_area | Indicates the original, non-clipped area where the image is drawn. This is essential for: 1. Layer rendering, where only part of a layer may be rendered and clip_radius needs the original image dimensions. 2. Tiling, where the draw area is larger than the image. |
sup | Internal field to store information about the palette or color of A8 images. |
Functions for image drawing:
lv_draw_image_dsc_init(&dsc)initializes an image draw descriptor.lv_draw_image(layer, &dsc, area)creates a task to draw an image in a given area.lv_draw_task_get_image_dsc(draw_task)retrieves the image descriptor from a task.
Layers - Special Images
Layers are treated as images, so an lv_draw_image_dsc_t can describe
how layers are blended into their parent layers. All image features apply to
layers as well.
lv_draw_layer(layer, &dsc, area) initializes the blending of a layer back to
its parent layer. Additionally, image-drawing-related functions can be used for
layers.
For more details, see Layers.
Label Draw Descriptor
The lv_draw_label_dsc_t label descriptor provides extensive options
for controlling text rendering:
| Field | Description |
|---|---|
text | The text to render. |
font | Font to use, with support for fallback fonts. |
color | Text color. |
opa | Text opacity. |
line_space | Additional space between lines. |
letter_space | Additional space between characters. |
ofs_x | Horizontal text offset. |
ofs_y | Vertical text offset. |
sel_start | Index of the first character for selection (character index, not byte index, since some characters can be multi-byte characters). LV_DRAW_LABEL_NO_TXT_SEL means no selection. |
sel_end | Index of the last character for selection. |
sel_color | Color of selected characters. |
sel_bg_color | Background color for selected characters. |
align | Text alignment. See lv_text_align_t. |
bidi_dir | Base direction for right-to-left text rendering (e.g., Arabic). See lv_base_dir_t. |
decor | Text decoration, e.g., underline. See lv_text_decor_t. |
flag | Flags for text rendering. See lv_text_flag_t. |
text_length | Number of characters to render (0 means render until \\0). |
text_local | Set to 1 to allocate a buffer and copy the text. |
text_static | Indicates text is constant and its pointer can be cached. |
hint | Pointer to externally stored data to speed up rendering. See lv_draw_label_hint_t. |
Functions for text drawing:
lv_draw_label_dsc_init(&dsc)initializes a label draw descriptor.lv_draw_label(layer, &dsc, area)creates a task to render text in an area.lv_draw_character(layer, &dsc, point, unicode_letter)creates a task to draw a character at a specific point.lv_draw_task_get_label_dsc(draw_task)retrieves the label descriptor from a task.
For character-specific drawing in draw units, use
lv_draw_label_iterate_characters(draw_unit, draw_dsc, area, callback).
This iterates through all characters, calculates their positions, and calls the
callback for rendering each character. For callback details, see
lv_draw_glyph_cb_t.
Arc Draw Descriptor
The lv_draw_arc_dsc_t arc descriptor defines arc rendering with
these fields:
| Field | Description |
|---|---|
color | Arc color. |
img_src | Image source for the arc, or NULL if unused. |
width | Arc thickness. |
start_angle | Starting angle in degrees (e.g., 0° is 3 o'clock, 90° is 6 o'clock). |
end_angle | Ending angle. |
center | Arc center point. |
radius | Arc radius. |
opa | Arc opacity (0--255). |
rounded | Rounds the arc ends. |
Functions for arc drawing:
lv_draw_arc_dsc_init(&dsc)initializes an arc descriptor.lv_draw_arc(layer, &dsc)creates a task to render an arc.lv_draw_task_get_arc_dsc(draw_task)retrieves arc descriptor from task.
Line Draw Descriptor
The lv_draw_line_dsc_t line descriptor defines line rendering with
these fields:
| Field | Description |
|---|---|
p1 | First point of line (supports floating-point coordinates). Ignored if points are set. |
p2 | Second point of line (supports floating-point coordinates). Ignored if points are set. |
points | Array of points to draw. |
point_cnt | Number of points in points |
color | Line color. |
width | Line thickness. |
opa | Line opacity (0--255). |
dash_width | Length of dashes (0 means no dashes --- a continuous line). |
dash_gap | Length of gaps between dashes (0 means no gaps --- a continuous line). |
round_start | Rounds the line start. |
round_end | Rounds the line end. |
raw_end | Set to 1 to skip end calculations if they are unnecessary. |
If a large amount of points needs to be rendered it's recommended to use points
instead of p1 and p2 as it avoids creating many draw tasks.
Functions for line drawing:
lv_draw_line_dsc_init(&dsc)initializes a line descriptor.lv_draw_line(layer, &dsc)creates a task to draw a line.lv_draw_task_get_line_dsc(draw_task)retrieves line descriptor.lv_draw_line_iterate(draw_task, dsc, callback)is a helper function to call a callback which draws a line between two points. This way it doesn't matter ifp1, p2orpointswere used as it calls thecallbackas needed.
Triangle Draw Descriptor
Triangles are defined by lv_draw_triangle_dsc_t, which includes:
| Field | Description |
|---|---|
p[3] | 3 points for the triangle's vertices. |
color | Triangle color. |
opa | Triangle opacity. |
grad | Gradient options. If grad.dir is not LV_GRAD_DIR_NONE, the color field is ignored. The opa field adjusts overall opacity. |
Functions for triangle drawing:
lv_draw_triangle_dsc_init(&dsc)initializes a triangle descriptor.lv_draw_triangle(layer, &dsc)creates a task to draw a triangle.lv_draw_task_get_triangle_dsc(draw_task)retrieves triangle descriptor.
Blur Draw Descriptor
Blur is defined by lv_draw_blur_dsc_t, which includes:
| Field | Description |
|---|---|
blur_radius | The radius of the blur. |
corner_radius | The radius of the corners. |
quality | Tells whether to prefer speed or quality. |
Functions for blur drawing:
lv_draw_blur_dsc_init(&dsc)initializes a blur descriptor.lv_draw_blur(layer, &dsc, area)creates a task to blur an area.lv_draw_task_get_blur_dsc(draw_task)retrieves blur descriptor.
Drop Shadow Draw Descriptor
Unlike Box shadow, the Drop shadow can be applied for any widgets and parts. For example a Label, the Arc's Indicator, an ARGB image, Lines of a chart, etc.
The Drop shadow doesn't have its own draw descriptor but it's part of the base descriptor. This way before rendering anything LVGL can create a new layer with A8 color format, render the shape there, blur the layer, and finally blend the blurred layer with an offset.
Creating a layer requires width x height bytes of memory. This memory is used only
temporarily, so in most of the cases if multiple widgets have drop shadow, only one
layer is active and using memory at a time.
The properties are stored in draw_dsc.base.drop_shadow_*. It includes the
following fields:
| Field | Description |
|---|---|
drop_shadow_opa | Opacity (0--255 range). Values like LV_OPA_TRANSP, LV_OPA_10, etc., can also be used. If 0, the drop shadow won't be rendered |
drop_shadow_color | Drop shadow color. |
drop_shadow_radius | The blur radius of the drop shadow. |
drop_shadow_ofs_x | Horizontal offset. |
drop_shadow_ofs_y | Vertical offset. |
Vector Draw Descriptor
Vector rendering works slightly differently than the other draw descriptors, because the data required to describe the operation doesn't have a fixed length.
The key element of vector rendering is a "path" (lv_vector_path_t) which describes
the shape of the drawing using lines, arcs, and curves. The paths can be stroked
(draw a line on the path) and filled (fill the path with a color, gradient, or image).
A lv_draw_vector_dsc_t vector descriptor can hold multiple paths.
The flow of creating a new vector descriptor is the following.
- Create a vector draw descriptor:
lv_draw_vector_dsc_t * dsc = lv_draw_vector_dsc_create(layer);- Create a path
lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);-
Set the shape of the path. The following show a few simple functions for that:
lv_vector_path_clear: Clear all lines, arcs, and curves from a pathlv_vector_path_move_to: Move to a point without drawing any lineslv_vector_path_line_to: Add a line to the path from last point to the pointlv_vector_path_quad_to: Add a quadratic bezier line to the path from last point to the pointlv_vector_path_cubic_to: Add a cubic bezier line to the path from last point to the pointlv_vector_path_arc_to: Add ellipse arc to the path from last point to the pointlv_vector_path_close: Close the sub path by connecting the first and last point
-
Set the stroke and fill settings on the draw descriptor for the given path. Use functions like:
lv_draw_vector_dsc_set_stroke_color: Set stroke color for a descriptor.lv_draw_vector_dsc_set_stroke_opa: Set stroke opacity for a descriptorlv_draw_vector_dsc_set_stroke_width: Set stroke width for a descriptor.lv_draw_vector_dsc_set_fill_color: Set fill color for a descriptor.lv_draw_vector_dsc_set_fill_opa: Set fill opacity for a descriptor.
-
Add the path to the descriptor. It will apply the stroke and fill settings for the path:
lv_draw_vector_dsc_add_path(dsc, path);- If more paths are needed, clear the path or create a new one, and add it to the draw descriptor too.
- Start drawing and clean up:
lv_draw_vector(dsc);
lv_vector_path_delete(path);
lv_draw_vector_dsc_delete(dsc);To see all the path, stroke, and fill options, check out lv_draw_vector.h .
Masking Operation
There are several options to mask parts of a layer, Widget, or drawing:
-
Radius of Rectangles: Set the
radiusstyle property or theradiusin the draw descriptors. This creates rounded rectangles, borders, outlines, etc.. However, the content of subsequent renderings will not be masked out in the corners. -
Clip Radius of Images: Similar to rectangles, images can also be rendered with a
radius. Since layer drawing and image drawing are handled the same way, this works for layers as well.You can draw various content on a layer and then render the layer with a
clip_radius, masking out all the content on the corners. -
Rectangle Mask Draw Task: A special Draw Task can mask out a rectangle from a layer by setting the alpha channel of certain pixels to 0. To achieve this:
- Create an
lv_draw_mask_rect_dsc_tdescriptor. - Set
area,radius, andkeep_outsideparameters. Ifkeep_outsideis set to 1, areas outside ofarearemain unchanged. Otherwise, they are cleared. - Call
lv_draw_mask_rect(layer, &dsc).
Note: The layer must have a color format with an alpha channel, typically
LV_COLOR_FORMAT_ARGB8888.In most cases, the "Clip Radius of Images" method is better because it blends the layer with a radius mask on the fly, avoiding a dedicated masking step. However, the "Rectangle Mask Draw Task" is useful when multiple areas need clearing or when the area to be masked differs from the layer area.
- Create an
-
Clip Corner Style Property: Enabling
..._style_clip_cornerin a local or global style allows LVGL to create a layer for the top and bottom corner areas of a Widget. It renders the children there and blends it by settingclip_radiusto the layer. -
Bitmap Masking for Images: Using
..._style_bitmap_maskorbitmap_maskinlv_draw_image_dsc_tallows setting an A8 or L8 image as a mask for an image/layer during blending.- Limitation: The mask always aligns to the center, and only one bitmap mask can be used for an image/layer.
- When
..._style_bitmap_maskis used, LVGL automatically creates a layer, renders the Widgets there, and applies the bitmap mask during blending. - Alternatively, the
bitmap_maskproperty in the draw descriptor can be used directly for image drawing.
By using the Canvas Widget with an
LV_COLOR_FORMAT_L8buffer, bitmap masks can be rendered dynamically.
API
How is this guide?
Last updated on
Draw Layers
Not to be confused with a Display's main 4 layers, a :dfn:Draw Layer is a buffer created during rendering, necessitated by certain style properties, so different sets of pixels are correctly combined.
Draw Units
A "Draw Unit" (lv_draw_unit_t) is any peripheral or system that can render something on the screen. This can be a CPU core, a GPU, a custom rendering library for specific draw tasks, or any entity ...