Wiseohub
stanislav@daixe

Как загрузить любой шрифт Google Fonts на дисплей ESP32 — без Processing и ручной конвертации

4 мин20 просмотров
  • #Интерфейсы
  • #ESP32
  • #Google Fonts

Каждый раз, когда я вывожу текст на TFT-дисплей через TFT_eSPI, приходится смотреть на одни и те же встроенные шрифты: жирные, зубчатые и будто прямиком из 1980-х. И это особенно обидно, потому что библиотека уже много лет умеет отрисовывать красивые сглаженные шрифты (smooth fonts). Проблема никогда не была в самой отрисовке — она была в инструментах. Официальный способ создать гладкий шрифт предполагает установку Processing IDE, редактирование Java-скетча и повторный запуск для каждого шрифта и каждого размера. В итоге в большинстве проектов с этим просто не связываются.

Поэтому я сделал инструмент, который решает эту проблему.

fonts.atomic14.com — бесплатный браузерный инструмент, который преобразует любой из более чем 1900 шрифтов Google Fonts или ваш собственный TTF-файл в шрифты, готовые для использования с TFT_eSPI, M5Stack/M5GFX или LVGL. Там же можно увидеть попиксельно точный предпросмотр того, как шрифт будет выглядеть на вашем дисплее. Всё работает прямо в браузере: файлы шрифтов никуда не загружаются.

Дальше разберём, что на самом деле находится внутри этих файлов шрифтов и что стоит знать перед их использованием.

Что на самом деле представляет собой «гладкий шрифт»

Гладкие шрифты в TFT_eSPI — это файлы VLW, формат которых достался библиотеке от проекта Processing. VLW устроен до неприличия просто: небольшой заголовок с количеством глифов, размером, верхним и нижним выносами, таблица метрик каждого глифа, а затем необработанные 8-битные альфа-маски — по одному байту на пиксель. Никаких векторных контуров, хинтинга или кернинга. Шрифт заранее растеризуется на компьютере, а микроконтроллеру остаётся лишь копировать готовые пиксели на экран.

«Сглаживание» обеспечивает именно альфа-канал. В каждом пикселе хранится степень покрытия глифом — от 0 до 255. Во время отрисовки библиотека смешивает цвет текста с цветом фона в цветовом пространстве RGB565.

PROGMEM или LittleFS?

Загрузить VLW на микроконтроллер можно двумя способами, и инструмент поддерживает оба:

Заголовочный файл .h, в котором шрифт хранится как массив байтов в PROGMEM. Это самый простой вариант: подключаете файл через #include, вызываете tft.loadFont(MyFont28); — и готово. Шрифт хранится во флеш-памяти вместе с кодом.

Файл .vlw в LittleFS или на SD-карте, который загружается вызовом tft.loadFont("MyFont28", LittleFS);. Этот вариант удобнее, если у вас несколько шрифтов или вы хотите менять их без перекомпиляции, но придётся повозиться с загрузкой файловой системы.

В любом случае не забудьте добавить #define SMOOTH_FONT в User_Setup.h. Его отсутствие — самая частая причина ошибок компиляции в духе «почему loadFont не существует».

Как уменьшить размер файлов

На один глиф приходится 28 байт метаданных плюс ширина × высота байт растрового изображения. При размере 28 пикселей полный набор Basic Latin занимает примерно 25–30 Кбайт, а шрифт только с цифрами для вывода показаний датчика может весить меньше 2 Кбайт. Каждый исключённый символ — это сэкономленная флеш-память. Инструмент в реальном времени показывает итоговый размер при изменении набора символов, а ненужные символы можно убирать из таблицы по одному. Если вам нужны только знак °C и десять цифр, оставьте только знак °C и десять цифр.

Особенности, которые лучше увидеть в предпросмотре

Есть два нюанса, которые удивляют почти всех. Я специально воспроизвёл их в предпросмотре: для отрисовки используется порт собственного кода TFT_eSPI, а не шрифтовый движок браузера.

Текст переносится у правого края. Если глиф не помещается, при отрисовке сглаженного шрифта библиотека переходит на следующую строку и начинает с x=0. По границе текст не обрезается.

Для пробелов используется не реальная ширина пробела из шрифта. Вместо неё библиотека вычисляет значение по формуле (ascent + descent) × 2/7 пикселя. Поэтому межсловный интервал на устройстве никогда полностью не совпадёт с тем, как тот же шрифт выглядит на компьютере. Зато предпросмотр совпадает с устройством — а это здесь главное.

Если какой-то символ на дисплее отображается пустым, почти всегда причина в том, что он не вошёл в выбранное подмножество. Классический пример — знак градуса: его нет в Basic Latin, поэтому показания температуры незаметно превращаются в 23.5C. Достаточно добавить его в поле дополнительных символов. Предпросмотр покажет пропуск ещё до того, как вы увидите его на дисплее.

020
?