RLE Decompression

LVGL provides a custom RLE (Run-Length Encoding) decompression method. It can be used to reduce binary image size. The RLE compression is a lossless compression method.

The LVGL's built-in binary image decoder supports RLE-compressed images. The decoder supports both variable and file as image sources. The original binary data is directly decoded to RAM.

Benefits

Most screenshot and UI images (where there are a limited number of colors) can be compressed to save more than 70% space. The below statistics are from a watch project. It shows the file count of every compress level. For rare conditions, RLE compress may increase the file size if there's no large repetition in data.

RLE compress statistics from a watch project

Theory

The RLE algorithm is a simple compression algorithm that is based on the fact that for many adjacent pixels, the color is the same. The algorithm simply counts how many repeated pixels with the same color there are, and stores the count value and the color value. If the up-coming pixels are not repeated, it stores the non-repeat count value and original color values. For more details, the script used to compress the image can be found from lvgl/script/LVGLImage.py.

def rle_compress(self, data: bytearray, blksize: int, threshold=16):
    index = 0
    data_len = len(data)
    compressed_data = []
    while index < data_len:
        memview = memoryview(data)
        repeat_cnt = self.get_repeat_count(
            memview[index:], blksize)
        if repeat_cnt == 0:
            # done
            break
        elif repeat_cnt < threshold:
            nonrepeat_cnt = self.get_nonrepeat_count(
                memview[index:], blksize, threshold)
            ctrl_byte = uint8_t(nonrepeat_cnt | 0x80)
            compressed_data.append(ctrl_byte)
            compressed_data.append(
                memview[index: index + nonrepeat_cnt * blksize])
            index += nonrepeat_cnt * blksize
        else:
            ctrl_byte = uint8_t(repeat_cnt)
            compressed_data.append(ctrl_byte)
            compressed_data.append(memview[index: index + blksize])
            index += repeat_cnt * blksize

    return b"".join(compressed_data)

Usage

To use the RLE Decoder, enable it in lv_conf.h configuration file by setting LV_USE_RLE to 1. The RLE image can then be used in the same way as other images.

lv_image_set_src(img, "path/to/image.rle");

Generating RLE Compressed Binary Images

An RLE image binary can be directly generated from another image using script lvgl/script/LVGLImage.py.

./scripts/LVGLImage.py --ofmt BIN --cf I8 --compress RLE cogwheel.png

This will decompress cogwheel.png, and then re-compress it using RLE and write the output to ./output/cogwheel.bin.

API

lv_rle.h .. Autogenerated

lv_rle.h