L8 이미지 형식을 통한 메모리 사용량 절감
L8 형식의 이미지는 다른 형식, 이를테면 ARGB8888에 비해 플래시 저장 공간을 적게 차지하며 그리기 작업 속도가 더 빠릅니다.
L8 형식의 이미지는 색상 팔레트와 픽셀 배열로 구성됩니다. 색상 팔레트에서는 최대 256가지의 색상이 16비트 형식 RGB565, 24비트 형식 RGB888, 또는 32비트 형식 ARGB8888로 지정됩니다. 픽셀 배열은 각 픽셀마다 1바이트로 구성됩니다. 이 바이트는 색상 팔레트(색상 목록)에 대한 인덱스로서 픽셀 색상을 나타냅니다. TouchGFX 프레임워크는 픽셀을 하나씩 읽고 팔레트에서 해당 색상을 찾아 이를 프레임버퍼에 작성함으로써 L8 이미지에 대한 그리기 작업을 수행합니다. 이는 자동으로 수행되며, 하드웨어에서 지원할 경우에는 STM32 Chrom-ART 하드웨어 가속기를 사용해 속도를 높일 수 있습니다.
8bpp(픽셀당 8비트)란, L8 이미지 1개가 256가지 색상을 사용할 수 있다는 것을 의미합니다. 또 다른 L8 이미지도 256가지의 다른 색상을 사용할 수 있는데, 이는 두 이미지가 각각 자체 팔레트를 가지고 있기 때문입니다.
픽셀은 각각 1바이트(8비트)입니다. 따라서 픽셀의 크기는 가로 x 세로 바이트로 나타냅니다. 팔레트 색상에는 16비트, 24비트 또는 32비트 색상이 있습니다. 따라서 각 색상마다 2, 3 또는 4바이트를 차지한다고 정의합니다.
솔리드 이미지는 L8_RGB888에 저장해야 합니다. 그 밖에 이미지가 투명하다면 반드시 32비트 형식(ARGB8888)을 사용해야 합니다.
형식 | 프레임버퍼 형식 | 투명한 픽셀 지원 여부 | DMA2D에서 지원 |
---|---|---|---|
L8_RGB565 | 16비트 RGB565 | 아니요 | 아니요 |
L8_RGB888 | 24비트 RGB888 | 아니요 | 예 |
L8_ARGB8888 | 둘 다 | 예 | 예 |
RGB565 팔레트가 포함된 L8 형식은 DMA2D에서 지원되지 않습니다. 이는 L8 형식으로 이미지 그리기를 하면 하드웨어가 가속화되지 않는다는 의미입니다. 따라서 DMA2D가 없는 플랫폼(예: STM32G0 또는 STM32F410)에 있는 경우가 아니라면 이 형식을 사용해서는 안 됩니다.
직렬 플래시(비메모리 매핑)를 사용해 이미지와 16비트 프레임버퍼(RGB565 형식)를 저장하는 경우에는 L8_RGB565 형식을 사용해야 합니다. 왜냐하면 이러한 색상 형식이 프레임버퍼 형식과 일치하고 프레임버퍼에 복사하는 것이 더 빠르기 때문입니다.
아래 표에는 선호하는 L8 형식이 나와 있습니다.
프레임버퍼 형식 | 플랫폼에 DMA2D가 포함 | DMA2D가 없는 플랫폼 |
---|---|---|
RGB565 | L8_RGB888 | L8_RGB565 |
RGB888 | L8_RGB888 | L8_RGB888 |
ARGB8888 | L8_RGB888 | L8_RGB888 |
투명한 이미지는 항상 L8_ARGB8888에 있어야 합니다.
Further reading
L8 이미지
다음은 일반적인 로고 이미지입니다. 이 이미지는 16가지 색상만 사용한 것입니다.
이 이미지의 플래시 크기는 표준 24비트 형식(RGB888)의 원본 이미지보다 훨씬 작습니다. 아래 표는 세 가지 팔레트 형식과 L8이 아닌 다른 형식일 때 이미지의 플래시 크기를 나타낸 것입니다.
형식 | 픽셀 크기(바이트) | 팔레트 크기(바이트) | 전체 크기(바이트) | 감소율(%) |
---|---|---|---|---|
RGB888 | 120,000 | 0 | 120,000 | - |
L8_RGB565 | 40,000 | 32 | 40,032 | 66.6 |
L8_RGB888 | 40,000 | 48 | 40,048 | 66.6 |
L8_ARGB8888 | 40,000 | 64 | 40,064 | 66.6 |
위 표에서 크기 감소율이 매우 높을 뿐만 아니라 중간 크기의 이미지에서는 팔레트의 크기에 별 차이가 없는 것을 알 수 있습니다.
TouchGFX Designer에서 사용되는 L8 이미지
TouchGFX에서는 L8 이미지 형식을 매우 쉽게 사용할 수 있습니다. Image Converter를 구성해 이미지 형식을 PNG에서 L8로 변환하기만 하면 됩니다. 변환하는 프로세스는 다음과 같습니다.
TouchGFX Designer에서 새 프로젝트를 시작합니다. 다음과 같이 새 프로젝트에서 이미지를 assets/images 폴더로 복사합니다.
이제 TouchGFX Designer로 이동하여 상단 도구 모음에 있는 Images 탭을 클릭하여 이미지를 선택합니다.
창 오른쪽에서 이미지 형식 L8_RGB888을 선택합니다(위 예에서는 24비트 색상을 실행 중입니다).
이제 캔버스에 이미지 위젯을 삽입할 수 있습니다(여기서는 배경에 Box를 삽입했습니다).
UI 코드에서는 아무것도 변경할 필요가 없습니다. Images 탭에서 설정한 구성 때문에 이미지 변환 프로그램이 PNG 파일을 변환하여 L8 형식의 이미지를 생성합니다.
투명한 이미지
위에서 언급한 것처럼 투명한 이미지에도 L8 형식을 사용할 수 있습니다.
위의 이미지는 108가지 색상(대부분 파란색 색조)을 사용하고 있습니다. 이 이미지는 L8_ARGB8888 형식을 사용할 수 있습니다. 그러면 크기가 다음과 같이 크게 줄어듭니다.
형식 | 픽셀 크기(바이트) | 팔레트 크기(바이트) | 전체 크기(바이트) | 감소율(%) |
---|---|---|---|---|
ARGB8888 | 40,800 | 0 | 40,800 | - |
L8_ARGB8888 | 10,200 | 432 | 10,632 | 73.9% |
L8 이미지 압축
L8 이미지의 L8 압축을 선택하면 메모리 소비를 훨씬 더 줄일 수 있습니다. 이미지 변환 프로그램은 3가지 압축 알고리즘(L4, RLE, LZW9)을 지원합니다. TouchGFX Designer에서는 Compression 값을 "Auto"로 설정할 수 있는데, 이렇게 하면 이미지 변환 프로그램이 이미지에 적합한 알고리즘을 선택하거나 특정 알고리즘을 강제로 적용할 수 있습니다. 메모리 사용량을 절감할 수 있다는 이점이 있지만, 경우에 따라 이미지를 그릴 때 프레임 버퍼에 대한 직접 압축이 압축되면서 CPU 부하가 증가하는 단점이 있습니다.
Note
L8 이미지 압축을 위해 TouchGFX Designer의 Default Image Configuration 탭에서 기본값을 설정할 수 있습니다(아래 스크린샷 참조). 여기에서 전체 애플리케이션의 기본 설정을 선택합니다.
Caution
Further reading
지금부터는 앞서 나온 L8 이미지를 사용해 각 알고리즘의 압축 기능과 압축 해제 성능을 시연해보겠습니다.
아래와 같이 압축 옵션이 서로 다른 4개의 화면이 포함된 애플리케이션에서 STM32F429-DISCO를 사용하겠습니다.
- 압축 없음
- L4 압축
- RLE 압축
- LZW9 압축
Note
형식 | 압축 | 픽셀 크기 (바이트) | 팔레트 크기 + 헤더 (바이트) | 전체 크기 (바이트) | 감소율 (%) | 성능 (렌더링 시간(ms)) |
---|---|---|---|---|---|---|
RGB565 | 아니요 | 120,000 | 0 | 120,000 | 0 | - |
L8_RGB565 | 아니요 | 40,000 | 32 + 4 | 40,036 | 66.6 | 2.12 |
L8_RGB565 | L4 | 20,000 | 32 + 4 | 20,036 | 83.3 | 2.34 |
L8_RGB565 | RLE | 3,197 | 32 + 164 | 3,393 | 97.2 | 1.66 |
L8_RGB565 | LZW9 | 4,475 | 32 + 168 | 4.675 | 96.1 | 7.45 |
위의 표에는 이미지를 그릴 때 압축으로 인한 메모리 사용량 감소와 압축 해제 성능이 모두 나와 있습니다. 압축(메모리 사용량 감소) 및 압축 해제(성능) 모두 이미지의 복잡성과 색상 수에 따라 크게 달라집니다.
각 알고리즘마다 적용 범위의 제한이 있는데, L4는 16가지 색상으로 제한되고 RLE는 64가지 색상으로 제한되며 LZW9는 제한 없이 모든 L8 이미지에서 작동합니다. 또한 이미지를 그릴 때 L4와 RLE의 성능이 LZW9보다 더 좋은 것은 사실이지만, 앞서 언급한 것처럼 모든 L8 이미지에 적용하는 것이 불가능합니다. 이미지가 잘리면 모든 알고리즘의 성능이 저하됩니다.
따라서, 일반적으로 L8 이미지 압축을 사용할 때 색상 수(품질 요구 사항), 사용 가능한 플래시 메모리(감소 요구 사항) 및 애플리케이션의 복잡성(애니메이션)을 항상 고려해야 합니다. 예를 들면 64가지 이상의 색상이 포함된 이미지가 있고 LZW9를 사용하지만 성능 저하가 심한 경우에는 이미지의 색상 수를 64가지 미만으로 줄여보고(품질 요구 사항이 허용하는 경우) RLE를 선택할 수 있습니다. 이것이 가능하지 않은 경우에는 압축되지 않은 L8 이미지를 사용하는 것이 더 나을 수 있습니다. 이미지에서 색상 수를 줄이는 방법은 ImageMagick를 참조하십시오.
애플리케이션에서 L8 이미지 압축을 사용하지 않으려면 기능을 비활성화해야 합니다. 아래의 TouchGFX Designer 스크린샷에 그 방법이 나와 있습니다.
위젯의 압축 및 비압축 L8 이미지 예
모든 위젯에서 L8 이미지 압축을 사용할 수 있는 것은 아니지만, 여러 이미지로 구성된 위젯(예: 게이지 및 아날로그 시계)에서는 일부 이미지는 압축하고 다른 이미지는 압축하지 않을 수 있습니다. 아래는 게이지 위젯에서 배경은 압축하고 바늘은 압축하지 않는 방법을 보여주는 예입니다.
이미지를 256가지 미만의 색상으로 변환
다수의 이미지가 256가지 이상의 색상을 사용합니다. 특히 실사 이미지나 그래디언트가 적용된 이미지라면 대부분이 그렇습니다. 이러한 이미지는 색상이 너무 많기 때문에 TouchGFX Designer에서 L8 이미지 형식으로 바로 변환되지 않습니다.
하지만 대체로 특정 이미지에 사용된 색상의 수를 줄이는 것은 가능합니다. 그래픽 아티스트가 256가지 색상으로 이미지를 변환하거나 제공한다면 더할 나위 없겠지만 이미지 조작 도구 역시 이미지 품질을 최대한 유지하면서 이미지를 변환할 수 있습니다.
Paint.NET
가장 쉬운 방법은 Paint.NET을 사용하는 것입니다. 원본 이미지를 열고 Save As를 사용해 이미지를 다른 파일로 저장합니다. Save Configuration 대화 상자에서 픽셀 심도로 8비트를 선택합니다.
이제 프로젝트에서 새 PNG를 사용합니다. 이때 TouchGFX Designer의 Images 탭에서 L8_ARGB8888 형식을 선택해야 합니다. 그림자 처리가 그다지 효과적이지는 않지만, 대체로 가장자리가 투명한 아이콘이 뚜렷하게 보입니다. 경우에 따라서는 "Transparency threshold" 값을 조정하여 결과를 개선할 수도 있습니다.
ImageMagick
때에 따라 L8 이미지의 품질이 좋아지는 변환 도구가 있는데, 바로 ImageMagick(www.imagemagick.org에서 다운로드)입니다. 이 도구는 명령줄에서도 이미지를 변환하기 때문에 스크립트로 사용하기 적합합니다. 예를 들어 clock_bg.png를 최대 256가지 색상을 사용하는 이미지로 변환한다고 가정할 경우 다음과 같이 명령을 사용합니다.
magick convert clock_bg.png -colors 256 clock_bg_l8_256.png
RLE 또는 L4 압축 알고리즘을 활성화한 경우에는 색상의 수를 256가지 미만으로 줄일 수도 있습니다.
magick convert clock_bg.png -colors 64 clock_bg_l8_64.png
ImageMagick 역시 이미지에 사용되는 색상의 수를 표시할 수 있습니다. 이 명령은 다음과 같습니다.
magick identify -format %k Blue_Buttons_Round_Edge_small.png
비교
비교를 위해 다음과 같이 세 가지 이미지(원본, Paint.NET을 사용한 L8, ImageMagick을 사용한 L8)를 준비했습니다.
가운데 이미지는 경계 그림자에서 선명도가 떨어집니다. 두 가지 모두 시계 배경에서 중앙 부분이 양호해 보입니다.
수동 구성
TouchGFX Designer를 사용하지 않고도 이미지 형식과 압축 알고리즘을 선택할 수 있습니다. 설정은 프로젝트 루트에 있는 application.config 파일에 명시되어 있습니다.
application.config
{
"image_configuration": {
images": {
"Blue_Buttons_Round_Edge_small.png": {
"format": "L8_ARGB8888",
"l8_compression": "LZW9"
}
},
"dither_algorithm": "2",
"alpha_dither": "yes",
"layout_rotation": "0",
"opaque_image_format": "RGB888",
"nonopaque_image_format": "ARGB8888",
"section": "ExtFlashSection",
"extra_section": "ExtFlashSection",
"l8_compression": "yes"
}
}
"image_configuration" 아래 "images” 섹션에서 각 이미지의 형식을 지정합니다. 여기서 이미지 형식을 지정하지 않으면 이미지가 기본 형식(opaque_image_format 또는 nonopaque_image_format)으로 생성됩니다.
가능하다면 TouchGFX Designer를 사용해 이미지를 구성하는 것이 좋습니다.