图像压缩
TouchGFX从4.22版开始支持图像压缩。 The support from version 4.22 to 4.23 inclusive is limited to compression of L8 images. From version 4.24 compression of RGB565, RGB888, and ARGB8888 image formats is supported.
图像压缩是降低图像存储需求的过程。 如果使用较小的闪存,缩减项目中的图像存储空间可以降低成本。 缩减还意味着可以在项目中使用更多的图像,从而获得更丰富的UI。
图像压缩通常有两种风格:无损或有损。 有损图像压缩通过去除图像的微小细节来实现。 这样通常会得到最大的缩减,但原始图像无法准确再现。 无损压缩总是无任何差异地再现原始图像。 无损压缩的尺寸缩减通常较小。
对于图形,通常要求UI元素完全按照其设计来绘制。 因此,TouchGFX只支持无损压缩。
图像压缩的优点是存储空间减少,但也有缺点,因为图像在绘制到帧缓存时必须解压缩。 与绘制未压缩的图像相比,这种解压缩在许多情况下需要CPU做更多的工作。 结果可能是性能下降。
这意味着必须将闪存减少带来的优势与CPU使用率增加带来的劣势进行比较。
请注意,许多STM32微控制器中的图形加速器DMA2D和GPU2D(ChromART and NeoChrom GPU)不能直接绘制压缩图像。 Compressed images are drawn using a mix of software and hardware rendering, i.e. the compressed data is decompressed in chunks by software and these chunks are then delegated to the DMA2D where applicable.
许多应用中,不建议压缩所有图像,而是只压缩那些性能不受影响且与减少闪存相关的图像。 See also the section below about decompression to the Bitmap cache as a mean to get both lower storage requirement and good performance.
L8压缩
如上所述,TouchGFX 4.22支持L8图像压缩。 回想一下,L8位图格式仅适用于高达256色的图像。 每个像素只是一个8位数字,表示与图像一起存储的颜色表中的一种颜色。 The compression of an L8 is only compression of the pixel numbers. 颜色表保持不变。
以下图为例。 其在计量应用中用作背景。
图像为184 x 184像素。 The size of the pixel data is thus 184 x 184 = 33,856 bytes.
If we compress the image the pixel data is reduced to 5,735 bytes. The total size of the compressed image data, including the color table, is less than 20% of the original image. Compression thus allows us to have 5 different backgrounds in the same flash space, or to reduce the flash requirements by 28,121 bytes.
压缩的L8图像像普通的未压缩位图一样使用。 例如,您可以使用图像控件显示图像,而无需在TouchGFX Designer或代码中对项目进行任何修改。 This makes use of compressed L8 images very easy.
3 algorithms #{three-algorithms}
TouchGFX uses 3 different compression algorithms for the L8 format. The image converter selects the algorithm that gives the best compression, unless the user has mandated a specific algorithm in the configuration. The algorithms are:
- L4,对每个像素进行4比特编码。 仅适用于最多16种颜色的图像。
- RLE,像素的游程编码。 仅适用于最多64种颜色的图像。
- LZW9,基于词典的编码。 适用于所有L8图像。
RLE算法的解压缩速度比LZW9快得多,因此如果LZW9仅压缩图像,转换器将选择RLE稍微好一点。
RGB Compression
As mentioned earlier, TouchGFX 4.24 introduced image compression support for the RGB565, RGB888, and ARGB8888 image formats. Images which contains more than 256 unique colors cannot be stored in the compact L8 image format and must be stored in one of the aforementioned formats. The compression of an RGB565, RGB888, or ARGB8888 image is directly compressing the 16-, 24-, or 32-bit pixels.
以下图为例。 It is a more complex and rich background than the above example and has more than 256 unique colors. Therefore, it cannot be stored in L8, and it must be stored in the ARGB8888 format because it has transparent pixels (in the corners).
The image is 240 x 240 pixels. The size of the pixel data is thus 240 x 240 x 4 = 230.400 bytes because we use 4 bytes to store each pixel in the ARGB8888 image format.
Compressing the image reduces the size to 32.347 bytes. The size of the compressed image is considerably smaller and only 14% of the original image size. Compression allows us to have multiple complex backgrounds in the same flash space, or reduce the flash requirements by a substantial amount. It also enables flash-limited devices to adopt more complex and rich graphics than otherwise possible with the L8 formats.
A compressed RGB image can be used like an ordinary uncompressed bitmap. 例如,您可以使用图像控件显示图像,而无需在TouchGFX Designer或代码中对项目进行任何修改。 This makes use of compressed RGB images very easy.
Caution
2 algorithms
TouchGFX uses 2 slightly different compression algorithms which are automatically selected based on the image format to be compressed. The algorithms are:
- QOI, encodes RGB888 and ARGB8888 pixels using a variation of the Quite OK Image format compression algorithm.
- QOI565, encodes RGB565 pixels using a variation of QOI that is tailored for 16-bit pixel values.
Both variants of the RGB Compression algorithms are optimized for fast decompression speeds to limit the run-time performance penalty when rendering compressed RGB images.
Working with Compressed Images
Enabling the Image Compression Features
Image compression requires extra code in the target application. To avoid this higher space requirements, the compression code is optional on some platforms. You may have to enable the feature for your project.
Click "Config" on the left of the Designer, then click "Framework Features"
The image compression features are shown in the bottom. You can enable the specific feature set you need.
The targets has different options for the framework features, and in some cases the target has no optional features as shown below:
In this case all the features are always enabled.
Caution
L8压缩
压缩图像和普通图像用法相同。 您可以在TouchGFX 设计器中将控件配置为使用位图,也可以在代码中分配位图。
唯一需要的配置是将“压缩”值设置为“自动”。 然后,图像转换器将自动选择最合适的压缩,或者如果图像不可压缩则不选择。
现在,我们可以正常选择控件的图像。 与未压缩的图像相比,没有什么区别。
使用代码中的图像也没有区别。 通常用压缩位图的BitmapID来进行引用:
image1.setXY(148, 148);
image1.setBitmap(touchgfx::Bitmap(BITMAP_GAUGE_BACKGROUND_ID));
在此阅读有关压缩L8图像的更多信息
RGB Compression
Compressing RGB565, RGB888, or ARGB8888 images in the TouchGFX Designer follows the same process as L8 compression.
If selecting "Yes" the Image Converter will compress the image with the algorithm that matches the image format.
As with the L8 Compression, we can select the image for a widget as normal and reference the bitmap in code as usual.
压缩等级
图像转换器选择的压缩算法会写入生成的文件中。 在这里我们还可以找到压缩等级。
The image we used above in the L8 Compression example is generated into the file generated/images/src/image_gauge_background.cpp
. The header of this file reads:
image_gauge_background.cpp (extract)
// 4.22 D0 AN R0 FL8_ARGB8888 U888 N0 SExtFlashSection EExtFlashSection CL8_LZW9
LOCATION_PRAGMA("ExtFlashSection")
KEEP extern const unsigned char image_gauge_background[] LOCATION_ATTRIBUTE("ExtFlashSection") = {
// 184x184 L8_ARGB8888 pixels. 压缩[输出/输入x 100]:5735/33856 x 100 = 16.9% 0x00, 0x26, 0x50, 0xa8, 0x60, 0xe1, 0x02, 0x86, 0x0c, 0x1a, 0x36, 0x70, ....
The end of the comment in the first line shows the compression algorithm. 这里,我们看到图像转换器已经选择了LZW9算法。 第5行的末尾显示,我们现有5735字节的像素数据,而原来是33856字节。 结果压缩到16.9%(压缩级别越小越好)。 注意! The compression percentage does not count the color table.
Compression Failure
In some cases the Image Converter gives a warning or error when compressing images. This can happen if the image is not compatible with the selected algorithm, or if the size of the compressed image is not below 90% of the original image. This will only happen in very rare coincidences. For example if a small image of 5 x 5 uses 25 different and distinct colors. Since there is no repetition or redundancy in the image, there is no possibilities for the compression to reduce the data.
L8 Images
For L8 images this can happen if a specific algorithm was selected that does not match the given image. For example if an image contains 17 colors or more, and and L4 compression is selected, the image can not be compressed using the selected algorithm. The Image Converter will print an error message when you generate code, and the Designer will show an error message:
The solution to the problem is to use another algorithm. The preferred way is to select "Auto" for L8 images. Then the image converter will try all algorithms, and select the best algorithm of those who are applicable.
In some rare cases the image does not compress below 90% of the original size. The Image Converter does not compress the image in that case and issues a warning text as shown below:
The reason for not compressing is that the saving in flash size does not outweigh the lower rendering performance. It is possible to force the compression by not using "Auto" but selecting one of the algorithms ("L4", "RLE", or "LZW").
The warning message is only informational. The code generation continues and the project will work as expected.
RGB Images
For RGB image formats you can not select the "Auto", as there is only one compression algorithm. If you select "Yes" and the image is not compressible below 90% of the original size, the Image Converter will generate an error:
The solution here is to select "None" for Compression for the image.
Decompressing Images to the Bitmap Cache
大多数情况下,绘制压缩图像的性能比绘制未压缩图像差。 Further more, as mentioned in the introduction, the graphics accelerators in STM32 micro-controllers (DMA2D and GPU2D) cannot draw the compressed images directly. Therefore, compressed images are drawn by a mix of software and hardware, resulting in lower performance and higher cpu-load.
出于这些原因,TouchGFX还包含在运行时将压缩图像解压缩到RAM中位图缓存的功能。
当图像被解压缩到RAM时,绘制性能类似于使用未压缩的图像,加速器可以绘制图像。
要解压缩,我们首先需要设置位图缓存。 在此阅读有关使用位图缓存的更多信息。
设置位图缓存后,我们可以使用函数Bitmap::decompress
来解压缩图像。 完整代码如下所示:
// Define an array for the bitmap cache
uint16_t cache[20*1024]; //40 KB cache
// Define an array for the decompression temporary buffer
uint16_t lzwBuffer[1024];
void TemplateView::setupScreen()
{
...
Bitmap::setCache(cache, sizeof(cache)); // Register the bitmap cache
bool r = Bitmap::decompress(BITMAP_GAUGE_BACKGROUND_ID, lzwBuffer); // Decompress the bitmap
image1.setBitmap(touchgfx::Bitmap(BITMAP_GAUGE_BACKGROUND_ID)); // Use the bitmap as normal
image1.setXY(148, 148); // Position Image widget
}
In this example we want to decompress the 184 x 184 image from the L8 Compression example above into the bitmap cache. The bitmap cache must be big enough to the hold uncompressed image. The 184 x 184 pixels plus the color table holding 207 ARGB8888 colors. The total size is therefore 34,688 bytes.
In this example we use the LZW9 algorithm. A 2048 bytes buffer is used by the decompresser during the decompression of an LZW9 compressed image (for building a dictionary). The buffer is not required after the decompression and can be reused for other purposes. The buffer is not required for decompression of L4, RLE, QOI, or QOI565 compressed images.
当不再使用解压缩图像时,可以使用Bitmap::cacheRemoveBitmap
将其从位图缓存中移除。
Limit program size
If you use decompression into the bitmap cache you have a few options to limit the size of your program. As mentioned above there are two types of image compression; L8 and RGB. When using Bitmap::decompress
your program will contain the code for both decompressing L8 and RGB images. If you only use the RGB image compression, you can use the dedicated method for decompressing RGB images into the bitmap cache, which is Bitmap::decompressRGB
, that way your program will only contain the required code for decompressing RGB images. The same applies if you only use L8 compression, here the method is called Bitmap::decompressL8
. See examples below.
void TemplateView::setupScreen()
{
...
// Decompress the bitmap (RGB using QOI)
bool r = Bitmap::decompressRGB(BITMAP_GAUGE_BACKGROUND_ID);
...
}
void TemplateView::setupScreen()
{
...
// Decompress the bitmap (L8 using RLE, no buffer required)
bool r = Bitmap::decompressL8(BITMAP_GAUGE_BACKGROUND_ID);
...
}
限制
There are a few limitations when working with compressed images. Compressed images cannot be used with Widgets that scales or rotates the image, or with Widgets that fills an area, or with the Canvas widgets.
Caution
These limitations are made for performance reasons. TouchGFX 设计器不允许您选择压缩图像。
If you want to use a specific image with any of these Widgets we suggest to not enable compression for the image. Alternatively, you can decompress the image at runtime.
不支持压缩图像的控件有:
- 纹理映射
- 可缩放图像
- 指针和弧形仪表
- 用于填充图形下方区域的静态和动态图表
- 指针模拟时钟
- 圆、线和形状
- 圆形和线形进度条