Skip to main content

Using the L8 Image Format to Reduce Memory Consumption

Images in the L8 format take up less flash storage and are faster to draw than e.g. ARGB8888.

An image in L8 format consists of a color palette and a pixel array: The color palette lists up to 256 different colors specified in either 16-bit format RGB565, 24-bit format RGB888, or 32-bit format ARGB8888. The pixel array consists of one byte for each pixel. This byte is an index into the color palette (list of colors), pointing out the color for the pixel. The TouchGFX framework draws an L8 image by reading the pixels one-by-one, looking up the colors in the palette and writing these to the framebuffer. This happens automatically and is accelerated by the STM32 Chrom-ART hardware accelerator, if available on the hardware.

8-bit per pixel means that one L8 image can use 256 different colors. Another L8 image can use 256 other colors, since the two images each have their own palette.

An L8 image with 4 x 4 pixels and a palette with 4 colors

Pixels are one byte (8-bit) each. The size of the pixels is therefore width x height bytes. The palette colors can be 16-bit, 24-bit, or 32 bit colors. Each color definition will therefore take up 2, 3, or 4 bytes.

Solid images should be stored in L8_RGB888. If the image is transparent the 32-bit format (ARGB8888) must be used:

FormatFramebuffer formatSupports transparent pixels Supported by DMA2D
L8_RGB56516-bit RGB565NoNo
L8_RGB88824-bit RGB888NoYes
L8_ARGB8888BothYesYes

The L8 format with a RGB565 palette is not supported by DMA2D. This means that drawing images in this format is not hardware accelerated. This format should therefore not be used unless you are on a platform without DMA2D (for example the STM32G0 or STM32F410).

If you are using a serial flash (non-memory-mapped) to store the images and a 16-bit framebuffer (format RGB565), then you should use the L8_RGB565 format, because the color format then matches the framebuffer format and is faster to copy to the framebuffer.

The table below shows the preferred L8 format:

Framebuffer formatPlatform has DMA2D Platform without DMA2D
RGB565L8_RGB888L8_RGB565
RGB888L8_RGB888L8_RGB888
ARGB8888L8_RGB888L8_RGB888

Transparent images should always be in L8_ARGB8888.

Further reading
  • Read more about palette image formats here: https://en.wikipedia.org/wiki/Indexed_color
  • L8 Image

    Here is a typical logo image. This image only uses 16 different colors:

    200 x 200 pixels L8 image with 16 different 24-bit colors.

    The size in flash of this image is significant lower than the original image in the standard 24-bit format (RGB888). The table below lists the flash usage for this concrete image for the three different palette formats and for the non L8 format

    FormatSize of pixels (bytes)Size of palette (bytes)Total size (bytes)Reduction (%)
    RGB888120,0000120,000-
    L8_RGB56540,0003240,03266.6
    L8_RGB88840,0004840,04866.6
    L8_ARGB888840,0006440,06466.6

    We see that the size reduction is very large, and that the size of the palette is insignificant on a medium sized image.

    Using L8 Images in TouchGFX Designer

    It is very easy to use the L8 image format in TouchGFX. The only thing to do is to configure the Image Converter to convert the image from PNG to L8 format. Here we will go through the whole process:

    Start a new project in the TouchGFX Designer. Copy your image to the assets/images folder in the new project:

    Images folder of TouchGFX project

    Now go to the TouchGFX Designer and click the Images tab in the top bar and select the image:

    Logo in Images view of TouchGFX Designer

    On the right side on the window, select image format L8_RGB888 (this example is running 24 bit colors).

    An image Widget can now be inserted on the canvas (here we inserted a Box in the background):

    Image widget on Canvas in TouchGFX Designer

    Nothing needs to be changed in the UI code. The Image Converter converts the PNG file and generates an image in L8 format because of the configuration we did in the Images tab.

    Transparent Images

    As mentioned above it is also possible to use L8 format for images with transparency.

    170 x 60 pixels button image in 32 bit format ARGB8888

    The above image uses 108 colors (many shades of blue). This image can use the format L8_ARGB8888. The size will be significantly lower:

    FormatSize of pixels (bytes)Size of palette (bytes)Total size (bytes)Reduction in %
    ARGB888840,800040,800-
    L8_ARGB888810,20043210,63273.9%

    Moving the palette to internal flash

    On platforms that uses non-memory-mapped flash for the images (for example the STM32G0, STM32U0, or STM32C0), it is required to move the L8 palette data to internal flash. Otherwise the L8 images will not be drawn.

    Configure location of extra data for an image to be in internal flash.

    The palette of an image can be moved to internal flash by changing the "Extra Section" to "IntFlashSection" in the TouchGFX Designer (Open the Images tab, find your image, and go to the right-most column).

    L8 Image Compression

    Memory consumption can be reduced even more by selecting L8 compression of your L8 image. The Image Converter supports 3 compression algorithms (L4, RLE, LZW9). In the TouchGFX Designer you can set the Compression value to "Auto", this will let the Image Converter select the suitable algorithm for your image, alternatively you can force a specific algorithm. The gain in reduced memory, comes in some cases with a price of increased CPU load due to decompression directly to the framebuffer when the image is drawn.

    Selecting L8 Image Compression

    Note
    Default Dither Algorithm and Alpha Dither is disabled for L8 compressed images. Select a specific Dither Algorithm and Alpha Dither on each L8 image if required.

    The L8 image compression has a default setting which is configurable on the Default Image Configuration tab in the TouchGFX Designer, see screenshot below. Here you select what the default setting for your entire application should be.

    Default L8 Image Compression setting

    Caution
    Compressed images can not be used with all Widgets. See the list.
    Further reading

    In the following we will use the L8 image from previous to demonstrate the compression capabilities of each algorithm and the performance of decompression.

    We use the STM32F429-DISCO with an application containing 4 screens, with different compressions:

    • No compression
    • L4 compression
    • RLE compression
    • LZW9 compression

    Example screen (240x320) with the L8 image running on STM32F429-DISCO

    Note
    The DMA2D is disabled to compare software rendering only.
    FormatCompressionSize of pixels
    (bytes)
    Size of palette + header
    (bytes)
    Total size
    (bytes)
    Reduction
    (%)
    Performance
    (render time in ms)
    RGB565No80,000080,0000-
    L8_RGB565No40,00032 + 440,03650.02.12
    L8_RGB565L420,00032 + 420,03675.02.34
    L8_RGB565RLE3,19732 + 1643,39395.71.66
    L8_RGB565LZW94,47532 + 1684,67596.17.45

    The above table shows both the memory reduction from compression and the performance for decompression when the image is drawn. Both the compression (reduction) and decompression (performance) highly relies on the complexity of the image and number of colors. Each algorithm has its limits of application, meaning, L4 is limited to 16 colors, RLE is limited to 64 colors and LZW9 works for all L8 images, i.e. no limits. Furthermore it is a fact that L4 and RLE performs better than LZW9, when drawing the image, but as mentioned they are not able to cover all L8 images. All algorithms will decrease in performance if the image is clipped. In general this means you always have to consider the number of colors (quality requirement), the flash memory available (reduction requirement) and the complexity of your application (animations) when you use L8 image compression. E.g. if you have an image with more than 64 colors and you use LZW9 but the performance penalty is to high, you could try and reduce the number of colors in the image to 64 or less, if your quality requirements allow it, and then select RLE. If that is not possible then your might be better of using an uncompressed L8 image. See ImageMagick for how to reduce colors in your image.

    If you are not going to use L8 image compression in your application, you should disable the feature, below screenshot from the TouchGFX Designer shows you how.

    Disabling L8 Image Compression

    Example of compressed and uncompressed L8 images in a Widget

    Even though L8 image compression can't be used for all widgets, it is still possible to have some images compressed and others uncompressed in a widget composed of multiple images, e.g. Gauge and Analog Clock. Below is an example showing how the background is compressed and the needle is uncompressed in a Gauge widget.

    Images used in Gauge widget

    Gauge widget

    Converting an image to 256 colors or less

    Many images use more than 256 colors. This is common for images that are photo-realistic or images with gradients. These images cannot directly be converted to L8 image format in the TouchGFX Designer, because they contain to many colors.

    In many cases though, it is possible to reduce the number of colors used in a specific image. Ideally, a graphics artist will convert/supply the images in 256 colors, however image manipulation tools can also perform the conversion without loosing too much of the image quality.

    Paint.NET

    The simplest way is to use Paint.NET. Open the original image and use Save As to save the image in another file. In the Save Configuration dialog, select 8-bit, as pixel depth:

    Paint.NET saving image in 8 bit format

    Now use the new PNG in your project. Remember to select the L8_ARGB8888 format in the Images tab in the TouchGFX Designer. Shadows are not handled very well, but icons with transparent edges looks good in many cases. It is possible to adjust the "Transparency threshold" value and in some cases improve the result.

    ImageMagick

    Another suitable tool, that sometimes results in better L8 images, is ImageMagick (download from www.imagemagick.org). This tool can convert images from the command line. This makes it suitable for use in scripts. To convert the clock_bg.png to an image using at most 256 colors, use the following command:

    magick convert clock_bg.png -colors 256 clock_bg_l8_256.png

    You can also reduce the colors to less than 256 colors, in the case of enabling the RLE or L4 compression algorithms.

    magick convert clock_bg.png -colors 64 clock_bg_l8_64.png

    ImageMagick can also tell you how many colors are used in an image. Use this command:

    magick identify -format %k Blue_Buttons_Round_Edge_small.png

    Comparison

    The three images (original, L8 using Paint.NET, L8 using ImageMagick) are seen below for comparison:

    Clock image comparison, left to right: original, Paint.NET, ImageMagick

    The middle clock lost the details in the border shadow. In both cases the central part of the clock background looks usable.

    Manual Configuration

    It is also possible to select image formats and compression algorithm without using the TouchGFX Designer. The settings are specified in file application.config located in the project root:

    application.config
    {
    "image_configuration": {
    images": {
    "Blue_Buttons_Round_Edge_small.png": {
    "format": "L8_ARGB8888",
    "l8_compression": "LZW9"
    }
    },
    "dither_algorithm": "2",
    "alpha_dither": "yes",
    "layout_rotation": "0",
    "opaque_image_format": "RGB888",
    "nonopaque_image_format": "ARGB8888",
    "section": "ExtFlashSection",
    "extra_section": "ExtFlashSection",
    "l8_compression": "yes"
    }
    }

    The "images" section under "image_configuration" specifies the format for individual images. If an image is not mentioned here, the image will be generated in the default format (opaque_image_format or nonopaque_image_format).

    We recommend using the TouchGFX Designer for image configuration when possible.