C

Managing Resources

This topic describes how Qt Quick Ultralite applications make use of image resources.

Font resources are not added through the resource system. For more information about font handling, see Text Rendering and Fonts.

See also topic on Image Caching.

Summary

To use resources in a Qt Quick Ultralite application, you must declare them using the CMake API.

The resource compiler (qulrcc tool) uses the resource declarations to prepare the contents for inclusion. It may perform optimizations on the raw resource data. For example, image optimization can result in lowering color depth, replacing with alphamap, removing outline transparent areas, and swizzling.

Adding files to the resource system

Use the ImageFiles.files QmlProject property to add resources to a Qt Quick Ultralite application.

ImageFiles {
    files: ["ui/spinner.png", "background.png"]
}

The function adds the files into to a virtual resource filesystem. Resources in the filesystem are referenced through resource URIs with the optional "qrc:" scheme.

qrc:/
  |-- background.png
  |-- ui/
       |-- spinner.png

In the above example, qrc:/ui/spinner.png is a resource URI for the resource data based on the ui/spinner.png file from the source directory. It can be displayed by using its URI as source in an Image:

Image {
    source: "qrc:/ui/spinner.png"
}

When using relative paths in resource URIs, the paths are relative to the root of the virtual resource filesystem. The scheme of the URI can be omited. The following URIs all refer to ui/spinner.png:

  • ui/spinner.png
  • /ui/spinner.png
  • qrc:ui/spinner.png
  • qrc:/ui/spinner.png
  • qrc:///ui/spinner.png

Resource properties

Optionally, you can set resource properties for a set of images listed using ImageFiles.files, from the list of available properties in the QmlProject ImageFiles node.

ImageFiles {
    files: ["image.png"]
    MCU.resourceCompression: true
}

Image resources support a number of resource properties that control how the image is stored on the device, or can trigger different optimizations. See QmlProject Manual (Technology Preview) for the full list.

In the following example, the large background.png is stored in a compressed format by setting ImageFiles.MCU.resourceCompression, while spinner.png is tagged with ImageFiles.MCU.resourceOptimizeForRotation to optimize it for runtime rotation:

ImageFiles {
    files: ["spinner.png"]
    MCU.resourceOptimizeForRotation: true
}
ImageFiles {
    files: ["background.png"]
    MCU.resourceCompression: true
}
Image {
    source: "qrc:/background.png"

    Image {
        anchors.centerIn: parent
        source: "qrc:/spinner.png"
        transform: Rotation {
            NumberAnimation on angle { from: 0; to: 360; running: true; loops: Animation.Infinite }
        }
    }
}

Lossless compressed image formats

Qt for MCUs supports Run-Length Encoding (RLE) compression formats as an alternative to ImageFiles.MCU.resourceCompression. It is useful if significant parts of an image have the same color. The RLE format options for the ImageFiles.MCU.resourceImagePixelFormat property are: RGB888RLE, XRGB8888RLE, and ARGB888RLE.

The supported RLE formats vary depending on the platform. Therefore, use the AutomaticCompressedLossless option to automatically choose the ideal format depending on the MCU.Config.platformOpaqueCompressedLosslessResourcePixelFormat and MCU.Config.platformAlphaCompressedLosslessResourcePixelFormat settings for the platform.

The benefit of using AutomaticCompressedLossless is that the images can be decoded on the fly as they are being blended, without decompressing them into the image cache. This means, less volatile memory is needed compared to images that use ImageFiles.MCU.resourceCompression.

However, the average compression ratio is not as good, and transformed images are not supported. It could also have a negative impact on the blending performance, as it uses CPU fallback on most platforms. The CPU is usually slow at blending images that contain a lot of semi-transparent pixels or if the computed Item::opacity value is less than one. Refer to the Supported Features table for information about platforms that support hardware accelerated blending of RLE pixel formats.

The following table shows two example images along with their uncompressed and compressed (RLE or PNG) sizes. The first image compresses a lot better due to the contiguous areas that contain the same pixel value. Compressing such images into PNG using ImageFiles.MCU.resourceCompression produces even better compression ratios, but they must be decompressed onto the image cache before drawing on screen.

Image

Uncompressed82.9 kB82.9 kB
RLE compression23.2 kB72.6 kB
PNG compression6.7 kB27.5 kB

Here are some useful heuristics for when to use PNG or RLE compression to better blending performance:

  • OnStartup cache policy - On platforms that have sufficient flash and volatile memory for the application.
  • RLE compression - On platforms that support hardware accelerated blending without intermediate buffers. You could also use it on platforms without hardware acceleration, if the performance overhead is acceptable.
  • PNG compression with ImageFiles.MCU.resourceCompression - On platforms that do not have sufficient memory required to store all the uncompressed image resources. If the image cache is big enough to fit all the visible images on screen at the same time, animation performance will be good as all the required images are in the volatile memory.
  • AutomaticCompressedLossless or uncompressed images without caching to retain the images in flash memory. One of these two techniques is ideal on platforms with limited volatile memory, as PNG compression is not an option on such platforms.

Here's how to enable the use of lossless compression for a given image resource:

ImageFiles {
    files: "example.png"
    MCU.resourceImagePixelFormat: "AutomaticCompressedLossless"
}

Resource placement in memory

By default a resource is placed in a reserved memory section named QulResourceData. Resources can be placed in a different storage section by setting the ImageFiles.MCU.resourceStorageSection property. The ImageFiles.MCU.resourceCachePolicy property controls when and how resources are loaded into volatile memory. When different kinds of volatile memory are available (for example RAM, VRAM or HyperRAM), the ImageFiles.MCU.resourceRuntimeAllocationType property can be used to choose the volatile memory region to use for a given resource.

In the following example, three images are stored in a memory section named Arrows.

set(ARROWS
    images/arrow-0.png
    images/arrow-45.png
    images/arrow-90.png
)

set_source_files_properties(${ARROWS} PROPERTIES QUL_RESOURCE_STORAGE_SECTION "Arrows")
qul_add_resource(app FILES ${ARROWS})

The section name can be freely chosen as long as a section with the same name is defined in the linker script. The section start address needs to be aligned to the largest alignment requirement among resources within the same section.

Arrows :
{
    . = ALIGN(4);
    *(Arrows)
} > QSPI_FLASH

OTA resources update

If the user wants to do an over-the-air (OTA) update of some resources, these resources should be placed in a specific memory section (for example OTAResourceSection) as shown above in Resource placement in memory.

Once the user has updated the images that are part of the OTA update on the host, it is possible to regenerate the binary content of the OTAResourceSection for a given target application.

Such binary generation is performed by the resource compiler and can be invoked via CMake as follows:

cmake --build . --target <application>_resource_binaries

without the need of recompiling the whole application. The resource binaries are named qul_resources_<section_name>.bin (for example qul_resources_OTAResourceSection.bin) and can be found in the target application build folder.

Since some of the images might either be cached (OnDemand) or preloaded at startup (OnStartup) with ImageFiles.MCU.resourceCachePolicy, the Qt Quick Ultralite application must be restarted for the images part of the OTA update to be effectively used by the application.

Notes

  • Apart from generating new binary data, Qt Quick Ultralite does not offer any direct mechanism for rewriting the data to Flash memory. An application specific solution will need to be implemented.
  • The resource binary content is in Little-Endian format.
  • Filenames need to match with the ones that have been used in the QML application originally. Otherwise the resource lookup will fail.
  • To avoid overwriting other memory areas, the section part of an OTA update should be placed last in Flash.
  • The flash memory must be erased and rewritten on a block-by-block basis. If the binary data does not start and end on the exact block boundaries, it might be necessary to read the old data for the memory blocks that will be erased. Ensure to take this into consideration if the flashing tool or library you are using does not handle it automatically.

Resource properties for sprite animation

Sprite animation involves some preprocessing at compile time. Resource properties give useful information for the process, enabling it to optimize the resources.

A sprite animation source can be a directory that has a series of image files, which can be rendered by AnimatedSpriteDirectory QML type. Tag such image files with ImageFiles.MCU.resourceAnimatedSprite in the .qmlproject file, to enable identify their directory name at compile time.

    ImageFiles {
        files: [
            "loading/01.png",
            "loading/02.png",
            "loading/03.png",
            "loading/04.png"
        ]
        MCU.resourceAnimatedSprite: true
    }

This enables identifying the image files directory and using it as the sourcePath for AnimatedSpriteDirectory. The following example demonstrates how you can do it:

import QtQuickUltralite.Extras

AnimatedSpriteDirectory {
    sourcePath: "loading"
}

See also ImageFiles.MCU.resourceImagePixelFormat and QUL_BINARY_ASSET_OPTIONS.

Available under certain Qt licenses.
Find out more.