Skip to main content

Vector Fonts

TouchGFX supports using fonts in vector format starting from version 4.23. Fonts stored in vector format can potentially reduce the size of the font data as the font data is shared between all sizes of a font. This is in contrast to bitmap fonts where every size of a font contains dedicated bitmaps of the glyphs in that size.

Vector fonts are used on the user interface just like the normal bitmap fonts using widgets like TextArea or ButtonWithLabel.

To use the vector font format, the vector font functionality must be enabled for the platform in STM32CubeMX.

Vector fonts are only supported on 16bpp, 24bpp, or 32bpp frame buffers.

What are vector fonts

Vector fonts are fonts where the individual letters are described by curves and lines. These curves and lines can be scaled up and down to produce glyphs in different sizes. All the fonts we normally use in TouchGFX are vector fonts (for example TrueType or OpenType fonts). The curves and lines in the font description are converted to many small bitmaps by the TouchGFX Font Converter when TouchGFX Designer generates assets.

The conversion of vector fonts to bitmaps is based on the typographies defined in TouchGFX Designer. For example, an application may use two typographies, Large and Small. Large could be based on Verdana in size 30 and Small could be based on Verdana in size 20. If we assume that the application is using the glyphs A-Z and a-z in these typographies we get 52 glyphs for each typography, but the appplication will contain 104 bitmaps, as we get two bitmaps for each letter. One bitmap for size 30 and one for size 20.

Vector fonts are different because we keep the vector definition for a glyph and do not create a bitmap of the glyph. This vector definition is instead included in the target application one time only. The only extra data that is needed to produce the two required typographies is two different scaling factors. One to scale the vector definitions to size 30 and one to scale to size 20.

As a result, if we add another typography size to the example application - for example Verdana in size 40 - the flash requirement will only increase marginally.

Example

To give an example, the vector definition for "G" in the Truetype font Verdana is 170 bytes.

The size of the bitmap representing the glyph depends on the bpp used and the size of the glyph. The table below shows the bitmap size for "G" in various glyph sizes in 4bpp:

Font sizeG glyph dimension / pixelsBitmap size / bytes
2014 x 1498
3021 x 22242
4027 x 32448
Total788

We see that the bitmap size for font size 20 is smaller than the vector definition of "G", but already at size 30 the vector definition is smaller than the bitmap size. And if we use three different sizes of Verdana, we use 788 bytes for the bitmaps while the vector definition still only uses 170 bytes. We therefore save 78% of the flash usage.

This storage saving comes with a disadvantage - performance. When we need to draw a glyph, we have to convert the vector definition to pixels. This is done by scaling and translating the vector definition of a glyph and then render it to the framebuffer.

A single "G" in Verdana consists of 20 Bezier curves and 6 straight line-pieces. These are all converted into an outline, which is finally colored using the selected text color. This process is repeated for all the letters in the text and repeated whenever the text is redrawn.

The above process is hardware accelerated on microcontrollers with GPU2D (for example STM32U5G9) where it works well. On slow microcontrollers like STM32G0, without floating point hardware, it would be very demanding for the hardware to perform these operations.

In such cases, the rendering time would be better if bitmap fonts are used. It is therefore recommended to use vector fonts where the flash-savings are necessary and otherwise use bitmap fonts.
If a text is animated (scrolled, moved or faded) it is recommended to use bitmap fonts.

Configuration

The use of vector fonts requires the additional framework features Vector Rendering and Vector Fonts. These are enabled in STM32CubeMX. See the Generator User Guide for more information.

Typographies are configured in TouchGFX Designer. Here you can select if a typography should use bitmap font format or a vector font format in for the project. The default is bitmap font format.

Using vector fonts

Vector fonts are used exactly as bitmap fonts in TouchGFX. You create texts either as named resources or single use texts. You show the text in one of the widgets, for example a TextArea. The differences between vector fonts and bitmap fonts are hidden in the rendering code.

Typographies

Vector fonts are generated when a typography in is configured to be vector based in TouchGFX Designer. See the Designer User Guide.

If multiple typographies uses the same font (e.g. Verdana), the typographies will share the vector definitions in the project, but use them with a different scale factor to produce glyphs of different sizes.

This also means that the typography attributes Fallback Character and Ellipsis Character must be the same for the typographies.

The characters used in the typographies (including wildcard characters) are combined and made available for all the typographies in the project using the same font.

Architecture

Rendering of vector fonts is based on a new component VectorFontRenderer. This component uses the VectorRenderer component to draw the glyphs.

In a project that uses vector fonts, these two components must be made available. This is done by STM32CubeMX automatically if these are enabled. It must be done manually if you are not using STM32CubeMX.

Here is the code generated by STM32CubeMX with the relevant lines highlighted:

static STM32TouchController tc;
static STM32DMA dma;
static TouchGFXDataReader dataReader;
static LCD16bppSerialFlash display(dataReader);
static VectorFontRendererImpl vectorFontRenderer;
static ApplicationFontProvider fontProvider;
static Texts texts;
static TouchGFXHAL hal(dma, display, tc, 240, 320);

void touchgfx_init()
{
Bitmap::registerBitmapDatabase(BitmapDatabase::getInstance(), BitmapDatabase::getInstanceSize());
TypedText::registerTexts(&texts);
Texts::setLanguage(0);

hal.setDataReader(&dataReader);
fontProvider.setFlashReader(&dataReader);

display.setVectorFontRenderer(&vectorFontRenderer);
...

The VectorRenderer component must also be provided (from TouchGFXGeneratedHAL.cpp):

namespace touchgfx
{
VectorRenderer* VectorRenderer::getInstance()
{
static CWRVectorRendererRGB565 renderer;

return &renderer;
}
} // namespace touchgfx

If you are on a platform with the GPU2D accelerator, you should use CPU2DVectorRenderer instead of CWRVectorRendererRGB565. This will enable hardware acceleration.

Limitations

Winding rules

Vector font typographies used in TouchGFX applications are required to follow certain rules in order for glyphs to be drawn correctly. Specifically, glyphs with overlapping outlines are sometimes not rendered correctly due to the winding rule deployed by TouchGFX when drawing vector fonts. To remove overlapping outlines from custom typographies, it is recommended to use the free FontForge tool.

Using FontForge

Navigate to the FontForge installation folder (usually c:/Program Files (x86)/FontForgeBuilds) and launch the .exe:

FontForge launch view.

Navigate to the assets/fonts/ folder of your project, e.g., c:/TouchGFXProjects/MyApplication/TouchGFX/assets/fonts/. FontForge will detect all the TrueType fonts in the application. In this example, the Cairo-Bold.ttf TrueType font contains overlapping outlines which are not drawn correctly:

FontForge open TrueType font view.

Clicking OK will open the font view of all the glyphs in the typography:

FontForge font view.

To remove overlapping contours from glyphs, select all glyphs in the font view with Ctrl + A. Next, with all glyphs selected use shortcut Ctrl + u followed by Ctrl + Shift + O to remove overlapping contours from selected glyphs. A blue mark will appear above all glyphs, indicating they have been changed. The effect can be seen by double-clicking on individual glyphs. An example is shown of the $ glyph from before and after removing overlapping contours below:

$-glyph with overlapping contours (left) and non-overlapping contours (right).

Observe that the outline of the glyph remains unaffected, but contours which were overlapping are merged. To use the non-overlapping typography in a TouchGFX application we use FontForge to export the new font. In the FontForge font view, use shortcut Ctrl + Shift + G to export the fonts. This opens the Generate Fonts view. It is recommended to rename the typography, e.g., with "-no-overlap" as a suffix, to avoid overwriting the original font in case of an error. Select TrueType as output format. The settings should be set as shown below:

FontForge generate font settings.

Press Generate to export the fonts. Press Yes if warnings appear. The exported typography will appear next to the original TrueType font in the assets/fonts/ folder of your project. The original font can be removed from this folder and placed elsewhere on disk, to avoid having multiple typographies of the same name appear in the TouchGFX Designer. Restart TouchGFX Designer to make the new font visible in the font selector. If you had generated code in TouchGFX Designer before modifying the font, make sure to remove the generated/fonts/ folder before generating code again.

Storage

Vector font data must be stored in a memory mapped area. This can be internal flash, external QSPI/OSPI flash in memory-mapped mode, RAM, or other similar memories.

If your platform stores other font data in non-memory-mapped data you must change the linker script to move all vector font data to e.g. internal flash. Here is how to do this with ARM gcc:

  /* Constant data into "FLASH" Rom type memory */
.FontFlashSection :
{
. = ALIGN(4);
*/Vector_*.o(FontFlashSection) /* Vector font data */
. = ALIGN(4);
} >FLASH

FontFlashSection :
{
*(FontFlashSection FontFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >SPI_FLASH

This puts font data from files matching */Vector_*.o/ into the FLASH region and other font data into the SPI_FLASH region.

Vector font data is generated into files like generated/fonts/src/Vector_Font_Verdana.cpp and similar.

Thai

It is a known issue that Thai does not render correctly with vector fonts. The work around is to use a bitmap font for Thai.