图像压缩
TouchGFX从4.22版开始支持图像压缩。 4.22版仅支持L8图像压缩。
图像压缩是降低图像存储需求的过程。 如果使用较小的闪存,缩减项目中的图像存储空间可以降低成本。 缩减还意味着可以在项目中使用更多的图像,从而获得更丰富的UI。
图像压缩通常有两种风格:无损或有损。 有损图像压缩通过去除图像的微小细节来实现。 这样通常会得到最大的缩减,但原始图像无法准确再现。 无损压缩总是无任何差异地再现原始图像。 无损压缩的尺寸缩减通常较小。
对于图形,通常要求UI元素完全按照其设计来绘制。 因此,TouchGFX只支持无损压缩。
图像压缩的优点是存储空间减少,但也有缺点,因为图像在绘制到帧缓存时必须解压缩。 与绘制未压缩的图像相比,这种解压缩在许多情况下需要CPU做更多的工作。 结果可能是性能下降。
这意味着必须将闪存减少带来的优势与CPU使用率增加带来的劣势进行比较。
Be aware that the graphics accelerators DMA2D and GPU2D (ChromART and NeoChrom GPU) present in many STM32 micro controllers cannot draw a compressed image directly. Compressed images are always drawn using software rendering.
许多应用中,不建议压缩所有图像,而是只压缩那些性能不受影响且与减少闪存相关的图像。
L8压缩
如上所述,TouchGFX 4.22支持L8图像压缩。 回想一下,L8位图格式仅适用于高达256色的图像。 每个像素只是一个8位数字,表示与图像一起存储的颜色表中的一种颜色。 L8压缩仅压缩像素数。 颜色表保持不变。
以下图为例。 其在计量应用中用作背景。
图像为184 x 184像素。 因此,像素数据的大小为184×184=33,856字节。
如果我们压缩图像,像素数据将减少到5,735字节。 包括颜色表在内的图像数据总尺寸小于原始图像的20%。 因此,压缩可以让我们在同一大小的闪存空间中拥有5个不同的背景,或者将闪存需求减少28,121字节。
压缩的L8图像像普通的未压缩位图一样使用。 例如,您可以使用图像控件显示图像,而无需在TouchGFX Designer或代码中对项目进行任何修改。 从而轻松地使用压缩图像。
也有一些限制。 压缩图像不能与缩放或旋转图像的控件或画布控件一起使用。 参见以下列表。
Caution
三种算法
TouchGFX采用三种不同的压缩算法。 图像转换器选择提供最佳压缩的算法,除非用户在配置中强制使用特定算法。 算法包括:
- L4,对每个像素进行4比特编码。 仅适用于最多16种颜色的图像。
- RLE,像素的游程编码。 仅适用于最多64种颜色的图像。
- LZW9,基于词典的编码。 适用于所有L8图像。
RLE算法的解压缩速度比LZW9快得多,因此如果LZW9仅压缩图像,转换器将选择RLE稍微好一点。
使用压缩图像
压缩图像和普通图像用法相同。 您可以在TouchGFX 设计器中将控件配置为使用位图,也可以在代码中分配位图。
唯一需要的配置是将“压缩”值设置为“自动”。 然后,图像转换器将自动选择最合适的压缩,或者如果图像不可压缩则不选择。
现在,我们可以正常选择控件的图像。 与未压缩的图像相比,没有什么区别。
使用代码中的图像也没有区别。 通常用压缩位图的BitmapID来进行引用:
image1.setXY(148, 148);
image1.setBitmap(touchgfx::Bitmap(BITMAP_GAUGE_BACKGROUND_ID));
在此阅读有关压缩L8图像的更多信息
压缩等级
图像转换器选择的压缩算法会写入生成的文件中。 在这里我们还可以找到压缩等级。
我们在上文使用的图像生成到文件generated/images/src/image_gauge_background.cpp
中。 此文件的标题为:
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 level. Here we see that the Image Converter has selected the LZW9 algorithm. 第5行的末尾显示,我们现有5735字节的像素数据,而原来是33856字节。 Resulting in a compression to 16.9% (the smaller compression level the better). Note! The compression doesn't count the color table.
将图像解压缩到位图缓存
大多数情况下,绘制压缩图像的性能比绘制未压缩图像差。 此外,如引言中所述,STM32微控制器(DMA2D和GPU2D)中的图形加速器无法绘制压缩图像。 因此,压缩图像始终由软件绘制,从而导致性能降低和cpu负载增加。
出于这些原因,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));
bool r = Bitmap::decompress(BITMAP_GAUGE_BACKGROUND_ID, lzwBuffer);
image1.setXY(148, 148);
image1.setBitmap(touchgfx::Bitmap(BITMAP_GAUGE_BACKGROUND_ID));
}
位图缓存必须足够大才能容纳未压缩的图像。 我们的图像是184 x 184像素加包含207 ARGB888颜色的颜色表。 因此,总大小为34.688字节。
在LZW9压缩图像的解压缩期,解压缩器使用2048字节的缓冲区(用于构建字典)。 解压缩后不再需要缓冲区,可以重新用于其他目的。 RLE和L4压缩图像的解压缩不需要缓冲区。
当不再使用解压缩图像时,可以使用Bitmap::cacheRemoveBitmap
将其从位图缓存中移除。
限制
压缩图像不能与缩放或旋转图像的控件或填充区域的控件一起使用。 此类限制出于性能原因而制定。 TouchGFX 设计器不允许您选择压缩图像。
如果你想在这些控件中使用一个特定的L8图像,我们建议不要对图像进行压缩。 或者,您可以在运行时解压缩图像。
不支持压缩图像的控件有:
- TextureMapper
- 可缩放图像
- 指针和弧形仪表
- 用于填充图形下方区域的静态和动态图表
- 指针模拟时钟
- 圆、线和形状
- 圆形和线形进度条