How to define and show bitmap icons in LVGL

Hello,
How do I define and show bitmap icons in LVGL?

For example, I want to define a binary icon like this:

const uint8_t my_image_bitmap[] = {
0b11111111,
0b10000001,
0b10000001
0b10000001,
0b10000001,
0b11111111}

How do I show that on the screen with LVGL?
Thanks!

I tried to do this several ways but none worked.

This, for example:

const uint8_t my_1bit_img_data[] = {
    0b11111111,
    0b10000001,
    0b10000001,
    0b10000001,
    0b10000001,
    0b10000001,
    0b10000001,
    0b11111111
};

const lv_image_dsc_t my_1bit_img = {
    .header = {
        .magic = LV_IMAGE_HEADER_MAGIC,
        .cf = LV_COLOR_FORMAT_I1,  // 1-bit indexed
        .w = 8,
        .h = 8,
    },
    .data_size = sizeof(my_1bit_img_data),
    .data = my_1bit_img_data,
};

void show_hollow_square()
{
    lv_obj_t * img = lv_image_create(lv_screen_active());
    lv_image_set_src(img, &my_1bit_img);
    lv_obj_center(img);

    lv_obj_set_style_image_recolor(img, lv_color_hex(0xFF0000), LV_PART_MAIN);
    lv_obj_set_style_image_recolor_opa(img, LV_OPA_COVER, LV_PART_MAIN);
}

Showed a square but with random pixels, not the image defined in my_1bit_img_data.

And so, without any more options, I did it this way:

#define O 0xFF
#define X 0x00

const uint8_t my_image_map[] = {

    // Color format (in binary, MSB..LSB): BBBBBGGGGGGRRRRR. 0x00,0xF1=Full red. 0x07,0xE0=Full green. 0xF8,0x00=Full blue.
    
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 

    // Alpha: 0xFF=100% visible. 0x00=Invisible.

    O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,
    O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,X,X,X,X,X,X,X,X,X,X,X,X,X,X,O,O,
    O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,
    O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,
    
};

const lv_image_dsc_t my_image = {
    .header = {
        .magic = LV_IMAGE_HEADER_MAGIC,
        .cf = LV_COLOR_FORMAT_NATIVE_WITH_ALPHA,
        .w = 18,
        .h = 18,
    },
    .data_size = sizeof(my_image_map),
    .data = my_image_map
};

void show_hollow_square()
{
    lv_obj_t * img = lv_image_create(lv_screen_active());
    lv_image_set_src(img, &my_image);
    lv_obj_center(img);
}

And it worked.
But its a big waste of memory compared with a binary map.

// Define field images
const LV_ATTRIBUTE_MEM_ALIGN uint8_t ui_img2_data[] = {
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0
  /*Pixel format: Red: 5 bit, Green: 6 bit, Blue: 5 bit BUT the 2 bytes are swapped*/
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,.......
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
  };
  
const lv_img_dsc_t ui_img2 = 
{
	.header.always_zero = 0,
	.header.w = 76,
	.header.h = 52,
	.data_size = sizeof(ui_img2_data),
	.header.cf = LV_IMG_CF_TRUE_COLOR,
	.data = ui_img2_data
};

// Use converter: https://lvgl.io/tools/imageconverter

// Inside ui.h
LV_IMG_DECLARE(ui_img2);

// Create a label and set an image to it
static lv_obj_t *labelImg = NULL;
labelImg = lv_label_create(NULL);
...
lv_img_set_src(labelImg, &ui_img2);

For I1 color format, it seems you are missing a header in the data…

Notice the first line of img_small_i1_map.

static const
LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_SMALL_I1
uint8_t img_small_i1_map[] = {

    0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xff,

    0xff,
    0x81,
    0x81,
    0x81,
    0x81,
    0x81,
    0x81,
    0xff,

};

const lv_image_dsc_t img_small_i1 = {
  .header.magic = LV_IMAGE_HEADER_MAGIC,
  .header.cf = LV_COLOR_FORMAT_I1,
  .header.flags = 0,
  .header.w = 8,
  .header.h = 8,
  .header.stride = 1,
  .data_size = sizeof(img_small_i1_map),
  .data = img_small_i1_map,
};

This would be you “bitmap” in I1 format, well since the source was png with the “inside” transparent, the “recolor” is only changing the border color…

If black border, and white inside:

static const
LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_SMALL_WHITE_I1
uint8_t img_small_white_i1_map[] = {

    0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,

    0x00,
    0x7e,
    0x7e,
    0x7e,
    0x7e,
    0x7e,
    0x7e,
    0x00,

}:

Simplest way, is to design the image in paint (you favorite software) and generate the image with the image converter for format I1

1 Like

Thanks arturv2000! That header is what was missing! Now it worked!

I did it like this to show 16x16 pixels binary images:

#define SPLIT_U16(val)  ((uint8_t)(((val) >> 8) & 0xFF)) , ((uint8_t)((val) & 0xFF))

const uint8_t image_check_map[] = {
    0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xff,

    SPLIT_U16(0b0000000000000000),
    SPLIT_U16(0b0000000000000000),
    SPLIT_U16(0b0000000000000100),
    SPLIT_U16(0b0000000000001110),
    SPLIT_U16(0b0000000000011111),
    SPLIT_U16(0b0000000000111110),
    SPLIT_U16(0b0000000001111100),
    SPLIT_U16(0b0010000011111000),
    SPLIT_U16(0b0111000111110000),
    SPLIT_U16(0b1111101111100000),
    SPLIT_U16(0b0111111111000000),
    SPLIT_U16(0b0011111110000000),
    SPLIT_U16(0b0001111100000000),
    SPLIT_U16(0b0000111000000000),
    SPLIT_U16(0b0000010000000000),
    SPLIT_U16(0b0000000000000000)
};

const lv_image_dsc_t image_check = {
    .header = {
        .magic = LV_IMAGE_HEADER_MAGIC,
        .cf = LV_COLOR_FORMAT_I1,
        .w = 16,
        .h = 16,
    },
    .data_size = sizeof(image_check_map),
    .data = image_check_map,
};

void show_binary_image(lv_obj_t *obj, const lv_img_dsc_t *src, lv_color_t color, lv_align_t align, uint32_t PX, uint32_t PY)
{
    lv_obj_t * img = lv_image_create(obj);
    lv_image_set_src(img, src);
    lv_obj_align(img, align, PX, PY);

    lv_obj_set_style_image_recolor(img, color, LV_PART_MAIN);
    lv_obj_set_style_image_recolor_opa(img, LV_OPA_COVER, LV_PART_MAIN);
}