Skip to content

LVGL 9 Images: C Arrays, PNGs, and v8 Migration ​

Abstract image descriptor and orange pixel matrix aligning into a single image object

In LVGL 9, a converted image asset is described by lv_image_dsc_t. Create an image object with lv_image_create(), then pass the descriptor's address to lv_image_set_src(). The C file containing that descriptor must also be part of the firmware build.

If your example uses lv_img_dsc_t and lv_img_set_src(), check its version before copying it. Those are the names used in LVGL 8 tutorials.

Check the version at both ends ​

There are two versions to match: the library in your firmware and the converter that produced the asset. A v9 function call does not repair a descriptor generated for a different format.

TaskLVGL 8 namesLVGL 9 names
Describe an imagelv_img_dsc_tlv_image_dsc_t
Declare an external imageLV_IMG_DECLARELV_IMAGE_DECLARE
Create an image objectlv_img_createlv_image_create
Set its sourcelv_img_set_srclv_image_set_src

The official LVGL 8 image reference and LVGL 9 image reference show the respective APIs. Compatibility aliases may exist in a particular build, but using one version consistently makes integration easier to inspect.

Add a converted image to LVGL 9 ​

Assume your converter generated status_logo.c and the descriptor inside it is named status_logo. Add that file to the source files compiled by your project. Then use this integration function after LVGL and the display are initialized:

c
#include "lvgl.h"

LV_IMAGE_DECLARE(status_logo);

void add_status_logo(lv_obj_t *parent)
{
    lv_obj_t *image = lv_image_create(parent);
    lv_image_set_src(image, &status_logo);
    lv_obj_align(image, LV_ALIGN_TOP_LEFT, 12, 12);
}

The name must match the symbol inside the generated file, which may differ from the filename. This example supplies integration code, not the logo's pixel data.

Compile the asset once. Including a .c file directly while also compiling it separately can define the same symbol twice. An external declaration makes the symbol visible; it does not supply its definition.

Why the descriptor matters ​

A pointer to image pixels does not tell LVGL their dimensions or color format. The descriptor carries that information alongside the data pointer and size. The exact fields are defined in the LVGL 9.2 image descriptor header.

Keep the converter-generated descriptor intact when testing. Editing its width to stretch an image changes how the data is interpreted; it does not resample the pixels. Regenerate the asset at the desired dimensions instead.

For a first check, use a small image with a visible border and an asymmetric mark in one corner. It is easier to spot clipping, orientation, and missing rows than with a uniform background.

A PNG file needs a different path ​

LVGL can use image variables or file-backed sources, but those routes have different requirements. A raw converted C asset already contains pixel data. A .png file still needs a suitable decoder, and a filesystem source also needs storage access configured in the firmware. The image storage guide explains that distinction.

For a fixed status logo, a compiled asset is often straightforward to manage. For images users replace on an SD card, a file-backed path may suit the product better. Keep a known working compiled image available while bringing up the filesystem and decoder, so an empty widget does not leave you debugging everything at once.

Using Lopaka for the asset and layout ​

Lopaka's current platform documentation identifies v9 as its LVGL C API target. It also documents downloadable image assets. Match that output to the LVGL version already used by your board's firmware.

The editor handles the screen design. Display initialization, storage drivers, input handling, and application behavior still belong in your firmware. If you are choosing a display workflow first, start with the ESP32 GUI builder guide.

Common questions ​

Why do I get an undefined reference to my image? ​

Check that the generated asset is compiled and that its exported symbol matches the declaration. In a mixed C/C++ project, also check linkage at the declaration boundary.

Can I rename lv_img_dsc_t to lv_image_dsc_t? ​

Regenerate for the intended LVGL version. Renaming the type alone does not establish that the header layout, color constants, and payload are compatible.

Why does the image appear with the wrong dimensions? ​

Compare the source dimensions, converted dimensions, descriptor, and widget settings. Fix the first mismatch you find, then retest the same small asset.