画像の圧縮
TouchGFXバージョン4.22から、画像の圧縮がサポートされています。 4.22でのサポートは、L8画像の圧縮に限定されています。
画像圧縮は、画像のストレージ要件を低減するプロセスです。 より小さなFlashメモリの使用で済むならば、プロジェクトの画像サイズの削減はコスト削減につながります。 また、圧縮することでプロジェクトでより多くの画像を使用できるので、その結果、UIが豊かになる可能性もあります。
画像圧縮には、通常、可逆圧縮と非可逆圧縮の2種類があります。 非可逆画像圧縮では、画像の細部が削除されます。 これは多くの場合、最大の削減になりますが、元の画像を正確に再現することはできません。 可逆圧縮は、常に、元の画像を全く同じに再現します。 可逆圧縮は、通常、サイズの削減は小さくなります。
グラフィックスの場合、UI要素を設計に従って正確に描画する必要があることがよくあります。 このため、TouchGFXでは、可逆圧縮のみをサポートしています。
画像圧縮のメリットはサイズの削減ですが、デメリットもあります。画像がフレームバッファに描画される場合に解凍する必要があるからです。 この解凍処理には、多くの場合、非圧縮画像の描画と比べて多くのCPU処理が必要になります。 結果として性能が低下する可能性があります。
つまり、Flashメモリの使用量削減から得られるメリットを、CPUの負荷の増加によるデメリットと比較する必要があります。
多くのSTM32マイクロコントローラに搭載されているグラフィック・アクセラレータであるDMA2DとGPU2Dは、圧縮画像を直接描画できないことに注意してください。 圧縮画像は、常にソフトウェア・レンダリングを使用して描画されます。
多くのアプリケーションでは、すべての画像を圧縮することは推奨されていません。性能に悪影響を及ぼさず、Flashメモリの使用量削減に直結する画像のみを圧縮してください。
L8圧縮
前述のとおり、TouchGFX 4.22はL8画像の圧縮をサポートしています。 L8ビットマップ・フォーマットは最大256色の画像にのみ適していることを思い出してください。 各ピクセルは8ビットの数値で、画像とともに格納されているカラー・テーブルの色を参照します。 L8の圧縮はピクセルを表す数値を圧縮するだけです。 カラー・テーブルは圧縮されません。
たとえば、次の画像を考えてみましょう。 これは計量アプリケーションのバックグラウンドとして使用されます。
この画像は184 x 184ピクセルです。 したがって、ピクセル・データのサイズは184 x 184 = 33,856バイトになります。
画像を圧縮すると、ピクセル・データは5,735バイトまで削減されます。 カラー・テーブルを含めた画像データの全体サイズは、元の画像の20%未満になります。 したがって、圧縮により、同一のFlashメモリ領域に5つの異なるバックグラウンドを格納したり、Flashメモリの使用量を28,121バイト削減したりできます。
圧縮されたL8画像は、通常の非圧縮ビットマップのように使用されます。 たとえば、TouchGFX Designerやコードでプロジェクトに変更を加えることなく、Imageウィジェットを使用して画像を表示できます。 これにより、圧縮画像の使用が大変容易になっています。
少々制限があります。 圧縮画像は、画像を拡大したり回転するウィジェットやCanvasウィジェットでは使用できません。 以下のリストを参照してください。
Caution
3つのアルゴリズム
TouchGFXは3つの圧縮アルゴリズムを使用します。 ユーザが設定でアルゴリズムを指定しないかぎり、画像コンバータにより、最適な圧縮を提供するアルゴリズムが選択されます。 アルゴリズムは次のとおりです。
- L4は、各ピクセルを4 bitにエンコードします。 最大16色の画像にのみ対応しています。
- RLEは、ピクセルのランレングス符号化を行います。 最大64色の画像にのみ対応しています。
- LZW9は、ディクショナリ・ベースのエンコードを行います。 すべてのL8画像に対応しています。
RLEアルゴリズムの圧縮解除速度はLZW9よりもはるかに速いので、LZW9による画像圧縮がほんのわずかしか優れていない場合には、画像コンバータによりRLEが選択されます。
圧縮画像の使用
圧縮画像は、通常の画像のように使用されます。 TouchGFX Designerでビットマップを使用するようにウィジェットを設定するか、コードでビットマップを割り当てます。
唯一必要な設定は、[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,
....
先頭行のコメントの最後に、圧縮レベルが示されます。 ここでは、画像コンバータにより、LZW9アルゴリズムが選択されたことがわかります。 5行目の最後には、現在のピクセル・データが5735バイトで、元のデータが33856バイトであることが示されています。 結果として、16.9%に圧縮されました(カラー・テーブルはカウントされていません)。
ビットマップ・キャッシュへの画像の解凍
圧縮画像の描画は、ほとんどの場合、非圧縮画像の描画よりも性能が低下します。 そのうえ、冒頭で述べたように、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ピクセルで、カラー・テーブルではARGB8888の色を207個保持しています。 したがって、全体サイズは34,688バイトになります。
LZW9圧縮画像の解凍時には、デコンプレッサにより、2,048バイトのバッファが使用されます(ディクショナリ作成のため)。 バッファは、解凍後には不要になるため、別の目的で再利用できます。 バッファはRLEおよびL4圧縮画像の解凍には必要ありません。
解凍された画像をこれ以上使用しない場合は、Bitmap::cacheRemoveBitmap
メソッドを使用して、ビットマップ・キャッシュから削除できます。
制限
圧縮画像は、画像を拡大したり回転するウィジェットや領域を塗りつぶすウィジェットでは使用できません。 こうした制限は、性能上の理由で設けられています。 TouchGFX Designerでは、圧縮画像を選択できません。
特定のL8画像をこれらのウィジェットで使用したい場合は、画像の圧縮を有効にしないことをお勧めします。 または、画像を実行時に解凍できます。
圧縮画像をサポートしないウィジェットは、次のとおりです。
- ScalableImage
- 針と円弧を描画するGauge
- グラフの下の領域を塗りつぶすStaticGraphとDynamicGraph
- AnalogClockでの針の描画
- Circle、LineおよびShape
- CircleProgressおよびLineProgress