Gopalakrishnan M
05 December 2023 Categories: Technology,

In the realm of product design and user interaction, the significance of visual communication cannot be overstated. In today's fast-paced world, where attention spans are fleeting and competition is fierce, the ability to captivate and engage customers within seconds is paramount. This is where images and visual elements step into the spotlight as a pivotal element in embedded product displays, serving as powerful tools to convey information, evoke emotions, and drive consumer action.

Image handling in QT

At the heart of Embedded product displays lies the visual allure of images, which play a multifaceted role in shaping perceptions, influencing decisions, and ultimately easing user’s life. QT for MCU is a capable library that can be used to render a variety of images.

The below picture shows how QT handles images.

Image Loading in QT based Embedded Systems

Image Loading in QT based Embedded Systems

Based on the application design, QT will fetch a static image from external flash or dynamic image from external memory and render the picture in UI. Let us understand them in detail in the upcoming sections.

Image usage in embedded systems GUIs

In embedded systems, images or pictures are used for various purposes depending on the specific application requirements. Here are some common types of image/picture usage in embedded systems:

Types Use cases
User Interface (UI) Elements Embedded systems often incorporate graphical user interfaces (GUIs) for user interaction. Images are used to represent buttons, icons, menus, and other visual elements to provide a more intuitive user experience
Data Visualization Images are used to display data in a graphical format, such as charts, graphs, and plots. This is particularly common in embedded systems used for monitoring and control applications where visualizing data trends is important
Diagnostic and Debugging Tools Images can be used in diagnostic and debugging tools to visualize system states, error conditions, sensor readings, or other relevant information for troubleshooting purposes
Logo and Branding Embedded systems deployed in commercial products often display logos or branding images during startup or as part of the user interface to reinforce brand identity
Documentation and Help Screens Images are used in embedded systems to provide visual aids in documentation, user manuals, help screens, and tutorials to assist users in understanding system operation and features
Displaying Images or Video Content Some embedded systems, especially those used in consumer electronics or digital signage, display images or video content for entertainment, advertising, or informational purposes

These use cases can be achieved using static and dynamic techniques. Static techniques mean pictures that are loaded and presented to the UI will not change, for example, company logo. With dynamic techniques images are loaded or updated in runtime, such as an alarm icon shown based on current error condition. Again, dynamic technique can involve preloaded images or on the fly rendering.

Below are some of the ways for above use cases can be achieved.


Types Technique Approach
User Interface (UI) Elements Static Load the required images as fixed during compile time and display in UI
Data Visualization Dynamic with on-the-fly-loading Show the dynamically generated images in run time on the UI
Diagnostic and Debugging Tools Dynamic with preloaded images Show different images available on compile time on the same location of UI
Logo and Branding Static Load the required images as fixed during compile time and display in UI
Documentation and Help Screens Static Load the required images as fixed during compile time and display in UI
Displaying Images or Video Content Dynamic with on-the-fly-loading Show the dynamically generated images in run time on the UI

Static Image loading in QT for MCU

In the QT qml, we can define the layout and image component by loading them during compile time itself.In the QT qml, we can define the layout and image component by loading them during compile time itself.


Image { 
    width: 130; height: 100 
    source: 'qrc:/embienlogo.png'
} 

Respective Image shall be loaded in the project and included in qmlproject or CMakefile like below.

In the QML project file by using image files property, required images has to be added to the project.


ImageFiles { 
    files: ['embienlogo.png'] 
} 

In case of a CMakefile project, below approach need to be followed to add image in the project.

 
qul_add_resource(PROJECT NAME    FILES embienlogo.png) 

Dynamic image loading in QT for MCU with preloaded images

In some cases, there is a placeholder, where one or more images needed to be loaded in the same place based on the system state.

For an example, in a cluster , there is a placeholder for headlight where either an icon for Hi-beam state or Low-beam/Dipped state will have to be shown based on the light setting. In the QT qml, we can define the layout and update image component properties in run time dynamically using a QT Object property variable. Let us see that with an example below.

In the QML project file by using image files property, Low-Beam and Hi-Beam images shall be added to the project.

Example(Test.qmlproject)
ImageFiles { 
    files: ['embienlogo.png',  
            'Hi-Beam.png',  
            'Low-Beam.png'] 
} 

Create a QT object variable to store the image name as string including path.

Example(TestModel.qml)

pragma Singleton 
import QtQuick 2.15 
QtObject { 
    id: TestModel 
    property string Headlight: '' => QT Object Variable 
} 

In the Test.QML, image component source properties can be updated with QT object variable that holds the image name.

Example(Test.qml)

Image { 
    Id:Headlight 
    source: 'qrc:/' + Headlight 
}

Now by updating QT object variable in run time as per need, we can swap the Hi-Beam image and Low-Beam image.

In the below example, we are checking the stored CAN data and updating the QT object variable to update the Telltale image in the GUI dynamically.

Example(Test.cpp)

void Headlight_Handler () 
{ 
::TestModel &model = < Model URI >:: TestModel::instance();	=>	Fetch instance of a singleton qtobject class 
          if (CAN message indicates Headlight DIM on) 
             Model.Headlight.setValue(“Low-Beam.png”); 
          else if (CAN message indicates Headlight Bright ON) 
             Model.Headlight.setValue(“Hi-Beam.png”); 
          else	/*Headlight OFF*/ 
             Model.Headlight.setValue(“”); 
} 

Dynamic Loading of Preloaded Images

Dynamic Loading of Preloaded Images

Dynamic image loading in QT for MCU with on-the-fly loading

For more user friendly and engaging product designs, the images must be loaded or rendered dynamically. For example, one can receive an image from mobile phone or cloud and display in UI in run time or render the images based on the currently selected theme. This cannot be achieved with the above 2 approaches as the image is not available in the system during compilation.

The process involved in achieving this in Qt is as follows.

  1. Fetch a custom or user image to the embedded system/product via wired or wireless interface.
  2. Decode the image and convert it to one of the image formats supported in QT as listed below.
    • PixelFormat_ARGB32
    • PixelFormat_RGB32
    • PixelFormat_RGB888
    • PixelFormat_RGB16
    • PixelFormat_Alpha8
    • PixelFormat_Alpha1
    • PixelFormat_ARGB4444
    • PixelFormat_RGB332
    • PixelFormat_RLE_ARGB32
    • PixelFormat_RLE_RGB32
    • PixelFormat_RLE_RGB888
  3. Develop a CPP class for image components and map the same to the image via
    
    source: 'image://Image Container/'
    
  4. Image Container class shall implement the requestImage method to draw the image on GUI pixel by pixel

One big change from earlier discussed 2 approach is that when developers compile the code, they don't have the actual image they need to display on the UI. Instead, the developer just set aside a space for the image. Developers will fill in this space later when they get the image information. Let's say a driver connects their phone to their car using Bluetooth or Wi-Fi. When the driver gets a call, the car's screen should show the caller's phone number and picture to make it more engaging.

Assume call info and picture are received in the board and now, let's figure out how to make the picture show up on the car's UI screen for the driver.

Step 1:

Create a QT object variable to enable or disable the visibility of image.

Example(TestModel.qml)

pragma Singleton 
import QtQuick 2.15 
QtObject { 
    id: TestModel 
    property bool CallerNotificationvisble: false			=> QT Object Variable 
} 
Step 2:

Create an image component in QML and provide the source of the image as CallerNotification.

CallerNotification class should be equipped with methods to process the QT request to draw image in UI.

This can be achieved in QT using Qul::ImageProvider and Qul::Image to display an image at run time.


Image { 
            source: 'image://callernotification/' + 'profile.png' 
            width: 800 
            height: 480 
            visible: TestModel.CallerNotificaitonvisible 
        } 
Step 3:

Create callernotification class to implement QT draw requests for image component. In the request image method, allocate a memory for image component and fill the memory with received user profile picture data.

CallerNotification.h:

#include  
#include  
#include  
#include  
#include  
#include  
struct MyImageLoadedEvent 
{ 
    MyImageLoadedEvent(Qul::Image &image) 
        : sharedImage(image) 
    {} 
 
    Qul::SharedImage sharedImage; 
}; 

struct CallerNotification : public Qul::ImageProvider, public Qul::EventQueue 
{ 
    Qul::SharedImage requestImage(const char *imageName, size_t imageNameLength) QUL_DECL_OVERRIDE; 
    void onEvent(MyImageLoadedEvent *const &event) QUL_DECL_OVERRIDE; 
    void onEventDiscarded(MyImageLoadedEvent *const &event) QUL_DECL_OVERRIDE; 
private: 
    Qul::SharedImage sharedImage; 
}; 
CallerNotification.cpp

#include 'callernotification.h'
#include  
#include  
Qul::SharedImage CallerNotification::requestImage(const char *imageName, size_t imageNameLength) 
{ 
    // Create the image and mark it as being-written-to 
    Qul::Image img(800, 480, Qul::PixelFormat_RGB16); 
    sharedImage = img; 
    img.beginWrite(); 

    // Start the image loading process. 
    // 
    // When done, post an event to trigger endWrite(). 
    // (postEvent() is safe to call asynchronously, while endWrite() is not) 
    // Fill a segment of the image with a solid color 
    assert(this->sharedImage.image()); 
    Qul::Image &image = *(this->sharedImage).image(); 
    uint16_t *pixelBegin = reinterpret_cast( 
        image.bits() + image.bytesPerLine() * image.height()); 
    uint16_t *pixelEnd = reinterpret_cast( 
        image.bits() + image.bytesPerLine() * image.height()); 
        memcpy(pixelBegin, , size);
} 
void CallerNotification::onEvent(MyImageLoadedEvent *const &event) 
{ 
    // Causes the finished image to become visible. 
    event->sharedImage.image()->endWrite(); 
    Qul::PlatformInterface::qul_delete(event); 
} 
 
void CallerNotification::onEventDiscarded(MyImageLoadedEvent *const &event) 
{ 
    // Causes the finished image to become visible. 
    event->sharedImage.image()->endWrite(); 
    Qul::PlatformInterface::qul_delete(event); 
} 		
Step 4:

Register CallerNotification class with the application and attach with QT application using addImageProvider API.


int main() 
{ 
    Qul::initHardware(); 
    CallerNotification mycallerProvider; 
    Qul::Application app; 
    app.addImageProvider('CallerNotification', &mycallerProvider); 

With the above approach we have completed including handling of custom image in QT for MCU. Now to complete the flow, once the call information received in cluster at predefined memory location, enable the image component visibility true to draw the profile picture received in caller information.

Step 5: Example(Test.cpp)

void Notification_Handler () 
{ 
Model URI::TestModel &model =  Model URI :: TestModel::instance();	=>	Fetch instance of a singleton qtobject class 
     If (Call Notification available){ 
       /*Decode the image and store in SDRAM*/ 
          Model.CallerNotificationvisble.setValue(true); 
} 
}  

With the above step showing of user profile picture in product can be successfully achieved.

Dynamic Loading in QT with On-the-fly Images

Dynamic Loading of On-the-fly Images

Conclusion

Thus, In the landscape of embedded systems, image usage spans from static branding elements to dynamically updating visualizations. By understanding the nuances of static and dynamic image loading methodologies, developers can tailor solutions to meet diverse application needs efficiently in the Qt environment. Please note that these are some basic techniques and more advanced mechanisms can be built on top of it to achieve a much more engaging user interface.

Embien has been in the field of QT based designs for many years helping customers realize stunning GUIs on resource constrained embedded systems. Get in touch with our QT development team to leverage our QT expertise.

Subscribe to our Blog