uGFX — графическая библиотека для микроконтроллеров. Часть 4
Возможности вывода текста
Графическая библиотека uGFX предоставляет богатые возможности по выводу текста на дисплей. Можно выделить следующие особенности:
- вывод текста различными шрифтами (одновременно можно использовать несколько разных шрифтов);
- только горизонтальная ориентация текста, вывести строку вертикально возможности нет;
- набор встроенных шрифтов, каждый из которых можно отключить для экономии памяти;
- возможность добавить свой собственный шрифт, конвертировав его из векторного формата TrueType;
- шрифты хранятся в памяти в растровом виде с использованием алгоритма сжатия RLE [15];
- поддержка кириллицы;
- поддержка символов Unicode (технические, математические, любые другие символы);
- возможность выводить как сглаженные (anti-aliased), так и не сглаженные шрифты;
- возможность при выводе текста включить или выключить кернинг (уплотнение текста за счет сдвига некоторых букв друг к другу).
Библиотека uGFX берет на себя функцию знакогенератора. В некоторые модели контроллеров дисплеев встроены свои знакогенераторы — uGFX их не использует. Это, с одной стороны, дает свободу выбора шрифта, его размера и расширяет набор выводимых символов, а с другой — требует дополнительных затрат памяти для размещения своего знакогенератора (то есть шрифта).
Для демонстрации возможностей вывода текста автор выбрал последнюю на момент написания статьи версию uGFX 2.2 от 4 января 2015 года. Среда разработки (CooCox CoIDE) и аппаратная платформа (микроконтроллер ARM Cortex-M3 + цветной ЖКИ-дисплей разрешением 320×240 пикселей на контроллере ILI9341) использовались те же, что и в предыдущих статьях цикла [14].
Читатель может загрузить готовый проект для среды разработки CooCox CoIDE 1.7.7, с которым работал автор, — в виде ZIP-архива. Сделать это можно по адресу [17].
Внутренняя организация. Библиотека mcufont
Поддержка шрифтов в библиотеке uGFX реализована с помощью библиотеки mcufont [1], которая существует и как отдельный программный продукт с открытым исходным кодом. Столь богатые возможности вывода текста присутствуют в uGFX именно благодаря библиотеке mcufont.
Вывод текста в uGFX включен в модуль GDISP. Каталог c исходным кодом модуля GDISP \ugfx\src\gdisp имеет директорию mcufont, содержащую часть исходного кода библиотеки mcufont, а также директорию fonts, в которой находятся исходные файлы со встроенными в uGFX шрифтами.
Открытие шрифта
Как и другие компоненты модуля GDISP, функция вывода текста может быть включена или отключена (для экономии памяти в случаях, когда вывод текста не нужен). По умолчанию вывод текста отключен, чтобы его включить, в конфигурационный файл ugfxconf.h следует добавить строку:
#define GDISP_NEED_TEXT TRUE
Текст выводится с применением какого-либо шрифта. Перед использованием шрифта он должен быть открыт с помощью API-функции gdispOpenFont(), ее прототип:
font_t gdispOpenFont(const char *name);
В качестве аргумента API-функция получает нуль-терминальную строку — имя шрифта. Шрифт с данным именем должен быть либо встроенным и разрешенным к использованию в конфигурационном файле, либо пользовательским. Например, встроенному шрифту DejaVu Sans с размером 32 и со сглаживанием будет соответствовать имя “DejaVuSans32_aa”, тогда операция его открытия будет выглядеть так:
font_t font = gdispOpenFont(“DejaVuSans32_aa”);
Кроме этого, данный встроенный шрифт должен быть разрешен к применению: конфигурационный файл ugfxconf.h должен содержать строку с конфигурационным макроопределением:
#define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA TRUE
Полный список встроенных шрифтов, их имен и соответствующих конфигурационных макроопределений приведен в таблице. Anti-Aliased в названии означает, что шрифт сглаженный. Каждый встроенный шрифт имеет имя, представленное в uGFX в виде текстовой нуль-терминальной строки. Именно это имя следует указывать при открытии шрифта API-функцией gdispOpenFont().
Шрифт |
Его имя в uGFX |
Файл со шрифтом |
Конфигурационное макроопределение |
DejaVu Sans 10 |
DejaVuSans10 |
DejaVuSans10.c |
GDISP_INCLUDE_FONT_DEJAVUSANS10 |
DejaVu Sans 12 |
DejaVuSans12 |
DejaVuSans12.c |
GDISP_INCLUDE_FONT_DEJAVUSANS12 |
DejaVu Sans 12 Bold |
DejaVuSansBold12 |
DejaVuSansBold12.c |
GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 |
DejaVu Sans 12 Anti-Aliased |
DejaVuSans12_aa |
DejaVuSans12_aa.c |
GDISP_INCLUDE_FONT_DEJAVUSANS12_AA |
DejaVu Sans 12 Anti-Aliased Bold |
DejaVuSansBold12_aa |
DejaVuSansBold12_aa.c |
GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA |
DejaVu Sans 16 |
DejaVuSans16 |
DejaVuSans16.c |
GDISP_INCLUDE_FONT_DEJAVUSANS16 |
DejaVu Sans 16 Anti-Aliased |
DejaVuSans16_aa |
DejaVuSans16_aa.c |
GDISP_INCLUDE_FONT_DEJAVUSANS16_AA |
DejaVu Sans 24 |
DejaVuSans24 |
DejaVuSans24.c |
GDISP_INCLUDE_FONT_DEJAVUSANS24 |
DejaVu Sans 24 Anti-Aliased |
DejaVuSans24_aa |
DejaVuSans24_aa.c |
GDISP_INCLUDE_FONT_DEJAVUSANS24_AA |
DejaVu Sans 32 |
DejaVuSans32 |
DejaVuSans32.c |
GDISP_INCLUDE_FONT_DEJAVUSANS32 |
DejaVu Sans 32 Anti-Aliased |
DejaVuSans32_aa |
DejaVuSans32_aa.c |
GDISP_INCLUDE_FONT_DEJAVUSANS32_AA |
Fixed 10×20 |
fixed_10×20 |
fixed_10×20.c |
GDISP_INCLUDE_FONT_FIXED_10X20 |
Fixed 7×14 |
fixed_7×14 |
fixed_7×14.c |
GDISP_INCLUDE_FONT_FIXED_7X14 |
Fixed 5×8 |
fixed_5×8 |
fixed_5×8.c |
GDISP_INCLUDE_FONT_FIXED_5X8 |
UI1 |
UI1 |
UI1.c |
GDISP_INCLUDE_FONT_UI1 |
UI1 Narrow |
UI1 Narrow |
UI2.c |
GDISP_INCLUDE_FONT_UI2 |
Large numbers |
LargeNumbers |
LargeNumbers.c |
GDISP_INCLUDE_FONT_LARGENUMBERS |
Если шрифт с указанным именем не существует, то API-функция gdispOpenFont() откроет шрифт, отображенный последним в конфигурационном файле gfxconf.h.
API-функция gdispOpenFont() возвращает переменную типа font_t — это дескриптор шрифта, который в дальнейшем следует использовать в качестве аргумента во всех API-функциях работы с текстом. Тип font_t представляет собой указатель на структуру mf_font_s, являющуюся частью библиотеки mcufont и содержащую всю необходимую для вывода шрифта информацию.
Структура mf_font_s занимает в памяти значительный по меркам микроконтроллеров объем, зависящий от нескольких факторов:
- Количество символов в шрифте.
- Размер (высота) шрифта.
- Наличие сглаживания (со сглаживанием шрифт занимает больше места).
Для экономии памяти после вывода текста можно освободить память, занимаемую структурой mf_font_s. Для освобождения ресурсов памяти, выделенных для открытого шрифта, его следует закрыть с помощью API-функции gdispCloseFont(font);
void gdispCloseFont(font_t font);
Вывод текста
После того как шрифт открыт API-функ-цией gdispOpenFont(), он может быть использован для вывода текстовой строки с помощью одной из API-функций вывода. Самая простая — gdispGDrawString(), она принимает координаты верхнего левого угла прямоугольной области, куда будет выведен текст (рис. 1). Высота этой области определяется высотой шрифта, а длина — количеством символов в выводимой строке. API-функция gdispOpenFont() имеет следующий прототип:
void gdispGDrawString( GDisplay *g, coord_t x0, coord_t y0, const char *str, font_t font, color_t color);
Аргументы API-функции gdispGDrawString():
- GDisplay *g — дескриптор дисплея, если используется несколько дисплеев, если дисплей один, то следует применить
API-функцию gdispDrawString(), которая отличается от gdispGDrawString() только отсутствием аргумента GDisplay *g. - coord_t x0, coord_t y0 — координаты верхнего левого угла прямоугольной области, куда будет выведена строка (рис. 1).
- const char *str — нуль-терминальная строка, которую требуется вывести на дисплей. Для представления символов за пределами ASCII набора (например, кириллицы) должна быть представлена в кодировке Unicode UTF‑8.
- font_t font — дескриптор шрифта, должен быть предварительно получен API-функцией gdispOpenFont().
- color_t color — цвет выводимой строки.
uGFX предоставляет также возможность вывести текст внутри прямоугольной области, все размеры и положение которой определяет программист, гарантируя, что текст не выйдет за пределы данной области (рис. 2). Для этого служит API-функция gdispGDrawStringBox(). Особенности ее работы:
- Строка всегда центрирована по высоте — находится посередине прямоугольной области.
- Есть возможность задать выравнивание по горизонтали: по левому краю, по правому краю или посередине.
- Нет переноса на новую строку. Если строка целиком не помещается в прямоугольную область, то выходящие за пределы символы отображены не будут.
- Не поддерживается отображение текста, состоящего из нескольких строк. Добавление в строку символа перехода на новую строку (управляющий символ «\n» в языке С) не приводит к появлению на дисплее двух строк.
Прототип API-функции gdispGDrawStringBox() следующий:
void gdispGDrawStringBox( GDisplay *g, coord_t x0, coord_t y0, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify);
Ее аргументы аналогичны аргументам API-функции gdispGDrawString() за исключением следующих:
- coord_t cx, coord_t cy — соответственно ширина и высота прямоугольной области, куда будет выведена строка (рис. 2);
- justify_t justify — тип выравнивания по горизонтали, может принимать следующие значения:
- justifyLeft — выравнивание по левому краю,
- justifyCenter — выравнивание по центру,
- justifyRight — выравнивание по правому краю.
API-функции gdispGDrawString() и gdispGDrawStringBox() выводят строки поверх изображения, имевшегося до их вызова на дисплее. В uGFX есть их аналоги — gdispGFillString() и gdispGFillStringBox(), заполняющие прямоугольную область, в которую выводится строка, заданным цветом фона:
void gdispGFillString( GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor); void gdispGFillStringBox( GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify);
Их прототипы отличаются от прототипов API-функций gdispGDrawString() и gdispGDrawStringBox() только наличием аргумента color_t bgcolor. Аргумент color_t bgcolor задает цвет, которым будет закрашена прямоугольная область перед выводом в нее текстовой строки.
Сглаживание шрифтов
Под сглаживанием шрифта в uGFX понимается устранение эффекта «зубчатости», возникающего на краях символов того или иного шрифта. Эффект «зубчатости» проявляется по контуру символа, если этот контур представляет собой кривую линию либо наклонную прямую (рис. 3а, [16]).
Сглаживание достигается за счет размещения на границе символа пикселей, которые имеют средний цвет между цветом самого символа и фона, на котором этот символ выводится (рис. 3б).
Сглаживание в uGFX реализовано на уровне шрифта — он может быть либо сглаженным, либо несглаженным. Для встроенного шрифта (таблица) наличие слов Anti-Aliased в его названии означает, что шрифт является сглаженным.
Использование сглаженных шрифтов должно быть разрешено в конфигурационном файле ugfxconf.h:
#define GDISP_NEED_ANTIALIAS TRUE
При выводе текста API-функциями, которые закрашивают фон под текстом (gdispGFillString() и gdispGFillStringBox()), сглаживание будет работать всегда при соблюдении условий, перечисленных выше.
Если требуется выводить сглаженный текст API-функциями gdispGDrawString() и gdispGDrawStringBox(), помимо прочего необходимо, чтобы драйвер контроллера дисплея поддерживал чтение цвета пикселей с дисплея, а также была разрешена API-функция чтения gdispGGetPixelColor() в конфигурационном файле ugfxconf.h:
#define GDISP_NEED_PIXELREAD TRUE
Попытка вывести сглаженный шрифт (например, встроенный “DejaVuSans32_aa”), если не соблюдается одно из приведенных выше условий, приведет к тому, что текст будет отображен, но шрифт будет выглядеть несглаженным.
Пример программы, выводящей сглаженный и несглаженный шрифт, приведен ниже:
font_t font1 = gdispOpenFont(“DejaVuSans32”); font_t font2 = gdispOpenFont(“DejaVuSans32_aa”); font_t font11 = gdispScaleFont(font1, 2, 2); font_t font22 = gdispScaleFont(font2, 2, 2); // Без сглаживания gdispDrawStringBox( 0, 0, 320, 34, “Anti-aliasing”, font1, Orange, justifyCenter); gdispDrawStringBox( 0, 34, 320, 68, “Off”, font11, Orange, justifyCenter); // Со сглаживанием gdispFillStringBox( 0, 122, 320, 34, “Anti-aliasing”, font2, Yellow, Black, justifyCenter); gdispFillStringBox( 0, 156, 320, 68, “On”, font22, Yellow, Black, justifyCenter);
Результат выполнения программы приведен на рис. 4. Чтобы эффект «зубчатости» был лучше заметен, шрифт для слов Off и On увеличен в два раза API-функцией gdispScaleFont() — подробнее об этой возможности ниже.
Кернинг
Кернинг — это избирательное уменьшение расстояния между некоторыми буквами с целью уплотнения текста. Кернинг возможен только для пропорциональных шрифтов, то есть тех, где разные символы имеют различную ширину. Принцип кернинга проиллюстрирован на рис. 5.
Функция кернинга является опциональной в uGFX, для включения кернинга в конфигурационном файле ugfxconf.h должна быть строка:
#define GDISP_NEED_TEXT_KERNING TRUE
На практике кернинг позволяет слегка уменьшить длину строки, это актуально при большом количестве символов в строке. На рис. 6а показан вывод строки на реальный дисплей с выключенным кернингом, на рис. 6б — с включенным.
Увеличение шрифта
В uGFX есть возможность увеличить имеющийся шрифт в целое число раз. Причем коэффициент увеличения задается отдельно по ширине и высоте символов. Для увеличения шрифта служит API-функция gdispScaleFont(), ее прототип:
font_t gdispScaleFont(font_t font, uint8_t scale_x, uint8_t scale_y);
Аргументы:
- font_t font — дескриптор шрифта, который надо увеличить;
- uint8_t scale_x, uint8_t scale_y — коэффициенты увеличения по горизонтали и вертикали соответственно.
API-функция gdispScaleFont() возвращает дескриптор вновь созданного шрифта, причем для его размещения выделяет новую память. Старый шрифт при этом также остается доступным.
Пример увеличения шрифта API-функци-ей gdispScaleFont():
font_t font1 = gdispOpenFont(“arial32”); font_t font2 = gdispScaleFont(font1, 2, 1); font_t font3 = gdispScaleFont(font1, 1, 2); font_t font4 = gdispScaleFont(font1, 2, 2); gdispDrawStringBox(0, 0, 320, 34, “Обычный шрифт”, font1, Orange, justifyCenter); gdispDrawStringBox(0, 50, 320, 34, “по ширине”, font2, Red, justifyCenter); gdispDrawStringBox(0, 84, 320, 68, “по высоте”, font3, Blue, justifyCenter); gdispDrawStringBox(0, 150, 320, 68, “оба”, font4, Green, justifyCenter);
Результат работы примера выше показан на рис. 7. Первая строка выведена обычным шрифтом Arial 32 (он не является встроенным, о том, как добавить свой шрифт, рассказано ниже). Вторая строка на рис. 7 сделана увеличенным в 2 раза по ширине шрифтом. Шрифт в третьей строке увеличен по высоте. Четвертая строка выведена шрифтом, увеличенным как по ширине, так и по высоте.
Дополнительные возможности
Получение ширины символа
Иногда необходимо знать, какую ширину займет тот или иной символ на дисплее при выводе его заданным шрифтом. Особенно полезным это может быть для пропорциональных шрифтов, то есть таких, у которых разные символы имеют разную ширину.
Получить ширину символа позволяет API-функция gdispGetCharWidth(), ее прототип:
coord_t gdispGetCharWidth(char c, font_t font);
Аргументы:
- char c — символ, ширину которого необходимо получить;
- font_t font — дескриптор шрифта, которым будет представлен символ.
Возвращаемое значение — ширина символа в пикселях.
Как видно из прототипа API-функции gdispGetCharWidth(), символ она получает через аргумент типа char. Это означает, что в функцию могут быть переданы только символы из набора ASCII, получение ширины для других символов Unicode (в том числе кириллических) невозможно.
Если требуется получить ширину, например, русской буквы, то можно воспользоваться функцией mf_character_width() библиотеки mcufont (на самом деле API-функция gdispGetCharWidth() является лишь ее «оберткой»). Функция mf_character_width() присутствует в дистрибутиве библиотеки uGFX и имеет следующий прототип:
uint8_t mf_character_width( const struct mf_font_s *font, mf_char character);
Функция mf_character_width() принимает символ с типом mf_char, который эквивалентен uint16_t, если в конфигурационном файле uGFX разрешено использование Unicode:
#define GDISP_NEED_UTF8 TRUE
Тип uint16_t для символа подразумевает использование кодировки Unicode UTF‑16, позволяющей закодировать и символы кириллицы. Поэтому если текстовый редактор среды разработки настроен на кодировку Unicode UTF‑8, то для получения ширины, например, русской буквы «Щ» следует передать в функцию mf_character_width() не саму букву «Щ», а ее код 1065:
font_t font2 = gdispOpenFont(“arial32”); // Правильно: uint8_t w = mf_character_width(font2, 1065); // Неправильно: uint8_t w = mf_character_width(font2, ‘Щ’);
Получение длины строки
В uGFX есть средство, позволяющее получить длину в пикселях целой строки при выводе ее заданным шрифтом. Это может быть полезно, когда требуется определить, уместится ли строка в заданную область на дисплее. Вычисление длины строки выполняет API-функция gdispGetStringWidth(), ее прототип:
coord_t gdispGetStringWidth(const char* str, font_t font);
Функция принимает следующие аргументы:
- const char* str — нуль-терминальная строка, длину которой требуется измерить;
- font_t font — дескриптор шрифта, которым будет выведена строка.
Возвращаемое значение — длина строки в пикселях.
Надо отметить, что описанных выше проблем с типом символа (как с API-функцией gdispGetCharWidth()) здесь нет, поскольку тип const char* позволяет передавать строки, кодированные в кодировке Unicode UTF‑8.
Получение подробной информации о шрифте
Есть возможность получения размеров различных элементов данного шрифта — например, расстояние между строками текста. Для получения такой информации служит API-функция gdispGetFontMetric(), имеющая следующий прототип:
coord_t gdispGetFontMetric(font_t font, fontmetric_t metric);
Ее аргументы:
- font_t font — дескриптор шрифта, информацию о котором надо получить;
- fontmetric_t metric — целочисленная константа, определяющая размер какого именно элемента должна вернуть API-функция gdispGetFontMetric().
Аргумент metric может принимать значения, определенные перечислением fontmetric_t:
- fontHeight — высота шрифта;
- fontDescendersHeight — размер нижнего выносного элемента;
- fontLineSpacing — межстрочный интервал;
- fontCharPadding — размер символа заполнения;
- fontMinWidth — минимальная ширина символа;
- fontMaxWidth — максимальная ширина символа.
API-функция gdispGetFontMetric() возвращает размер заданного аргументом metric элемента шрифта в пикселях.
Добавление новых шрифтов и кириллицы
uGFX содержит набор встроенных шрифтов различных начертаний и размеров, полный список которых приведен в таблице. Все встроенные шрифты, перечисленные в таблице, имеют существенный недостаток — они не содержат букв русского алфавита.
Тот факт, что, используя встроенные шрифты, невозможно вывести надпись на русском языке (и на любом другом с алфавитом, отличным от латиницы), а также желание вывести текст шрифтом большего размера или иного начертания, чем у шрифтов из набора встроенных, приводит к необходимости добавить свой собственный шрифт.
В uGFX есть возможность использовать помимо встроенных шрифтов, которые перечислены в таблице, собственные шрифты, содержащие не только буквы латинского алфавита, а вообще любые другие символы и буквы любого языка (например, символы кириллицы). Единственное требование — необходимые символы должны находиться в файле шрифта, представленном в одном из следующих форматов:
- TTF — векторный формат True Type;
- BDF — растровый формат шрифта, используемый преимущественно в операционных системах семейства Unix.
Однако uGFX не работает напрямую с приведенными выше форматами шрифтов, поскольку их вывод потребовал бы слишком много ресурсов микроконтроллера.
Вместо этого предлагается конвертировать шрифт из векторного формата во внутреннее растровое представление, сжатое для экономии памяти по алгоритму RLE [15]. При этом на этапе конвертации жестко фиксируется размер (высота букв) шрифта.
В результате конвертации из файла шрифта (с расширением TTF или BDF) получается файл исходных кодов языка С (с расширением C), который может быть легко добавлен в проект.
Онлайн-конвертер
На официальном сайте библиотеки uGFX [4] конвертацию предлагается выполнять с помощью онлайн-конвертера, чья интернет-страница доступна по адресу [3].
К сожалению, онлайн-конвертер работает неустойчиво [5], и автору также не удалось выполнить конвертацию с его помощью. Можно предположить, что неисправность будет со временем устранена и онлайн-версия конвертера будет работать исправно. А пока автор предлагает пойти другим путем — создать офлайн-версию конвертера в виде утилиты, выполняемой из командной строки операционной системы.
Конвертер в виде утилиты
На данный момент на официальном сайте uGFX не представлено ни исходных кодов, ни исполняемых файлов утилиты для конвертации файлов со шрифтами.
Однако на странице [1] библиотеки mcufont (которая используется в uGFX для вывода шрифтов) размещены исходные коды конвертера, доступные для свободного скачивания.
Поэтому автор предлагает скомпилировать утилиту для конвертации самостоятельно и ниже приводит подробные инструкции, как это можно сделать. Далее предполагается, что на рабочем компьютере установлена операционная система Windows 7. Если же установлена Ubuntu (или иная ОС из семейства Linux), это значительно упростит компиляцию утилиты.
Исходный код конвертера написан на языке C++ стандарта C++11 (или ISO/IEC 14882:2011). Кроме этого, предполагается использование для сборки пакета GCC (GNU Compiler Collection) — вместе с файлами с исходным кодом находится файл Makefile.
Теоретически сборку такого проекта можно выполнить операционной системой Windows, поскольку существует не одна реализация пакета GCC для Windows, например MinGW [6].
Однако на практике автор столкнулся с целым рядом проблем при попытке собрать утилиту для Windows. Прежде всего, проблемы вызвало наличие в исходном коде вызовов функции std::stoi() и некоторых других. Эти функции входят в стандартную библиотеку языка С++ и появились в ней начиная со стандарта C++11. Оказалось, данные функции не реализованы в пакете MinGW (версия GCC 4.8.1). Это означало бы необходимость заменять их вызовы в исходном коде утилиты на свой код.
При дальнейшем изучении библиотеки mcufont выяснилось, что она использует части библиотеки FreeType 2 [7] и для сборки утилиты-конвертера требуется запуск утилиты freetype-config, предназначенной для запуска в среде Linux.
Все эти трудности исчезают, если собирать утилиту в операционной системе Linux. Поэтому, если на рабочем компьютере установлена Windows, имеет смысл создать виртуальную машину, затем установить на нее Linux, собрать утилиту-конвертер и в дальнейшем конвертировать шрифты во внутренний формат библиотеки uGFX в среде Linux.
Если же на рабочем компьютере установлена Linux, то шаг с созданием виртуальной машины и установкой на нее Linux можно пропустить.
Установка Linux на виртуальную машину
Автор предлагает использовать виртуальную машину Virtual Box от компании Oracle, которую можно бесплатно скачать с сайта [8]. Автор использовал версию Virtual Box 4.3.20. Процесс установки виртуальной машины Virtual Box тривиальный и не отличается от установки любой другой программы для Windows.
Далее следует установить Linux на виртуальную машину. Автор выбрал популярный дистрибутив Ubuntu версия 14.04.1 LTS. Бесплатно загрузить Ubuntu можно со страницы [9], в результате загрузки должен быть получен файл ubuntu‑14.04.1‑desktop-i386.iso — это образ установочного диска.
Затем в Virtual Box нужно создать новую виртуальную машину, для этого в главном меню надо выбрать пункт «Машина», потом — «Создать…». На экране появится диалог (рис. 8), в котором следует выбрать тип операционной системы Linux, версия — “Ubuntu (32bit)” или “Ubuntu (64bit)” в зависимости от разрядности установленной Windows.
Потом будет предложено установить объем памяти, который будет использоваться виртуальной машиной (рис. 9). Автор установил объем, равный 1024 Мбайт.
Далее последовательно будут появляться диалоги с настройками виртуального жесткого диска (рис. 10–13), настройки можно выбрать такие, как показано на рис. 10–13.
Когда виртуальная машина создана, следует выбрать пункт главного меню «Машина», затем — «Запустить». Virtual Box предложит выбрать образ установочного диска (рис. 14).
Следует выбрать загруженный ранее файл ubuntu‑14.04.1‑desktop-i386.iso, после чего начнется установка Ubuntu на только что созданную виртуальную машину. В процессе установки будет предложен выбор языка (рис. 15).
Следует выбрать русский язык и нажать кнопку «Установить Ubuntu». Далее в процессе установки будет предложено задать имя компьютера, пусть это будет «vm», а также имя пользователя и пароль. Автор задал имя пользователя «andy».
По окончании установки получим работающую операционную систему Ubuntu на виртуальной машине Virtual Box (рис. 16).
После этого следует установить дополнения, расширяющие возможности Ubuntu при работе на виртуальной машине Virtual Box. Для этого в Virtual Box надо выбрать пункт главного меню «Устройства», далее — «Подключить образ диска Дополнений гостевой ОС…». После установки следует перезагрузить виртуальную машину.
На этом этап установки операционной системы Ubuntu на виртуальную машину, которая работает в среде Windows 7, можно считать законченным.
Отдельно стоит коснуться вопроса, как перемещать файлы между основной операционной системой (Windows 7) и гостевой, выполняющейся на виртуальной машине Ubuntu. Есть возможность, как описано в [10], настроить общую папку, доступную как из основной, так и из гостевой операционной системы. Автор же для этой цели использовал USB флэш-накопитель, который можно подключить к виртуальной машине, выбрав соответствующий пункт меню.
Компиляция конвертера
Все действия, рассмотренные ниже, должны выполняться в среде операционной системы Ubuntu. Необходимо также, чтобы компьютер был подключен к сети Интернет — для скачивания недостающих пакетов. Кроме этого, большинство операций выполняется в терминале, вызвать который в Ubuntu можно, нажав на клавиатуре Ctrl-Alt-T.
Исходный код конвертера вместе с остальными частями библиотеки mcufont находится по адресу [1]. Однако непосредственно загрузить его с помощью браузера невозможно. Дело в том, что исходный код находится в удаленном репозитории системы управления версиями Git.
Для того чтобы загрузить исходный код mcufont на компьютер, необходимо предварительно установить систему управления версиями Git. Сделать это в среде Ubuntu очень просто, достаточно выполнить в терминале следующую команду:
sudo apt-get install git
После того как Git установлен, можно загрузить на свой компьютер исходный код библиотеки mcufont, выполнив в терминале следующую команду:
git clone https://code.google.com/p/mcufont/
По окончании загрузки в домашней папке должна появиться папка mcufont с исходным кодом библиотеки mcufont. В папке mcufont находится папка encoder, которая содержит исходный код для сборки конвертера.
Как уже упоминалось, mcufont использует библиотеку Freetype 2 — файл Makefile в папке encoder содержит следующие строки:
CXXFLAGS += $(shell freetype-config --cflags) LDFLAGS += $(shell freetype-config --libs)
которые предписывают компилятору подключить заголовочные файлы, а компоновщику — готовые объектные модули из библиотеки Freetype. Для получения путей к компонентам Freetype используется вызов утилиты freetype-config.
Для загрузки библиотеки Freetype в том виде, в котором требует ее наличия библиотека mcufont, необходимо установить программный пакет libfreetype6‑dev. Сделать это в Ubuntu можно, выполнив в терминале:
sudo apt-get install libfreetype6-dev
После установки пакета в системе должна стать доступной утилита freetype-config (можно проверить, выполнив ее в терминале).
После того как Freetype установлена, необходимо установить недостающий компилятор языка C++ (для пакета GCC он называется g++) и утилиту make (также из пакета GCC), сделать это можно, выполнив в терминале следующую команду:
sudo apt-get install build-essential
По окончании установки пакетов следует проверить наличие компилятора, выполнив в терминале команды g++ и make. В ответ не должно быть сообщений о неустановленной или ненайденной программе.
Теперь все недостающие пакеты установлены, и можно приступать непосредственно к сборке утилиты конвертера mcufont. Для этого следует зайти в директорию ~/mcufont/encoder:
andy@vm:~$ cd mcufont/encoder
и выполнить сборку конвертера mcufont:
andy@vm:~/mcufont/encoder$ make mcufont
В результате в папке ~/mcufont/encoder должен появиться исполняемый файл конвертера с именем mcufont. Проверить его наличие можно, выполнив команду:
andy@vm:~/mcufont/encoder$ ls mcufont
на дисплее должно появиться:
mcufont
Читатель может загрузить готовый исполняемый файл утилиты-конвертера по адресу [18]. Следует помнить, что исполняемый файл предназначен для запуска в среде операционной системы Ubuntu (возможно, утилита будет работать и в других операционных системах семейства Linux — автор такую возможность не проверял).
Конвертация
На примере популярного шрифта Times New Roman покажем, как его конвертировать, добавить в проект, использующий библиотеку uGFX, и как вывести надпись на кириллице, сделав это с помощью добавленного шрифта. Конвертация производится полученной ранее утилитой-конвертером mcufont.
Процесс конвертации состоит из нескольких этапов и схематично показан на рис. 17.
Прежде всего, необходимо получить файл в формате TrueType, содержащий целевой шрифт (Times New Roman в нашем примере). В операционной системе Windows 7 этот файл уже есть, он называется times.ttf и находится в папке C:\Windows\Fonts.
Далее файл нужно скопировать в папку с конвертером. В нашем случае эта папка ~/mcufont/encoder уже в операционной системе Ubuntu (как переносить файлы между основной и гостевой операционной системой, рассказано выше).
Конвертер не имеет графического интерфейса пользователя, для управления конвертацией необходимо задавать параметры в командной строке Ubuntu. Все дальнейшие действия подразумевают, что текущим каталогом является ~/mcufont/encoder, приглашение должно выглядеть подобным такому:
andy@vm:~/mcufont/encoder$
Если это не так, следует в терминале войти в каталог ~/mcufont/encoder, выполнив:
cd ~/mcufont/encoder
Конвертация в промежуточный файл с расширением .dat производится командой:
./mcufont import_ttf times.ttf 72
где параметр «import_ttf» задает конвертацию в промежуточный файл, параметр «times.ttf» — имя файла с конвертируемым шрифтом, параметр «72» — размер (высота) конвертированного шрифта в пикселях.
По завершении процесса конвертации в терминал будет выведено:
Importing times.ttf to times72.dat Done: 2503 unique glyphs.
Это означает, что шрифт успешно конвертирован в промежуточный файл times72.dat, общее количество символов в промежуточном файле — 2503.
Растровое представление такого количества символов, да еще с высотой в 72 пикселя, потребует очень большого по меркам микроконтроллеров объема памяти (даже с учетом того, что растры сжаты по алгоритму RLE).
Поэтому следующим шагом будет удаление лишних, неиспользуемых символов из промежуточного файла times72.dat.
Все символы как в исходном шрифте в формате TrueType, так и в промежуточном файле times72.dat пронумерованы в соответствии со стандартом кодирования Unicode [11]. Причем кодовое пространство поделено на несколько областей, каждая из которых соответствует тому или иному языку или системе знаков. Удаление лишних символов сводится к указанию диапазона кодов символов, которые должны остаться в промежуточном файле.
Все символы русского алфавита находятся в диапазоне кодов от 1040 до 1103 [12]. Печатаемые символы латинского алфавита и знаки из набора ASCII занимают диапазон от 32 до 126 [11]. Чтобы удалить из промежуточного файла все символы, кроме указанных выше, следует выполнить команду:
./mcufont filter times72.dat 32-126 1040-1103
где параметр «filter» — указание утилите убрать лишние символы, параметр «times72.dat» — имя промежуточного файла, параметры «32–126» и «1040–1103» — диапазоны кодов символов, которые должны остаться в файле. Числа задаются в десятичной системе счисления, можно задавать один или несколько диапазонов.
В результате выполнения команды на дисплей будет выведено:
Font originally had 2503 glyphs. After filtering, 142 glyphs remain.
Это значит, что только 142 символа осталось в промежуточном файле.
Следующий шаг — оптимизация промежуточного файла с целью уменьшить размер памяти, занимаемый шрифтом. Этот процесс итеративный, каждая новая итерация приводит к сокращению занимаемого шрифтом объема памяти.
Для запуска процесса оптимизации следует выполнить команду:
./mcufont rlefont_optimize times72.dat
На дисплей будет выведено:
Original size is 113363 bytes Press ctrl-C at any time to stop. Results are saved automatically after each iteration. Limit is 100 iterations iteration 1, size 59416 bytes, speed 359646 B/min iteration 2, size 51686 bytes, speed 205590 B/min iteration 3, size 47085 bytes, speed 159067 B/min iteration 4, size 44346 bytes, speed 118314 B/min ^C
Каждая следующая итерация сокращает размер файла, однако эффективность сжатия с каждой новой итерацией падает. Кроме того, с каждой новой итерацией увеличивается время ее выполнения. Поэтому процесс оптимизации можно прервать, когда каждая новая итерация сокращает размер файла на единицы-десятки байт. Чтобы прервать процесс оптимизации, следует нажать на клавиатуре комбинацию Ctrl+C. Автор добивался уменьшения размера файла более чем в 3 раза при количестве итераций около 20.
После оптимизации промежуточного файла следующим шагом является преобразование его в файл исходного кода языка С. Чтобы это сделать, необходимо выполнить команду:
./mcufont rlefont_export times72.dat
В итоге в текущем каталоге будет создан конечный файл times72.c, готовый для добавления в uGFX и содержащий конвертированный шрифт Times New Roman с высотой букв в 72 пикселя.
Получение несглаженного шрифта
По умолчанию конвертированный описанным выше способом шрифт будет сглаженным. Если требуется создать несглаженный шрифт, то к команде конвертации в промежуточный файл следует добавить ключ «bw»:
./mcufont import_ttf times.ttf 72 bw
Далее процесс практически ничем не отличается, единственная разница — имя шрифта, промежуточного и конечного файла будет c суффиксом «bw»: «times72bw», times72bw.dat и times72bw.c соответственно.
Несглаженный шрифт занимает гораздо меньший объем памяти, чем сглаженный. Так, в рассмотренном выше примере объем памяти для хранения сглаженного шрифта составил 44 271 байт, а для хранения несглаженного — 24 575 байт (размер указан после пятикратной оптимизации для обоих шрифтов).
Интеграция шрифта в проект на uGFX
Когда файл шрифта с расширением *.c получен, его можно добавить в свой проект, который использует библиотеку uGFX. Как это сделать, показано на примере среды разработки CooCox CoIDE, подробно о настройке среды разработки и используемой аппаратной платформе можно прочитать в [14].
Прежде всего, полученный файл шрифта (times72.c в нашем случае) следует скопировать в директорию, содержащую остальные файлы проекта, добавлять его в проект CooCox CoIDE не следует, иначе возникнут ошибки сборки проекта.
Затем нужно создать новый заголовочный файл userfonts.h в том же месте, куда был скопирован файл шрифта times72.c. Файл userfonts.h можно добавить в проект и написать в нем директиву включения в сборку файла шрифта:
#include “times72.c”
Далее необходимо настроить uGFX на применение пользовательских шрифтов, для этого в конфигурационный файл gfxconf.h надо добавить следующие строки:
#define GDISP_NEED_TEXT TRUE #define GDISP_NEED_UTF8 TRUE #define GDISP_INCLUDE_USER_FONTS TRUE
После этого нужно выяснить имя шрифта, которое будет использоваться при открытии шрифта API-функцией gdispOpenFont(). В файле шрифта times72.c следует отыскать определение структуры mf_rlefont_s, второе поле этой структуры и будет строка, определяющая имя шрифта:
const struct mf_rlefont_s mf_rlefont_times72 = { { “Times New Roman Regular 72”, “times72”, 79, /* width */ 80, /* height */ ...
В нашем случае имя шрифта совпадает с названием файла: times72.
Еще одним подготовительным шагом является переключение кодировки текстового редактора в среде разработки (IDE) в режим UTF‑8. Это необходимо для того, чтобы текстовые строки на русском языке (или другом с символами, отличными от латинского алфавита), предназначенные для отображения на дисплее микроконтроллерного устройства, можно было вводить прямо в текстовом редакторе среды разработки.
Для среды разработки CooCox CoIDE переключение кодировки можно сделать, выбрав пункт главного меню Edit -> Preferences. Далее следует выбрать пункт General, потом — Workspace, после чего установить параметр Text file encoding в значение UTF‑8 (рис. 18).
На этом этапе можно считать, что пользовательский шрифт добавлен в проект и все настройки для его применения сделаны. Чтобы проверить это, достаточно вывести какое-либо сообщение с помощью имени пользовательского шрифта (times72). Пример содержимого файла main.c для проверки нового шрифта:
#include “gfx.h” #include “stm32f10x.h” int main(void) { gfxInit(); font_t font = gdispOpenFont(“times72”); gdispDrawString(0, 0, “настройка”, font, Yellow); gdispDrawString(0, 74, “ датчика”, font, Blue); gdispDrawString(0, 148, “ ждите...”, font, Red); while(TRUE) { gfxSleepMilliseconds(1000); } }
Для аппаратной платформы, описанной в [14], результат работы программы показан на рис. 19.
Добавить в шрифт различные технические, математические и другие специальные символы, например знак градуса или знак диаметра, — не проблема. Сделать это можно на этапе удаления из промежуточного файла неиспользуемых символов, например, так:
./mcufont filter arial32.dat 32-126 1040-1103 176-179 181 197 8960
Коды символов, которые останутся в шрифте:
- 176–179 соответствуют знакам «градус», «плюс-минус», «возведение в квадрат», «возведение в куб»;
- 181 — символ «микро»;
- 197 соответствует знаку «ангстрем»;
- 8960 — знак диаметра.
На рис. 20 показан пример вывода специальных символов полученным шрифтом на реальный дисплей.
Заключение
Библиотека uGFX показала богатые возможности для вывода текста и работы со шрифтами. Большим преимуществом является возможность добавления своих шрифтов, содержащих в том числе и буквы кириллицы. Поддержка сглаженных шрифтов — также большой плюс в копилку достоинств библиотеки uGFX.
Из минусов следует отметить невозможность «развернуть» надпись на 90°, отсутствие API-функций, которые выводили бы многострочный текст, а также то, что в дистрибутиве uGFX изначально отсутствует утилита для конвертирования шрифтов во внутренний формат. Хотя последний недостаток можно таковым не считать — ведь получение утилиты-конвертера было детально описано в данной статье.
- code.google.com/p/mcufont/ссылка утрачена/
- Курниц А. uGFX — графическая библиотека для микроконтроллеров // Компоненты и технологии. 2014. № 10.
- ugfx.org/fontconvert.php/ссылка утрачена/
- wiki.ugfx.org/index.php?title=Font_rendering/ссылка утрачена/
- www.forum.ugfx.org/viewtopic.php?f=23&t=56&hilit=fontconvert /ссылка утрачена/
- www.mingw.org/
- www.ru.wikipedia.org/wiki/FreeType/ссылка утрачена/
- www.www.virtualbox.org/wiki/Downloads /ссылка утрачена/
- ubuntu.ru/get
- www.aboutubuntu.ru/content/nastroika-virtualnoi-mashiny-virtualbox-s‑gostevoi-ubuntu-na-windows-khoste
- www.unicode-table.com/ru/
- www.en.wikipedia.org/wiki/Cyrillic_(Unicode_block)/ссылка утрачена/
- www.ru.wikipedia.org/wiki/Кириллица_в_Юникоде /ссылка утрачена/
- Курниц А. uGFX — графическая библиотека для микроконтроллеров // Компоненты и технологии. 2014. № 11.
- ru.wikipedia.org/wiki/Кодирование_длин_серий /ссылка утрачена/
- webstyleguide.com/wsg2/type/graphics.html
- kit-e.ru/files/ugfx2.2_stm32.zip /ссылка утрачена/
- kit-e.ru/files/mcufont.zip /ссылка утрачена/