How to rotate a text label

Rotating a text label

When a label is constructed, it’s text follows a standard direction. It is possible to rotate the label, but how?

MCU and board

STM32F205RET (128K SRAM, 512K Flash) in a custom board, with gcc-arm(1) , GNU make(1) , and STM32 HAL .

LVGL version


What do you want to achieve?

I want to display a text label in the usual way, but add one or two source code lines to rotate it ninety degrees.

What have you tried so far?


I tried using a canvas transform, but because my display is monochrome (OLED SSD1306) and buffer LV_IMG_CF_INDEXED_1BIT the canvas draw functions such as lv_canvas_draw_text(3) appear to fail.


I tried adding a style to my text label, but it did not work. Maybe styles in 1-bit displays are defective just like the canvas draw functions?

Code to reproduce

I’m using the following source code block as a starting point. Please tell me how to modify this to rotate the text by ninety degrees?

// Create a label to rotate
lv_obj_t *pLabel = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(pLabel, LV_LABEL_LONG_EXPAND);
lv_obj_set_width(pLabel, lv_obj_get_height(lv_scr_act()));
lv_label_set_text(pLabel, "Bodacious");

// Add a rotated style to the label
static lv_style_t style_label;
lv_style_set_transform_angle(&style_label, LV_STATE_DEFAULT, 900);
lv_obj_add_style(pLabel, LV_LABEL_PART_MAIN, &style_label);

Currently, the only two ways to rotate text are:

  • Use a premade image for the text, and rotate the image using lv_img_set_angle (simpler).
  • Use a canvas and draw the text on it (example, more complex).

It is not possible to rotate most widgets directly, including the label.

Thanks for suggesting to render an image from a font (I guess in some external image editor) and rotate the image. This will not work whenever the text is dynamically created (for example a hours and minutes clock.)

I wrote that I’m using LVGL on a monochrome OLED with LV_IMG_CF_INDEXED_1BIT. Or do you still think I can draw text in a canvas?

I thought the canvas draw methods were defective with 1-bit palettes?

Or can I draw to 1-bit canvases in version 8?

By the way, I added trying with styles to my howto request above. This method seems to be equally broken as with the canvas.

Impossible lv_img_set_angle

Just when I thought it couldn’t get worse, it seems that even rotating indexed images is not possible in release/v7.

lv_obj_t *pImage = NULL;
pImage = lv_img_create(lv_scr_act(), NULL);
lv_obj_align(pImage, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_img_set_src(pImage, &mytext);
lv_img_set_angle(pImage, 900);

transform_angle only works on image-like objects as per its description in the style documentation, so unfortunately it won’t work on a label.

That is correct. The image will need to be true color, not indexed.

Sorry; I missed that. Drawing text on a canvas does not work if the canvas is indexed; the canvas needs to be true color. You should be able to use a true color canvas on a 1-bit display, but this only works if you have the RAM to spare.

is there a function to trasform a label into an image ?
in this way you could have the rotations

This link has become broken. :disappointed_relieved:

Here is a new link for v8.3.

Would somebody have good ways to solve this? I have tried to rotate a label on canvas with the the func(lv_obj_set_style_transform_angle()), the label disappeard. The same with lv_obj_set_style_transform_zoom(). this two func work good in simulator (visual stdio), but works abnormal in hardware(stm32H7) which the object sometimes is disappeard or not the whole.

lv_obj_t* test_btn;
   lv_obj_t * test_label;
void lv_timer_test(lv_timer_t* timer)
    static int16_t a = 1800;
    if (a > 3600)
        a = 1800;
    if (a <= 0)a = 10;
    int16_t ratio = (float)(a) / 3600 * 256;
    if (ratio < 1) ratio = 1;
    //lv_obj_set_style_transform_angle(test_btn, a, 0);        /*15 deg*/
    //lv_obj_set_style_transform_zoom(test_btn, ratio , 0);   /*1.25x*/

 * Opacity and Transformations

void lv_example_style_15(void)

    /*Normal button*/
    test_btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(test_btn, 100, 40);
    lv_obj_align(test_btn, LV_ALIGN_CENTER, 0, -70);

    test_label = lv_label_create(test_btn);
    lv_label_set_text(test_label, "Normal");

    /*Set opacity
     *The button and the test_label is rendered to a layer first and that layer is blended*/
    test_btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(test_btn, 100, 40);
    //lv_obj_set_style_opa(test_btn, LV_OPA_50, 0);
    lv_obj_align(test_btn, LV_ALIGN_CENTER, 0, 0);

    test_label = lv_label_create(test_btn);
    lv_label_set_text(test_label, "Opa:50%");

    /*Set transformations
     *The button and the test_label is rendered to a layer first and that layer is transformed*/
	 #define CANVAS_WIDTH 200
#define CANVAS_HEIGHT 100
    static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)] __attribute__((section(".ARM.__at_0x30000000")));

    lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
    lv_canvas_set_buffer(canvas, cbuf, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
    lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_GREY, 3), LV_OPA_COVER);

    //test_btn = lv_btn_create(lv_layer_top());
    test_btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(test_btn, 100, 40);
    //lv_obj_set_style_transform_angle(test_btn, 150, 0);        /*15 deg*/
    //lv_obj_set_style_transform_zoom(test_btn, 256 + 64, 0);   /*1.25x*/
    //lv_obj_set_style_transform_pivot_x(test_btn, 0, 0);
    //lv_obj_set_style_transform_pivot_y(test_btn, 0, 0);
    //lv_obj_set_style_opa(test_btn, LV_OPA_50, 0);
    lv_obj_align_to(test_btn,canvas, LV_ALIGN_CENTER, 0, 0);

    test_label = lv_label_create(test_btn);
    lv_label_set_text(test_label, "Transf.");

    lv_timer_t* timer_text = lv_timer_create(lv_timer_test, 500, NULL);