주요 내용으로 건너뛰기

바이너리 폰트

이 섹션에서는 TouchGFX에서 바이너리 폰트를 사용하는 방법을 설명합니다. 첫 번째 섹션에서는 바이너리 폰트 사용 시 이해하는 데 도움이 될 수 있는 TouchGFX의 폰트 및 텍스트 시스템에 대해 자세히 알아봅니다. 두 번째 섹션에서는 바이너리 폰트의 사용법에 대해 알아봅니다.

바이너리 폰트는 폰트 정보를 컴파일하여 애플리케이션(generated/fonts/src의 .cpp 파일)에 연결하는 기존 방식을 대체할 목적으로 사용할 수 있습니다. 바이너리 폰트의 가장 큰 이점은 용량이 더 작은 애플리케이션 이진 파일을 가져와서 사용하는 장치에 다양한 폰트 세트를 유연하게 제공할 수 있다는 점입니다. 예를 들어 중국에서 사용할 장치에는 중국어 폰트로, 그리고 일본에서 사용할 장치에는 일본어 폰트로 채울 수 있습니다. 단, 전체 바이너리 폰트를 RAM(또는 메모리 매핑 플래시)에 로드해야 하기 때문에 폰트 용량이 크면 문제가 될 수 있습니다.

일반적으로 폰트를 애플리케이션에 연결했을 때의 가장 큰 이점은 애플리케이션에 사용되는 텍스트와 타이포그래피가 업데이트되었을 때 항상 자동으로 애플리케이션에 추가된다는 점입니다. 따라서 사용법이 매우 쉽고 안전합니다. 하지만 폰트로 인해 애플리케이션의 크기가 커질 수 있다는 것이 단점입니다.

폰트 및 텍스트 시스템 클래스

TouchGFX는 기본 구성일 때 애플리케이션에서 사용되는 모든 텍스트와 폰트에 .cpp 파일을 생성합니다. 이 파일들은 컴파일된 후, 생성된 UI 및 애플리케이션 코드와 함께 애플리케이션에 연결됩니다.

예를 들어 TextArea가 포함된 UI에 텍스트를 표시할 경우 TypedTextId를 사용해 해당 텍스트를 참조합니다. 이 TypedTextId는 위젯이 텍스트에서 실제 문자를 찾는 데 사용됩니다. 그런 다음 위젯이 touchgfx::Texts 클래스 framework/include/touchgfx/Texts.hpp를 통해 텍스트에 액세스합니다.

텍스트 클래스에는 애플리케이션에서 사용되는 각 언어의 번역 테이블을 가리키는 포인터가 배열된 포인터 배열이 있습니다. 번역 테이블이란 원칙적으로 해당 언어에서 사용되는 모든 문자열을 모아 놓은 것을 말합니다.

텍스트를 특정 언어로 매핑하기

TouchGFX는 이 테이블을 통해 선택한 언어에서 지정된 텍스트를 찾습니다.

TouchGFX Designer에서, 또는 texts.xml 파일에서 직접 텍스트를 변경하고 애플리케이션을 생성할 때마다 테이블이 다시 생성됩니다.

스크린에 텍스트를 그리기 전에 먼저 텍스트에 어떤 폰트를 사용하는지 알아야 합니다. 이러한 텍스트와 폰트 간 매핑은 TypedTextDatabase 클래스(generated/texts/include/texts/TypedTextDatabase.hpp)에서 제어합니다.

TouchGFX Designer의 Texts 탭에서 타이포그래피, 작성 방향(Left-to-right 또는 Right-to-left), 각 텍스트 정렬(Left, Right, Center)을 지정할 수 있습니다. 타이포그래피와 순서 및 정렬은 각 텍스트 번역마다 달라질 수 있습니다. 이렇게 설정한 정보는 각 언어별 테이블에 컴파일됩니다. 따라서 TouchGFX에서 특정 텍스트에 사용되는 폰트와 정렬 방식 및 문자 작성 방향을 쉽게 알 수 있습니다.

언어별 타이포그래피 정보

위 그림에서 TypedTextData 테이블에는 세 개의 배열을 가리키는 포인터가 있는데, 애플리케이션에서 사용되는 각 언어마다 하나씩 총 세 개입니다. 각 배열에는 시스템 텍스트마다 하나씩 세 가지 요소가 있습니다. 각 요소는 폰트와 읽는 순서 및 정렬을 나타냅니다. 위 예에서는 세 가지 언어의 텍스트가 모두 동일한 폰트를 사용하고 있지만, 텍스트들은 서로 다른 폰트(F1 또는 F2)을 사용합니다. 에플리케이션에서 사용하는 폰트가 2개이기 때문에 폰트 테이블에도 2개의 포인터가 있습니다.

TouchGFX가 스크린에 텍스트를 그리기 위해서는 먼저 TypedTextData에서 지정된 텍스트를 찾습니다. 이 데이터에는 TouchGFX Designer 또는 xml 문서 시트에 지정된 텍스트의 폰트 인덱스, 문자 방향(LTR/RTL), 그리고 가로 정렬(Left, Right, Center)이 포함되어 있습니다. TouchGFX는 TypedTextData(F1 또는 F2)의 폰트 인덱스를 사용해 올바른 텍스트 폰트를 찾습니다.

폰트가 애플리케이션으로 컴파일되면 이 모든 과정이 자동으로 일어납니다.

바이너리 폰트 사용

애플리케이션에서 사용하는 폰트와 문자가 많고 다양하면 애플리케이션의 크기가 엄청나게 커질 수 있습니다.

TouchGFX는 이러한 문제를 줄이기 위해 애플리케이션에서 바이너리 폰트를 사용하도록 지원합니다. 바이너리 폰트는 애플리케이션에 연결되지 않지만 애플리케이션과 별도로 파일로 저장됩니다. 이러한 파일들은 런타임 시 애플리케이션에서 로드되어 TouchGFX에 제공될 수 있습니다. 애플리케이션은 예를 들어 SD 카드 같은 외장 저장 장치에서 폰트를 로드하거나, 인터넷에서 폰트를 다운로드할 수 있습니다.

애플리케이션이 폰트를 로드하면 TouchGFX에게 바이너리 폰트를 폰트 시스템에 설치할지 여부를 물을 수 있습니다.

폰트 테이블에 바이너리 폰트 설치하기

위에서는 기본적으로 제공되는 Font2가 애플리케이션에서 로드한 바이너리 폰트로 바뀌었습니다. 따라서 연결된 Font2는 이제 TouchGFX에서 사용되지 않습니다.

텍스트 테이블에서는 변경된 사항이 없습니다. 이들은 여전히 인덱스별로 동일한 폰트(F1 및 F2)를 참조합니다.

바이너리 폰트를 생성하도록 폰트 변환 도구 구성하기

폰트 변환 도구는 바이너리 폰트를 생성하도록 구성해야 하는데, TouchGFX Designer에서 이를 쉽게 구성할 수 있습니다. 다음과 같이 Config 탭으로 이동하여 "Text Configuration"을 선택한 다음 "Binary font files"를 클릭합니다.

바이너리 폰트 선택하기

코드를 다시 생성하면 TouchGFX가 generated/fonts/bin/ 폴더에 바이너리 폰트를 생성하고 generated/fonts/src/에 저장된 일반 파일에서 폰트를 소거합니다.

생성된 코드는 빈 폰트를 사용하도록 TouchGFX를 구성합니다. 런타임에서 바이너리 폰트를 설치하려면 이 애플리케이션이 필요합니다.

수동 구성

TouchGFX Designer를 사용하지 않는 경우에도 바이너리 폰트를 생성할 수 있습니다. 프로젝트에서 application.config 파일의 text_configuration 구간에 있는 "binary_fonts"를 “yes”로 변경합니다.

application.config
  "text_configuration": {
"remap": "yes",
"a4": "yes",
"binary_translations": "no",
"binary_fonts": "yes",
"framebuffer_bpp": "16"
}

이제 다음 번에 자산을 생성하면 generated/fonts/bin 폴더에 바이너리 폰트가 생성됩니다.

바이너리 폰트 설치

TouchGFX에서 바이너리 폰트를 사용할 수 있으려면 먼저 RAM이나 QSPI 플래시(포인터를 통해 직접 액세스가 가능) 같이 주소 지정이 가능한 메모리에서 폰트 데이터를 사용할 수 있어야 합니다. 이를 위해서는 일반적으로 파일이나 emmc 플래시 같은 블록 스토리지에서 데이터를 복사하는 작업을 수행해야 합니다. 프로덕션 단계에서 바이너리 폰트가 메모리 매핑 플래시에 미리 정의되어 있는 주소로 플래시되는 중에도 이러한 작업을 수행할 수 있습니다.

바이너리 폰트가 메모리에 로딩된 경우(아직 사용할 수 없는 경우), 애플리케이션은 TouchGFX의 데이터를 참조하는 BinaryFont 객체를 생성해서 설치해야 합니다. 이후부터는 TouchGFX가 컴파일된 폰트가 아닌 바이너리 폰트를 사용하게 됩니다.

바이너리 폰트는 텍스트를 그리는 데 사용하기 전에 설치해야 하지만, 부팅하자마자 설치할 필요는 없습니다. FrontApplication.cpp에서 FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap) 생성자를 사용하여 폰트를 설치할 수 있습니다. 무엇이든 그리기 전에 이 생성자가 실행됩니다.

setupScreen() 메서드에서도 폰트를 설치할 수 있습니다. 이 기능은 특정 화면에서만 사용되는 폰트가 있는 경우에 유용합니다. 그러면 tearDownScreen()에서 폰트를 제거할 수 있습니다.

다음은 파일 시스템에서 내부 RAM으로 바이너리 폰트를 로드하는 예입니다.

FrontendApplication.cpp
//read the file into this array in internal RAM
uint8_t fontdata[10000];

//binary font object using the data
BinaryFont bf;

FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
//read the binary font from a file
FILE* font = fopen("generated/fonts/bin/Font_verdana_20_4bpp.bin", "rb");
if (font)
{
//read data from the file
fread(fontdata, 1, 10000, font);
fclose(font);

//initialize BinaryFont object in bf using placement new
new (&bf) BinaryFont((const struct touchgfx::BinaryFontData*)fontdata);

//replace application font 'DEFAULT' with the binary font
TypedTextDatabase::setFont(DEFAULT, &bf); //verdana_20_4bpp
}
}

파일을 열고 데이터를 읽는 코드는 사용하는 파일 시스템과 운영 체제에 따라 다릅니다. 기본적으로 먼저 메모리에서 사용할 수 있는 폰트 데이터를 만들고 나서 포인터가 해당 데이터를 가리키도록 BinaryFont 객체를 초기화한 다음, 마지막으로 BinaryFont 객체를 TouchGFX의 TypedTextDatabase로 전달합니다.

그러면 폰트로 컴파일되는 대신에(DEFAULT), TouchGFX가 setFont를 호출한 후에 바이너리 폰트를 사용해 스크린에 텍스트를 그리게 됩니다.

폰트 리셋하기

간혹 바이너리 폰트를 사용하다가 애플리케이션으로 컴파일된 원본 폰트로 돌아가야 하는 경우도 있는데, 예를 들면 언어를 변경하면서 기본 폰트를 사용하고 싶을 때가 그렇습니다. 이때는 TypedTextDatabase에서 다음과 같이 resetFont() 함수를 사용하면 폰트 포인터가 기본적으로 제공되는 폰트를 가리키도록 리셋됩니다.

//reset to original font
TypedTextDatabase::resetFont(DEFAULT);

위 함수를 호출하면 애플리케이션이 새 폰트를 할당하거나, 그 밖에 다른 목적으로 바이너리 폰트에서 차지하고 있는 메모리를 재사용할 수 있게 됩니다.

또 다른 프로젝트에서 바이너리 폰트 생성

때로 프로젝트에서 일반 폰트와 바이너리 폰트를 모두 사용하고 싶은 경우가 있습니다. 예를 들어 컴파일된 정상적인 폰트로 영어 문자를 사용하되, 장치에 선택적으로 포함시킬 바이너리 폰트로는 중국어 및 일본어 문자를 사용하고 싶을 수 있습니다. TouchGFX Designer에서는 이러한 설정이 불가능합니다.

이 경우에는 TouchGFX 프로젝트를 2개 생성할 것을 권장합니다. 첫 번째 프로젝트(일반 애플리케이션)에는 모든 애플리케이션 코드와 UI가 일반 폰트로 되어 있습니다. 두 번째 프로젝트에는 바이너리 폰트를 생성하기에 충분한 텍스트(또는 와일드카드 문자)만 있습니다.

첫 번째 프로젝트에서 "Binary font files"의 선택을 취소합니다. 두 번째 프로젝트에서 "Binary font files"을 선택합니다

두 번째 TouchGFX 프로젝트에서 코드를 생성하면 바이너리 폰트가 생성됩니다. 그런 다음, 바이너리 폰트를 첫 번째 프로젝트를 사용하기 편한 폴더에 복사하고 위에서와 같이 코드에서 이를 사용할 수 있습니다.