이미지 압축
TouchGFX는 버전 4.22부터 이미지 압축 기능을 지원합니다. 4.22 버전부터 4.23 버전까지는 L8 이미지 압축으로만 지원됩니다. 4.24 버전부터는 RGB565, RGB888, ARGB8888 이미지 형식의 압축이 지원됩니다.
이미지 압축은 이미지에 대한 저장 공간 요구 사항을 줄여주는 프로세스입니다. 프로젝트에서 이미지 크기가 줄면 더 작은 플래시를 사용해서 비용을 절감할 수 있습니다. 또한, 프로젝트에서 더 많은 이미지를 사용할 수 있기 때문에 보다 풍부한 UI를 구현하는 것이 가능합니다.
이미지 압축은 일반적으로 무손실 압축과 손실 압축 두 가지 방식이 있습니다. 손실 압축은 이미지의 사소한 세부 사항을 제거해서 압축을 합니다. 크기는 최대한 줄일 수 있지만, 원본 이미지를 정확하게 재현할 수 없는 경우가 많습니다. 무손실 압축은 항상 원본 이미지를 그대로 재현합니다. 또한, 무손실 압축은 일반적으로 이미지의 크기를 줄여줍니다.
그래픽의 경우에 UI 요소를 디자인한 대로 정확히 드로잉해야 하는 경우가 많습니다. 이러한 이유로 TouchGFX는 무손실 압축만 지원하고 있습니다.
이미지 압축은 크기를 줄일 수 있다는 장점이 있지만, 이미지를 프레임 버퍼에 그릴 때 압축을 해제해야 한다는 단점도 있습니다. 압축되지 않은 이미지를 그릴 때와 비교해 이러한 압축 해제를 위해서는 많은 경우에 CPU에서 더 많은 작업이 필요합니다. 그 결과, 성능 저하가 발생할 수 있습니다.
따라서 플래시 공간 감소로 얻는 이점과 CPU 사용량 증가로 인한 단점을 비교해야 합니다.
많은 STM32 마이크로컨트롤러에 존재하는 DMA2D 및 GPU2D(ChromART 및 NeoChrom GPU) 그래픽 가속기는 압축된 이미지를 직접 그릴 수 없다는 점에 유의하십시오. 압축된 이미지는 소프트웨어 및 하드웨어 렌더링을 혼합하여 그려집니다. 즉, 압축된 데이터는 소프트웨어에 의해 청크로 압축 해제되고 해당하는 경우 이러한 청크는 DMA2D에 위임됩니다.
많은 애플리케이션에서 모든 이미지를 압축하는 것이 아니라, 성능이 손상되지 않고 플래시 공간 감소가 가능한 경우에만 이미지를 압축하도록 권장하고 있습니다. 적은 저장 공간으로 성능을 향상할 수 있는 방법인 비트맵 캐시로 압축 해제하는 방법에 관한 아래 섹션도 참조하십시오.
L8 압축
위에서 언급했듯이 TouchGFX 4.22는 L8 이미지 압축을 지원합니다. L8 비트맵 형식은 최대 256가지 색상이 지원되는 이미지에만 적합합니다. 각 픽셀은 이미지와 함께 저장된 컬러 테이블의 색상을 나타내는 8비트 숫자일 뿐입니다. L8 압축은 픽셀 수만 압축하는 것입니다. 컬러 테이블은 그대로 둡니다.
아래 이미지를 예로 들어보겠습니다. 이미지가 미터링 애플리케이션에서 배경으로 사용되는 경우입니다.
이미지는 184 x 184 픽셀입니다. 픽셀 데이터의 크기는 184 x 184 = 33,856바이트입니다.
이미지를 압축하면 픽셀 데이터가 5,735바이트로 줄어듭니다. 색상표를 포함하여 압축된 이미지 데이터의 전체 크기는 원본 이미지의 20% 미만입니다. 따라서 압축을 통해 동일한 플래시 공간에 5개의 서로 다른 배경을 넣거나 플래시 요구 사항을 28,232바이트까지 줄일 수 있습니다.
압축된 L8 이미지는 일반적인 비압축 비트맵처럼 사용됩니다. 예를 들어 TouchGFX Designer 또는 코드에서 프로젝트를 수정하지 않고도 이미지 위젯을 사용해 이미지를 표시할 수 있습니다. 이렇게 하면 압축된 L8 이미지를 매우 쉽게 사용할 수 있습니다.
3가지 알고리즘 #{three-algorithms}
TouchGFX는 L8 형식에 대해 3가지 압축 알고리즘을 사용합니다. 이미지 변환 프로그램은 사용자가 구성에서 특정 알고리즘을 지정하지 않는 한 최상의 압축을 제공하는 알고리즘을 선택합니다. 알고리즘은 다음과 같습니다.
- L4는 각 픽셀을 4비트로 인코딩하고, 최대 16가지 색상이 지원되는 이미지에만 적용할 수 있습니다.
- RLE는 픽셀의 실행 길이를 인코딩하고, 최대 64가지 색상이 지원되는 이미지에만 적용할 수 있습니다.
- LZW9은 딕셔너리를 기반으로 인코딩을 수행하고, 모든 L8 이미지에 적용할 수 있습니다.
RLE 알고리즘은 LZW9보다 압축 해제 속도가 훨씬 빠르다는 점에서 이미지 변환 프로그램은 LZW9의 이미지 압축 성능이 약간 더 나은 경우에는 RLE를 선택합니다.
RGB 압축
앞에서 언급한 바와 같이 TouchGFX 4.24에서는 RGB565, RGB888, ARGB8888 이미지 형식에 대한 이미지 압축 지원이 도입되었습니다. 256개 이상의 고유 색상을 포함하는 이미지는 컴팩트한 L8 이미지 형식으로 저장할 수 없으며, 앞서 언급한 형식 중 하나로 저장해야 합니다. RGB565, RGB888 또는 ARGB8888 이미지 압축은 16, 24 또는 32비트 픽셀을 직접 압축하는 방식입니다.
아래 이미지를 예로 들어보겠습니다. 아래 이미지는 위의 예제보다 배경이 더 복잡하고 풍부하며 256개 이상의 고유 색상을 포함하고 있습니다. 따라서 L8로 저장할 수 없으며 (모서리)에 투명 픽셀이 있으므로 ARGB8888 형식으로 저장해야 합니다.
이미지는 240 x 240픽셀입니다. 따라서 픽셀 데이터의 크기는 ARGB8888 이미지 형식으로 각 픽셀을 저장하는 데 4 바이트를 사용하므로 240 x 240 x 4 = 230.400바이트입니다.
이미지를 압축하면 크기가 32,347바이트로 줄어듭니다. 압축된 이미지의 크기는 원본 이미지 크기의 14%에 불과할 정도로 상당히 작습니다. 압축을 사용하면 동일한 플래시 공간에 여러 개의 복잡한 배경을 저장하거나 플래시 요구 사항을 크게 줄일 수 있습니다. 또한 한정된 용량의 플래시 장치에서도 L8 형식을 사용할 때보다 더 복잡하고 풍부한 그래픽을 채택할 수 있습니다.
압축된 RGB 이미지는 일반적인 비압축 비트맵처럼 사용될 수 있습니다. 예를 들어 TouchGFX Designer 또는 코드에서 프로젝트를 수정하지 않고도 이미지 위젯을 사용해 이미지를 표시할 수 있습니다. 이렇게 하면 압축된 RGB 이미지를 매우 쉽게 사용할 수 있습니다.
Caution
2가지 알고리즘
TouchGFX는 약간 다른 2가지의 압축 알고리즘을 사용하며, 이러한 알고리즘은 압축될 이미지 형식에 따라 자동으로 선택됩니다. 알고리즘은 다음과 같습니다.
- QOI는 Quite OK 이미지 형식 압축 알고리즘의 변형을 사용하여 RGB888 및 ARGB8888 픽셀을 인코딩합니다.
- QOI565는 16비트 픽셀 값에 맞게 조정된 QOI의 변형을 사용하여 RGB565 픽셀을 인코딩합니다.
RGB 압축 알고리즘의 두 변형은 모두 압축된 RGB 이미지를 렌더링할 때 런타임 성능 저하를 제한하기 위해 빠른 압축 해제 속도에 최적화되어 있습니다.
압축 이미지 사용하기
이미지 압축 기능 활성화하기
이미지 압축을 사용하려면 타겟 애플리케이션에 추가 코드가 있어야 합니다. 이러한 높은 공간 요구 사항을 피하기 위해 일부 플랫폼에서는 압축 코드가 선택 사항입니다. 프로젝트에서 이 기능을 활성화해야 할 수도 있습니다.
TouchGFX Designer 왼쪽에서 "Config"를 클릭한 다음 "Framework Features"를 클릭합니다.
이미지 압축 기능이 하단에 표시됩니다. 필요한 특정 기능 세트를 활성화할 수 있습니다.
대상에 따라 프레임워크 기능에 대한 옵션이 다르며, 아래와 같이 타겟에 선택적 기능이 없는 경우도 있습니다.
이 경우 모든 기능이 항상 활성화됩니다.
Caution
L8 압축
압축된 이미지는 일반 이미지와 똑같이 사용됩니다. TouchGFX Designer에서 비트맵을 사용하도록 위젯을 구성하거나, 코드에서 비트맵을 할당할 수 있습니다.
Compression 값을 "Auto"로 설정하기만 하면 됩니다. 이미지 변환 프로그램은 최적의 압축을 자동으로 선택하거나, 이미지를 압축할 수 없는 경우에는 어떤 것도 선택하지 않습니다.
이제는 평소처럼 위젯에 대한 이미지를 선택할 수 있습니다. 압축되지 않은 이미지와 비교해도 이 부분에서는 차이가 없습니다.
코드에서 이미지를 사용할 때도 별다른 차이가 없습니다. 압축된 비트맵은 평소와 같이 BitmapID를 사용하여 참조됩니다.
image1.setXY(148, 148);
image1.setBitmap(touchgfx::Bitmap(BITMAP_GAUGE_BACKGROUND_ID));
압축된 L8 이미지에 대한 자세한 내용은 여기에서 확인하십시오.
RGB 압축
TouchGFX Designer에서 RGB565, RGB888 또는 ARGB8888 이미지를 압축할 때 L8 압축과 동일한 프로세스를 따르게 됩니다.
"Yes"를 선택하면 이미지 변환 프로그램이 이미지 형식과 일치하는 알고리즘으로 이미지를 압축합니다.
L8 압축과 마찬가지로, 평소와 같이 위젯의 이미지를 선택하고 코드에서 비트맵을 참조하면 됩니다.
압축 수준
이미지 변환 프로그램이 선택한 압축 알고리즘이 생성된 파일에 기록됩니다. 여기에서 압축 수준을 확인할 수도 있습니다.
위의 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,
....
첫 번째 줄의 주석 끝에 압축 알고리즘이 나와 있습니다. 여기에서 Image Converter가 LZW9 알고리즘을 선택했음을 확인할 수 있습니다. 라인 5의 끝을 보면 원본이 33856 바이트인 것과 달리 현재 픽셀 데이터는 5735 바이트라는 것을 알 수 있습니다. 압축 결과는 16.9%입니다(압축 수준은 작을수록 좋음). 주의! 압축률은 색상표를 포함하지 않습니다.
압축 실패
이미지를 압축할 때 이미지 변환 프로그램에 경고나 오류가 표시되는 경우가 있습니다. 이는 이미지가 선택한 알고리즘과 호환되지 않거나 압축된 이미지의 크기가 원본 이미지의 90% 미만이 아닐 때 발생할 수 있습니다. 하지만 이 현상은 매우 드물게만 발생합니다. 5 x 5의 작은 이미지에 25개의 서로 다른 뚜렷한 색상이 사용되는 경우를 예로 들 수 있습니다. 이미지에 반복이나 중복되는 부분이 없기 때문에 압축으로 인해 데이터가 줄어들 가능성이 없습니다.
L8 이미지
L8 이미지의 경우, 지정된 이미지에 일치하지 않는 특정 알고리즘을 선택하면 이러한 현상이 발생할 수 있습니다. 예를 들어, 이미지에 17개 이상의 색상이 포함되어 있고 L4 압축을 선택한 경우 선택한 알고리즘을 사용하여 이미지를 압축할 수 없습니다. 이미지 변환 프로그램은 코드를 생성할 때 오류 메시지를 출력하고 TouchGFX Designer에는 다음과 같은 오류 메시지가 표시됩니다.
이 문제에 대한 해결책은 다른 알고리즘을 사용하는 것입니다. 선호되는 방법은 L8 이미지에 대해 "Auto"를 선택하는 것입니다. 그러면 이미지 변환 프로그램이 모든 알고리즘을 시도하고 적용 가능한 알고리즘 중 가장 적합한 알고리즘을 선택합니다.
드물긴 하지만, 이미지가 원본 크기의 90% 미만으로 압축되지 않는 경우가 있습니다. 이 경우 이미지 변환 프로그램은 이미지를 압축하지 않고 아래와 같은 경고 텍스트를 표시합니다.
압축이 되지 않는 이유는 플래시 크기를 줄이는 것이 렌더링 성능을 낮추는 것보다 크게 유리하지 않기 때문입니다. "Auto"를 사용하지 않고 알고리즘("L4", "RLE" 또는 "LZW") 중 하나를 선택하여 강제로 압축할 수 있습니다.
경고 메시지는 정보 제공만을 위한 것입니다. 코드 생성은 계속되며 프로젝트는 예상대로 작동합니다.
RGB 이미지
RGB 이미지 형식의 경우 압축 알고리즘이 하나뿐이므로 "Auto"를 선택할 수 없습니다. "Yes"를 선택했는데 이미지를 원본 크기의 90% 미만으로 압축할 수 없는 경우 이미지 변환 프로그램은 다음과 같은 오류를 생성합니다.
이 문제를 해결하는 방법은 이미지 압축에 대해 "None"을 선택하는 것입니다.
이미지를 비트맵 캐시로 압축 해제하기
대부분의 경우에 압축된 이미지를 그릴 때가 압축되지 않은 이미지를 그릴 때보다 성능이 떨어집니다. 또한 서론 부분에서 언급했듯이, 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)); // 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
}
이번 예제에서는 위의 L8 압축 예제에 나온 184 x 184 이미지를 비트맵 캐시로 압축 해제하려고 합니다. 비트맵 캐시는 압축되지 않은 이미지를 저장할 수 있을 만큼 충분히 커야 합니다. 이 이미지에는 184 x 184픽셀과 207개의 ARGB8888 색상이 포함된 색상표가 있습니다. 따라서 전체 크기는 34,688바이트입니다.
이 예제에서는 LZW9 알고리즘을 사용합니다. 2048 바이트 버퍼는 LZW9 압축 이미지를 압축 해제하는 동안 압축 해제기에 의해 사용됩니다(딕셔너리 빌드를 위해). 이 버퍼는 압축 해제 후에는 필요하지 않으며 다른 용도로 재사용할 수 있습니다. L4, RLE, QOI 또는 QOI565 압축 이미지의 압축 해제에는 버퍼가 필요하지 않습니다.
압축을 해제한 이미지를 더 이상 사용하지 않을 때는 Bitmap::cacheRemoveBitmap
메소드를 사용해 비트맵 캐시에서 이를 제거할 수 있습니다.
프로그램 크기 제한
비트맵 캐시로 압축 해제를 하는 경우 프로그램의 크기를 제한할 수 있는 몇 가지 옵션이 있습니다. 위에서 언급했듯이 이미지 압축에는 L8과 RGB라는 두 가지 유형이 있습니다. Bitmap::decompress
를 사용하는 경우 프로그램에 L8 및 RGB 이미지를 모두 압축 해제할 수 있는 코드가 포함됩니다. RGB 이미지 압축만 사용하는 경우 RGB 이미지를 비트맵 캐시로 압축 해제하는 전용 메소드인 Bitmap::decompressRGB
를 사용할 수 있으며, 이렇게 하면 RGB 이미지를 압축 해제하는 데 필요한 코드만 프로그램에 포함됩니다. L8 압축만 사용하는 경우에도 마찬가지이며, 여기에서는 이 메소드를 Bitmap::decompressL8
이라고 부릅니다. 아래 예제를 참조하십시오.
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);
...
}
제한 사항
압축된 이미지로 작업할 때 몇 가지 제한 사항이 있습니다. 압축된 이미지는 이미지의 크기를 조정하거나 이미지를 회전시키는 Widget, 영역을 채우는 Widget 또는 Canvas widget들과 함께 사용할 수 없습니다.
Caution
이러한 제한을 두는 것은 성능상의 이유 때문입니다. TouchGFX Designer에서는 압축된 이미지를 선택하도록 허용하지 않습니다.
특정 이미지를 이러한 Widget들과 함께 사용하려면 이미지 압축을 활성화하지 않는 것이 좋습니다. 대안적으로, 런타임 시 이미지 압축을 해제할 수 있습니다.
압축 이미지를 지원하지 않는 위젯은 다음과 같습니다.
- TextureMapper
- ScalableImage
- 바늘 및 아크용 Gauge
- 그래프 아래 영역을 채우기 위한 StaticGraph 및 DynamicGraph
- 손목용 AnalogClock
- 원, 라인 및 쉐이프
- CircleProgress 및 LineProgress