1.. |check|  unicode:: U+02713 .. CHECK MARK
2.. |Aacute| unicode:: U+000C1 .. LATIN CAPITAL LETTER A WITH ACUTE
3.. |eacute| unicode:: U+000E9 .. LATIN SMALL LETTER E WITH ACUTE
4.. |otilde| unicode:: U+000F5 .. LATIN SMALL LETTER O WITH TILDE
5.. |Utilde| unicode:: U+00168 .. LATIN CAPITAL LETTER U WITH TILDE
6.. |uuml|   unicode:: U+000FC .. LATIN SMALL LETTER U WITH DIAERESIS
7.. |uml|    unicode:: U+000A8 .. DIAERESIS
8
9.. _font:
10
11==============
12Font (lv_font)
13==============
14
15In LVGL fonts are collections of bitmaps and other information required
16to render images of individual letters (glyph). A font is stored in a
17:cpp:type:`lv_font_t` variable and can be set in a style's *text_font* field.
18For example:
19
20.. code-block:: c
21
22    lv_style_set_text_font(&my_style, &lv_font_montserrat_28);  /* Set a larger font */
23
24Fonts have a **format** property. It describes how the glyph data is stored.
25At this writing there are 12 possible values that this field can take, and those
26values fall into 2 categories:
27
28:Legacy simple: 1, 2, 4 or 8-bpp (aligned or unaligned) and image format, and
29:Advanced:      vector, SVG, and custom formats; for the latter, the user provides
30                the rendering logic.
31
32For simple formats:
33
34- the font is stored as an array of bitmaps, one bitmap per glyph;
35- the value stored for each pixel determines the pixel's opacity, enabling edges
36  to be smoother --- higher bpp values result in smoother edges.
37
38For advanced formats, the font information is stored in its respective format.
39
40The **format** property also affects the amount of memory needed to store a
41font. For example, ``format = LV_FONT_GLYPH_FORMAT_A4`` makes a font nearly four
42times larger compared to ``format = LV_FONT_GLYPH_FORMAT_A1``.
43
44
45
46Unicode Support
47***************
48
49LVGL supports **UTF-8** encoded Unicode characters. Your editor needs to
50be configured to save your code/text as UTF-8 (usually this the default)
51and be sure that :c:macro:`LV_TXT_ENC` is set to :c:macro:`LV_TXT_ENC_UTF8` in
52``lv_conf.h``. (This is the default value.)
53
54To test it try
55
56.. code-block:: c
57
58   lv_obj_t * label1 = lv_label_create(lv_screen_active(), NULL);
59   lv_label_set_text(label1, LV_SYMBOL_OK);
60
61If all works well, a '\ |check|\ ' character should be displayed.
62
63
64Typesetting
65***********
66
67Although LVGL can decode and display any Unicode characters
68(assuming the font supports them), LVGL cannot correctly render
69all complex languages.
70
71The standard Latin-based languages (e.g., English, Spanish, German)
72and East Asian languages such as Chinese, Japanese, and Korean (CJK)
73are relatively straightforward, as their characters are simply
74written from left to right.
75
76Languages like Arabic, Persian, and Hebrew, which use Right-to-Left
77(RTL) or mixed writing directions, are also supported in LVGL.
78Learn more :ref:`here <bidi>`.
79
80For characters such as '|eacute|', '|uuml|', '|otilde|', '|Aacute|', and '|Utilde|',
81it is recommended to use the single Unicode format (NFC) rather than decomposing them
82into a base letter and diacritics (e.g. ``u`` + |uml|).
83
84Complex languages where subsequent characters combine into a single glyph
85and where the resulting glyph has no individual Unicode representation
86(e.g., Devanagari), have limited support in LVGL.
87
88
89
90Built-In Fonts
91**************
92
93There are several built-in fonts in different sizes, which can be
94enabled in ``lv_conf.h`` with *LV_FONT_...* defines.
95
96Normal Fonts
97------------
98
99The following fonts contain all ASCII characters, the degree symbol (U+00B0), the
100bullet symbol (U+2022) and the built-in symbols (see below).
101
102- :c:macro:`LV_FONT_MONTSERRAT_12`: 12 px font
103- :c:macro:`LV_FONT_MONTSERRAT_14`: 14 px font
104- :c:macro:`LV_FONT_MONTSERRAT_16`: 16 px font
105- :c:macro:`LV_FONT_MONTSERRAT_18`: 18 px font
106- :c:macro:`LV_FONT_MONTSERRAT_20`: 20 px font
107- :c:macro:`LV_FONT_MONTSERRAT_22`: 22 px font
108- :c:macro:`LV_FONT_MONTSERRAT_24`: 24 px font
109- :c:macro:`LV_FONT_MONTSERRAT_26`: 26 px font
110- :c:macro:`LV_FONT_MONTSERRAT_28`: 28 px font
111- :c:macro:`LV_FONT_MONTSERRAT_30`: 30 px font
112- :c:macro:`LV_FONT_MONTSERRAT_32`: 32 px font
113- :c:macro:`LV_FONT_MONTSERRAT_34`: 34 px font
114- :c:macro:`LV_FONT_MONTSERRAT_36`: 36 px font
115- :c:macro:`LV_FONT_MONTSERRAT_38`: 38 px font
116- :c:macro:`LV_FONT_MONTSERRAT_40`: 40 px font
117- :c:macro:`LV_FONT_MONTSERRAT_42`: 42 px font
118- :c:macro:`LV_FONT_MONTSERRAT_44`: 44 px font
119- :c:macro:`LV_FONT_MONTSERRAT_46`: 46 px font
120- :c:macro:`LV_FONT_MONTSERRAT_48`: 48 px font
121
122Special fonts
123-------------
124
125-  :c:macro:`LV_FONT_MONTSERRAT_28_COMPRESSED`: Same as normal 28 px font but stored as a :ref:`fonts_compressed` with 3 bpp
126-  :c:macro:`LV_FONT_DEJAVU_16_PERSIAN_HEBREW`: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms
127-  :c:macro:`LV_FONT_SIMSUN_16_CJK`: 16 px font with normal range plus 1000 of the most common CJK radicals
128-  :c:macro:`LV_FONT_UNSCII_8`: 8 px pixel perfect font with only ASCII characters
129-  :c:macro:`LV_FONT_UNSCII_16`: 16 px pixel perfect font with only ASCII characters
130
131The built-in fonts are **global variables** with names like
132:cpp:var:`lv_font_montserrat_16` for a 16 px height font. To use them in a
133style, just add a pointer to a font variable like this:
134
135.. code-block:: c
136
137    lv_style_set_text_font(&my_style, &lv_font_montserrat_28);
138
139The built-in fonts with ``bpp = 4`` contain the ASCII characters and use
140the `Montserrat <https://fonts.google.com/specimen/Montserrat>`__ font.
141
142In addition to the ASCII range, the following symbols are also added to
143the built-in fonts from the `FontAwesome <https://fontawesome.com/>`__
144font.
145
146.. _fonts_symbols:
147
148.. image:: /misc/symbols.png
149
150The symbols can be used singly as:
151
152.. code-block:: c
153
154   lv_label_set_text(my_label, LV_SYMBOL_OK);
155
156Or together with strings (compile time string concatenation):
157
158.. code-block:: c
159
160   lv_label_set_text(my_label, LV_SYMBOL_OK "Apply");
161
162Or more symbols together:
163
164.. code-block:: c
165
166   lv_label_set_text(my_label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY);
167
168
169
170Special Features
171****************
172
173.. _bidi:
174
175Bidirectional support
176---------------------
177
178Most languages use a Left-to-Right (LTR for short) writing direction,
179however some languages (such as Hebrew, Persian or Arabic) use
180Right-to-Left (RTL for short) direction.
181
182LVGL not only supports RTL text but supports mixed (a.k.a.
183bidirectional, BiDi) text rendering as well. Some examples:
184
185.. image:: /misc/bidi.png
186
187BiDi support is enabled by setting :c:macro:`LV_USE_BIDI` to a non-zero value in ``lv_conf.h``.
188
189All text has a base direction (LTR or RTL) which determines some
190rendering rules and the default alignment of the text (left or right).
191However, in LVGL, the base direction is not only applied to labels. It's
192a general property which can be set for every Widget. If not set then it
193will be inherited from the parent. This means it's enough to set the
194base direction of a screen and its child Widgets will inherit it.
195
196The default base direction for screens can be set by
197:c:macro:`LV_BIDI_BASE_DIR_DEF` in ``lv_conf.h`` and other Widgets inherit the
198base direction from their parent.
199
200To set a Widget's base direction use :cpp:expr:`lv_obj_set_style_base_dir(widget, base_dir, selector)`.
201The possible base directions are:
202
203- :cpp:enumerator:`LV_BASE_DIR_LTR`: Left to Right base direction
204- :cpp:enumerator:`LV_BASE_DIR_RTL`: Right to Left base direction
205- :cpp:enumerator:`LV_BASE_DIR_AUTO`: Auto detect base direction
206
207This list summarizes the effect of RTL base direction on Widgets:
208
209- Create Widgets by default on the right
210- ``lv_tabview``: Displays tabs from right to left
211- ``lv_checkbox``: Shows the box on the right
212- ``lv_buttonmatrix``: Orders buttons from right to left
213- ``lv_list``: Shows icons on the right
214- ``lv_dropdown``: Aligns options to the right
215- The text strings in ``lv_table``, ``lv_buttonmatrix``, ``lv_keyboard``, ``lv_tabview``,
216  ``lv_dropdown``, ``lv_roller`` are "BiDi processed" to be displayed correctly
217
218Arabic and Persian support
219--------------------------
220
221There are some special rules to display Arabic and Persian characters:
222the *form* of a character depends on its position in the text. A
223different form of the same letter needs to be used when it is isolated,
224at start, middle or end positions. Besides these, some conjunction rules
225should also be taken into account.
226
227LVGL supports these rules if :c:macro:`LV_USE_ARABIC_PERSIAN_CHARS` is enabled
228in ``lv_conf.h``.
229
230However, there are some limitations:
231
232- Only displaying text is supported (e.g. on labels), i.e. text inputs (e.g. Text
233  Area) do not support this feature.
234- Static text (i.e. const) is not processed. E.g. text set by :cpp:func:`lv_label_set_text`
235  will be "Arabic processed" but :cpp:func:`lv_label_set_text_static` will not.
236- Text get functions (e.g. :cpp:func:`lv_label_get_text`) will return the processed text.
237
238.. _fonts_compressed:
239
240Compressed fonts
241----------------
242
243The built-in font engine supports compressed bitmaps.
244Compressed fonts can be generated by
245
246- ticking the ``Compressed`` check box in the online converter
247- not passing the ``--no-compress`` flag to the offline converter (compression is applied by default)
248
249Compression is more effective with larger fonts and higher bpp. However,
250it's about 30% slower to render compressed fonts. Therefore, it is
251recommended to compress only the largest fonts of a user interface,
252because
253
254- they need the most memory
255- they can be compressed better
256- and on the likelihood that they are used less frequently than the medium-sized
257  fonts, the performance cost will be smaller.
258
259Compressed fonts also support ``bpp=3``.
260
261Kerning
262-------
263
264Fonts may provide kerning information to adjust the spacing between specific
265characters.
266
267- The online converter generates kerning tables.
268- The offline converter generates kerning tables unless ``--no-kerning`` is
269  specified.
270- FreeType integration does not currently support kerning.
271- The Tiny TTF font engine supports GPOS (Glyph Positioning) and Kern tables.
272
273To configure kerning at runtime, use :cpp:func:`lv_font_set_kerning`.
274
275
276
277.. _add_font:
278
279Adding a New Font
280*****************
281
282There are several ways to add a new font to your project:
283
2841. The simplest method is to use the `Online font converter <https://lvgl.io/tools/fontconverter>`__.
285   Just set the parameters, click the *Convert* button, copy the font to your project
286   and use it. **Be sure to carefully read the steps provided on that site
287   or you will get an error while converting.**
2882. Use the `Offline font converter <https://github.com/lvgl/lv_font_conv>`__.
289   (Requires Node.js to be installed)
2903. If you want to create something like the built-in
291   fonts (Montserrat font and symbols) but in a different size and/or
292   ranges, you can use the ``built_in_font_gen.py`` script in
293   ``lvgl/scripts/built_in_font`` folder. (This requires Python and
294   https://github.com/lvgl/lv_font_conv/ to be installed.)
295
296To declare a font in a file, use :cpp:expr:`LV_FONT_DECLARE(my_font_name)`.
297
298To make fonts globally available (like the built-in fonts), add them to
299:c:macro:`LV_FONT_CUSTOM_DECLARE` in ``lv_conf.h``.
300
301
302
303Adding New Symbols
304******************
305
306The built-in symbols are created from the `FontAwesome <https://fontawesome.com/>`__ font.
307
3081. Search for a symbol on https://fontawesome.com. For example the
309   `USB symbol <https://fontawesome.com/icons/usb?style=brands>`__. Copy its
310   Unicode ID which is ``0xf287``.
3112. Open the `Online font converter <https://lvgl.io/tools/fontconverter>`__.
312   Add `FontAwesome.woff <https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff>`__.
3133. Set the parameters such as Name, Size, BPP. You'll use this name to
314   declare and use the font in your code.
3154. Add the Unicode ID of the symbol to the range field. E.g.\ ``0xf287``
316   for the USB symbol. More symbols can be enumerated with ``,``.
3175. Convert the font and copy the generated source code to your project.
318   Make sure to compile the ``.c`` file of your font.
3196. Declare the font using ``extern lv_font_t my_font_name;`` or simply
320   use :cpp:expr:`LV_FONT_DECLARE(my_font_name)`.
321
322**Using the symbol**
323
3241. Convert the Unicode value to UTF8, for example on
325   `this site <http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f287&mode=hex>`__.
326   For ``0xf287`` the *Hex UTF-8 bytes* are ``EF 8A 87``.
3272. Create a ``#define`` string from the UTF8 values: ``#define MY_USB_SYMBOL "\xEF\x8A\x87"``
3283. Create a label and set the text. Eg. :cpp:expr:`lv_label_set_text(label, MY_USB_SYMBOL)`
329
330:note: :cpp:expr:`lv_label_set_text(label, MY_USB_SYMBOL)` searches for this symbol
331       in the font defined in the style's ``text.font`` property. To use the symbol
332       you will need to set the style's text font to use the generated font, e.g.
333       :cpp:expr:`lv_style_set_text_font(&my_style, &my_font_name)` or
334       :cpp:expr:`lv_obj_set_style_text_font(label, &my_font_name, 0)`.
335
336
337
338Loading a Font at Run-Time
339**************************
340
341:cpp:func:`lv_binfont_create` can be used to load a font from a file. The font needs
342to have a special binary format. (Not TTF or WOFF). Use
343`lv_font_conv <https://github.com/lvgl/lv_font_conv/>`__ with the
344``--format bin`` option to generate an LVGL compatible font file.
345
346:note: To load a font :ref:`LVGL's filesystem <overview_file_system>`
347       needs to be enabled and a driver must be added.
348
349Example
350
351.. code-block:: c
352
353   lv_font_t *my_font = lv_binfont_create("X:/path/to/my_font.bin");
354   if(my_font == NULL) return;
355
356   /* Use the font */
357
358   /* Free the font if not required anymore */
359   lv_binfont_destroy(my_font);
360
361
362
363Loading a Font from a Memory Buffer at Run-Time
364***********************************************
365
366:cpp:func:`lv_binfont_create_from_buffer` can be used to load a font from a memory buffer.
367This function may be useful to load a font from an external file system, which is not
368supported by LVGL. The font needs to be in the same format as if it were loaded from a file.
369
370:note: To load a font from a buffer :ref:`LVGL's filesystem <overview_file_system>`
371       needs to be enabled and the MEMFS driver must be added.
372
373Example
374
375.. code-block:: c
376
377   lv_font_t *my_font;
378   uint8_t *buf;
379   uint32_t bufsize;
380
381   /* Read font file into the buffer from the external file system */
382   ...
383
384   /* Load font from the buffer */
385   my_font = lv_binfont_create_from_buffer((void *)buf, buf));
386   if(my_font == NULL) return;
387   /* Use the font */
388
389   /* Free the font if not required anymore */
390   lv_binfont_destroy(my_font);
391
392
393Using a BDF Font
394****************
395
396Small displays with low resolution don't look pretty with automatically rendered fonts. A bitmap font provides
397the solution, but it's necessary to convert the bitmap font (BDF) to a TTF.
398
399Convert BDF to TTF
400------------------
401
402BDF are bitmap fonts where fonts are not described in outlines but in pixels. BDF files can be used but
403they must be converted into the TTF format using ``mkttf``, which can be found
404in this GitHub repository:  https://github.com/Tblue/mkttf .  This tool uses potrace to generate outlines from
405the bitmap information. The bitmap itself will be embedded into the TTF as well. `lv_font_conv <https://github.com/lvgl/lv_font_conv/>`__ uses
406the embedded bitmap but it also needs the outlines. One might think you can use a fake MS Bitmap
407only sfnt (ttf) (TTF without outlines) created by fontforge, but this will not work.
408
409Install imagemagick, python3, python3-fontforge and potrace
410
411On Ubuntu Systems, just type
412
413.. code:: bash
414
415    sudo apt install imagemagick python3-fontforge potrace
416
417Clone mkttf
418
419.. code:: bash
420
421    git clone https://github.com/Tblue/mkttf
422
423Read the mkttf docs.
424
425Former versions of imagemagick needs the imagemagick call in front of convert, identify and so on.
426But newer versions don't. So you might want to change 2 lines in ``potrace-wrapper.sh`` ---
427open ``potrace-wrapper.sh`` and remove imagemagick from line 55 and line 64:
428
429line 55
430
431.. code:: bash
432
433    wh=($(identify -format '%[width]pt %[height]pt' "${input?}"))
434
435line 64
436
437.. code:: bash
438
439    convert "${input?}" -sample '1000%' - \
440
441It might be necessary to change the mkttf.py script.
442
443line 1
444
445.. code:: bash
446
447    #!/usr/bin/env python3
448
449Example for a 12px font
450-----------------------
451
452.. code-block:: console
453
454    cd mkttf
455    ./mkttf.py ./TerminusMedium-12-12.bdf
456    Importing bitmaps from 0 additional fonts...
457    Importing font `./TerminusMedium-12-12.bdf' into glyph background...
458    Processing glyphs...
459    Saving TTF file...
460    Saving SFD file...
461    Done!
462
463The TTF ``TerminusMedium-001.000.ttf`` will be created from ``./TerminusMedium-12-12.bdf``.
464
465To create a font for LVGL:
466
467.. code:: bash
468
469    lv_font_conv --bpp 1 --size 12 --no-compress --font TerminusMedium-001.000.ttf --range 0x20-0x7e,0xa1-0xff --format lvgl -o terminus_1bpp_12px.c
470
471:note: use 1-bpp because we don't use anti-aliasing. It doesn't look sharp on displays with a low resolution.
472
473
474
475Adding a New Font Engine
476************************
477
478LVGL's font interface is designed to be very flexible but, even so, you
479can add your own font engine in place of LVGL's internal one. For
480example, you can use `FreeType <https://www.freetype.org/>`__ to
481real-time render glyphs from TTF fonts or use an external flash to store
482the font's bitmap and read them when the library needs them. FreeType can be used in LVGL as described in :ref:`Freetype <freetype>`.
483
484To add a new font engine, a custom :cpp:type:`lv_font_t` variable needs to be created:
485
486.. code-block:: c
487
488   /* Describe the properties of a font */
489   lv_font_t my_font;
490   my_font.get_glyph_dsc = my_get_glyph_dsc_cb;        /* Set a callback to get info about glyphs */
491   my_font.get_glyph_bitmap = my_get_glyph_bitmap_cb;  /* Set a callback to get bitmap of a glyph */
492   my_font.line_height = height;                       /* The real line height where any text fits */
493   my_font.base_line = base_line;                      /* Base line measured from the top of line_height */
494   my_font.dsc = something_required;                   /* Store any implementation specific data here */
495   my_font.user_data = user_data;                      /* Optionally some extra user data */
496
497   ...
498
499   /* Get info about glyph of `unicode_letter` in `font` font.
500    * Store the result in `dsc_out`.
501    * The next letter (`unicode_letter_next`) might be used to calculate the width required by this glyph (kerning)
502    */
503   bool my_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
504   {
505       /* Your code here */
506
507       /* Store the result.
508        * For example ...
509        */
510       dsc_out->adv_w = 12;        /* Horizontal space required by the glyph in [px] */
511       dsc_out->box_h = 8;         /* Height of the bitmap in [px] */
512       dsc_out->box_w = 6;         /* Width of the bitmap in [px] */
513       dsc_out->ofs_x = 0;         /* X offset of the bitmap in [pf] */
514       dsc_out->ofs_y = 3;         /* Y offset of the bitmap measured from the as line */
515       dsc_out->format= LV_FONT_GLYPH_FORMAT_A2;
516
517       return true;                /* true: glyph found; false: glyph was not found */
518   }
519
520
521   /* Get the bitmap of `unicode_letter` from `font`. */
522   const uint8_t * my_get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter)
523   {
524       /* Your code here */
525
526       /* The bitmap should be a continuous bitstream where
527        * each pixel is represented by `bpp` bits */
528
529       return bitmap;    /* Or NULL if not found */
530   }
531
532
533
534Using Font Fallback
535*******************
536
537If the font in use does not have a glyph needed in a text-rendering task, you can
538specify a ``fallback`` font to be used in :cpp:type:`lv_font_t`.
539
540``fallback`` can be chained, so it will try to solve until there is no ``fallback`` set.
541
542.. code-block:: c
543
544   /* Roboto font doesn't have support for CJK glyphs */
545   lv_font_t *roboto = my_font_load_function();
546   /* Droid Sans Fallback has more glyphs but its typeface doesn't look good as Roboto */
547   lv_font_t *droid_sans_fallback = my_font_load_function();
548   /* So now we can display Roboto for supported characters while having wider characters set support */
549   roboto->fallback = droid_sans_fallback;
550
551
552
553.. _fonts_api:
554
555API
556***
557