跳轉到主要內容

圖像壓縮

從4.22版本開始,TouchGFX支援使用圖像壓縮。 4.22版僅限支援L8圖像壓縮。

圖像壓縮是縮減圖像儲存需求的程序。 在專案中縮減圖像尺寸,如果能夠因此使用更小的Flash,就能降低成本。 縮減尺寸也能讓專案使用更多圖像,產生更豐富的UI。

圖像壓縮一般有兩種選擇:無損或有損。 有損圖像壓縮的運作原理是移除圖像的微小細節。 這通常可達到最大的縮減率,但無法完全確切重現原始圖像。 無損壓縮則一定可以重現原始圖像,沒有任何差異。 無損壓縮一般來說尺寸縮減率較低。

對圖形而言,通常會要求繪製的UI元素與當初設計時完全一樣。 因此TouchGFX僅支援無損壓縮。

圖像壓縮的優點在於縮小尺寸,但缺點則是圖像繪製到影像緩衝區時必須進行解壓縮。 相較於繪製未壓縮圖像,解壓縮在許多情況下會增加CPU工作量, 可能結果就是降低效能。

這代表我們必須將減少Flash所獲得的優點,與增加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.

許多應用程式都不建議壓縮所有圖像,而是僅壓縮效能不會受損且減少Flash至關重要的圖像。

L8壓縮

如前所述,TouchGFX 4.22支援L8圖像壓縮。 回想一下,L8點陣圖格式僅適合用於最多256種色彩的圖像。 每個像素都只是8位元數字,在與圖像一同儲存的色表中用於代表色彩。 L8壓縮只壓縮了像素數, 並沒有動到色表。

請參考以下圖像作為範例。 該圖像是計量應用程式中使用的背景。

L8-ARGB8888

圖像為184 x 184像素, 因此像素資料大小為184 x 184 = 33,856位元組。

如果我們壓縮圖像,像素資料會縮減為5,735位元組。 圖像資料的總大小(包含色表)比原始圖像減少20%。 因此壓縮可讓我們在相同的Flash空間擁有5種不同背景,或是可減少28,121位元組的Flash需求。

壓縮L8圖像使用時就像是一般的未壓縮點陣圖。 例如您可使用圖像小工具顯示圖像,無需在TouchGFX Designer或程式碼中對專案進行任何修改。 這樣使用壓縮圖像就非常方便。

不過也有一些限制。 壓縮圖像無法搭配使用會縮放或旋轉圖像的小工具,也無法搭配使用Canvas小工具。 請參閱以下清單。

Caution
壓縮圖像無法搭配使用所有小工具。 Designer會顯示警告圖示。

壓縮圖像搭配使用不相容的小工具。

3種演算法

TouchGFX使用3種不同的壓縮演算法。 圖像轉換器會選擇提供最佳壓縮的演算法,除非使用者強制在設定中使用特定演算法。 使用的演算法如下:

  • L4:以4位元為單位編碼各個像素。 僅適用於最多16種色彩的圖像。
  • RLE:對像素進行長度編碼。 僅適用於最多64種色彩的圖像。
  • LZW9:採用字典型編碼。 適用於所有L8圖像。

RLE演算法的解壓縮速度比LZW9快很多,因此如果LZW9壓縮圖像的效果只稍微好一些,圖像轉換器就會選擇使用RLE。

使用壓縮圖像

壓縮圖像的使用方式就和一般圖像一樣。 您可在TouchGFX Designer設定小工具使用點陣圖,或是以程式碼指派點陣圖。

設定壓縮用於L8-ARGB8888圖像

唯一需要進行的設定,就是將Compression(壓縮)值設定為「Auto」(自動)。 接著圖像轉換器將自動選擇最適合的壓縮方法,如果圖像無法壓縮則會選擇不壓縮。

為小工具選擇壓縮圖像

現在我們可以和平常一樣為小工具選擇圖像。 其中與未壓縮圖像之間並沒有不同之處。

在程式碼之中使用圖像也沒有差別。 壓縮點陣圖和平常一樣是以其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. Compression [output/input 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 ARGB8888色彩的色表, 因此總大小為34,688位元組。

解壓縮器在解壓縮LZW9壓縮圖像時(用於建構字典),會使用2048位元組的緩衝區。 解壓縮之後就不需要緩衝區,可重新用於其他用途。 解壓縮RLE及L4壓縮圖像不需要使用緩衝區。

解壓縮圖像不再需要使用時,可利用Bitmap::cacheRemoveBitmap方法從點陣圖快取中移除。

限制

壓縮圖像無法搭配使用會縮放或旋轉圖像的小工具,也無法搭配使用填充區域的小工具。 前述限制是考量效能因素所訂定。 TouchGFX Designer不會讓您選擇壓縮圖像。

如果您要使用特定L8圖像搭配前述小工具,我們建議不要啟用圖像壓縮。 或者您可以在執行階段解壓縮圖像。

不支援壓縮圖像的小工具如下:

  • TextureMapper
  • ScalableImage
  • 用於指標及弧線的Gauge
  • 用於填充繪圖下方區域的Static-及DynamicGraph
  • 用於時鐘指針的AnalogClock
  • Circle、Line及Shape
  • Circle-及LineProgress