uGFX — графическая библиотека для микроконтроллеров. Часть 4

№ 4’2015
PDF версия
Статья продолжает знакомить читателя с графической библиотекой uGFX. На этот раз речь пойдет о возможностях вывода текста различными шрифтами, отдельно затронут вопрос о поддержке русского языка. Показано, как конвертировать любой векторный шрифт TrueType во внутренний формат uGFX и использовать его для вывода текста.

Все статьи цикла

Возможности вывода текста

Графическая библиотека 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

Шрифт

Его имя в 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 занимает в памяти значительный по меркам микроконтроллеров объем, зависящий от нескольких факторов:

  1. Количество символов в шрифте.
  2. Размер (высота) шрифта.
  3. Наличие сглаживания (со сглаживанием шрифт занимает больше места).

Для экономии памяти после вывода текста можно освободить память, занимаемую структурой mf_font_s. Для освобождения ресурсов памяти, выделенных для открытого шрифта, его следует закрыть с помощью API-функции gdispCloseFont(font);

void gdispCloseFont(font_t font);

Вывод текста

После того как шрифт открыт API-функ-цией gdispOpenFont(), он может быть использован для вывода текстовой строки с помощью одной из API-функций вывода. Самая простая — gdispGDrawString(), она принимает координаты верхнего левого угла прямоугольной области, куда будет выведен текст (рис. 1). Высота этой области определяется высотой шрифта, а длина — количеством символов в выводимой строке. API-функция gdispOpenFont() имеет следующий прототип:

Вывод строки с помощью API-функции gdispGDrawString()

Рис. 1. Вывод строки с помощью API-функции gdispGDrawString()

void gdispGDrawString(
        GDisplay *g,
        coord_t x0, coord_t y0,
        const char *str,
        font_t font,
        color_t color);

Аргументы API-функции gdispGDrawString():

  1. GDisplay *g — дескриптор дисплея, если используется несколько дисплеев, если дисплей один, то следует применить
    API-функцию gdispDrawString(), которая отличается от gdispGDrawString() только отсутствием аргумента GDisplay *g.
  2. coord_t x0, coord_t y0 — координаты верхнего левого угла прямоугольной области, куда будет выведена строка (рис. 1).
  3. const char *str — нуль-терминальная строка, которую требуется вывести на дисплей. Для представления символов за пределами ASCII набора (например, кириллицы) должна быть представлена в кодировке Unicode UTF‑8.
  4. font_t font — дескриптор шрифта, должен быть предварительно получен API-функцией gdispOpenFont().
  5. color_t color — цвет выводимой строки.

uGFX предоставляет также возможность вывести текст внутри прямоугольной области, все размеры и положение которой определяет программист, гарантируя, что текст не выйдет за пределы данной области (рис. 2). Для этого служит API-функция gdispGDrawStringBox(). Особенности ее работы:

Вывод строки в прямоугольной области с помощью API-функции gdispGDrawStringBox()

Рис. 2. Вывод строки в прямоугольной области с помощью API-функции gdispGDrawStringBox()

  1. Строка всегда центрирована по высоте — находится посередине прямоугольной области.
  2. Есть возможность задать выравнивание по горизонтали: по левому краю, по правому краю или посередине.
  3. Нет переноса на новую строку. Если строка целиком не помещается в прямоугольную область, то выходящие за пределы символы отображены не будут.
  4. Не поддерживается отображение текста, состоящего из нескольких строк. Добавление в строку символа перехода на новую строку (управляющий символ «\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() за исключением следующих:

  1. coord_t cx, coord_t cy — соответственно ширина и высота прямоугольной области, куда будет выведена строка (рис. 2);
  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. Разница между:
а) несглаженным;
б) сглаженным шрифтом

Сглаживание достигается за счет размещения на границе символа пикселей, которые имеют средний цвет между цветом самого символа и фона, на котором этот символ выводится (рис. 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() — подробнее об этой возможности ниже.

Вывод текста несглаженным и сглаженным шрифтом на реальном дисплее

Рис. 4. Вывод текста несглаженным и сглаженным шрифтом на реальном дисплее

Кернинг

Кернинг — это избирательное уменьшение расстояния между некоторыми буквами с целью уплотнения текста. Кернинг возможен только для пропорциональных шрифтов, то есть тех, где разные символы имеют различную ширину. Принцип кернинга проиллюстрирован на рис. 5.

Принцип работы кернинга — уплотнение текста

Рис. 5. Принцип работы кернинга — уплотнение текста

Функция кернинга является опциональной в uGFX, для включения кернинга в конфигурационном файле ugfxconf.h должна быть строка:

#define GDISP_NEED_TEXT_KERNING TRUE

На практике кернинг позволяет слегка уменьшить длину строки, это актуально при большом количестве символов в строке. На рис. 6а показан вывод строки на реальный дисплей с выключенным кернингом, на рис. 6б — с включенным.

Вывод текста

Рис. 6. Вывод текста:
а) без кернинга;
б) с кернингом

Увеличение шрифта

В uGFX есть возможность увеличить имеющийся шрифт в целое число раз. Причем коэффициент увеличения задается отдельно по ширине и высоте символов. Для увеличения шрифта служит API-функция gdispScaleFont(), ее прототип:

font_t gdispScaleFont(font_t font, uint8_t scale_x, uint8_t scale_y);

Аргументы:

  1. font_t font — дескриптор шрифта, который надо увеличить;
  2. 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 раза по ширине шрифтом. Шрифт в третьей строке увеличен по высоте. Четвертая строка выведена шрифтом, увеличенным как по ширине, так и по высоте.

Возможность увеличения шрифта в uGFX

Рис. 7. Возможность увеличения шрифта в uGFX

 

Дополнительные возможности

Получение ширины символа

Иногда необходимо знать, какую ширину займет тот или иной символ на дисплее при выводе его заданным шрифтом. Особенно полезным это может быть для пропорциональных шрифтов, то есть таких, у которых разные символы имеют разную ширину.

Получить ширину символа позволяет 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);

Функция принимает следующие аргументы:

  1. const char* str — нуль-терминальная строка, длину которой требуется измерить;
  2. font_t font — дескриптор шрифта, которым будет выведена строка.

Возвращаемое значение — длина строки в пикселях.

Надо отметить, что описанных выше проблем с типом символа (как с API-функцией gdispGetCharWidth()) здесь нет, поскольку тип const char* позволяет передавать строки, кодированные в кодировке Unicode UTF‑8.

 

Получение подробной информации о шрифте

Есть возможность получения размеров различных элементов данного шрифта — например, расстояние между строками текста. Для получения такой информации служит API-функция gdispGetFontMetric(), имеющая следующий прототип:

coord_t gdispGetFontMetric(font_t font, fontmetric_t metric);

Ее аргументы:

  1. font_t font — дескриптор шрифта, информацию о котором надо получить;
  2. fontmetric_t metric — целочисленная константа, определяющая размер какого именно элемента должна вернуть API-функция gdispGetFontMetric().

Аргумент metric может принимать значения, определенные перечислением fontmetric_t:

  1. fontHeight — высота шрифта;
  2. fontDescendersHeight — размер нижнего выносного элемента;
  3. fontLineSpacing — межстрочный интервал;
  4. fontCharPadding — размер символа заполнения;
  5. fontMinWidth — минимальная ширина символа;
  6. 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.

Выбор типа новой виртуальной машины

Рис. 8. Выбор типа новой виртуальной машины

Потом будет предложено установить объем памяти, который будет использоваться виртуальной машиной (рис. 9). Автор установил объем, равный 1024 Мбайт.

Настройка объема оперативной памяти

Рис. 9. Настройка объема оперативной памяти

Далее последовательно будут появляться диалоги с настройками виртуального жесткого диска (рис. 10–13), настройки можно выбрать такие, как показано на рис. 10–13.

Создание виртуального жесткого диска

Рис. 10. Создание виртуального жесткого диска

Выбор типа виртуального жесткого диска

Рис. 11. Выбор типа виртуального жесткого диска

Задание способа размещения файла с виртуальным диском

Рис. 12. Задание способа размещения файла с виртуальным диском

Задание имени файла с виртуальным диском и его размера

Рис. 13. Задание имени файла с виртуальным диском и его размера

Когда виртуальная машина создана, следует выбрать пункт главного меню «Машина», затем — «Запустить». Virtual Box предложит выбрать образ установочного диска (рис. 14).

Выбор образа установочного диска

Рис. 14. Выбор образа установочного диска

Следует выбрать загруженный ранее файл ubuntu‑14.04.1‑desktop-i386.iso, после чего начнется установка Ubuntu на только что созданную виртуальную машину. В процессе установки будет предложен выбор языка (рис. 15).

Выбор языка и способа и варианта запуска или установки

Рис. 15. Выбор языка и способа и варианта запуска или установки

Следует выбрать русский язык и нажать кнопку «Установить Ubuntu». Далее в процессе установки будет предложено задать имя компьютера, пусть это будет «vm», а также имя пользователя и пароль. Автор задал имя пользователя «andy».

По окончании установки получим работающую операционную систему Ubuntu на виртуальной машине Virtual Box (рис. 16).

Работа Ubuntu на виртуальной машине

Рис. 16. Работа Ubuntu на виртуальной машине

После этого следует установить дополнения, расширяющие возможности 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 во внутренний формат библиотеки uGFX

Рис. 17. Схема конвертации шрифта из формата TrueType во внутренний формат библиотеки uGFX

Прежде всего, необходимо получить файл в формате 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).

Настройка среды разработки для использования кодировки UTF 8

Рис. 18. Настройка среды разработки для использования кодировки UTF 8

На этом этапе можно считать, что пользовательский шрифт добавлен в проект и все настройки для его применения сделаны. Чтобы проверить это, достаточно вывести какое-либо сообщение с помощью имени пользовательского шрифта (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.

Вывод сообщения на русском языке

Рис. 19. Вывод сообщения на русском языке

Добавить в шрифт различные технические, математические и другие специальные символы, например знак градуса или знак диаметра, — не проблема. Сделать это можно на этапе удаления из промежуточного файла неиспользуемых символов, например, так:

./mcufont filter arial32.dat 32-126 1040-1103 176-179 181 197 8960

Коды символов, которые останутся в шрифте:

  • 176–179 соответствуют знакам «градус», «плюс-минус», «возведение в квадрат», «возведение в куб»;
  • 181 — символ «микро»;
  • 197 соответствует знаку «ангстрем»;
  • 8960 — знак диаметра.

На рис. 20 показан пример вывода специальных символов полученным шрифтом на реальный дисплей.

Вывод специальных символов шрифтом Arial

Рис. 20. Вывод специальных символов шрифтом Arial

 

Заключение

Библиотека uGFX показала богатые возможности для вывода текста и работы со шрифтами. Большим преимуществом является возможность добавления своих шрифтов, содержащих в том числе и буквы кириллицы. Поддержка сглаженных шрифтов — также большой плюс в копилку достоинств библиотеки uGFX.

Из минусов следует отметить невозможность «развернуть» надпись на 90°, отсутствие API-функций, которые выводили бы многострочный текст, а также то, что в дистрибутиве uGFX изначально отсутствует утилита для конвертирования шрифтов во внутренний формат. Хотя последний недостаток можно таковым не считать — ведь получение утилиты-конвертера было детально описано в данной статье.

Литература
  1. code.google.com/p/mcufont/ссылка утрачена/
  2. Курниц А. uGFX — графическая библиотека для микроконтроллеров // Компоненты и технологии. 2014. № 10.
  3. ugfx.org/fontconvert.php/ссылка утрачена/
  4. wiki.ugfx.org/index.php?title=Font_rendering/ссылка утрачена/
  5. www.forum.ugfx.org/viewtopic.php?f=23&t=56&hilit=fontconvert /ссылка утрачена/
  6. www.mingw.org/
  7. www.ru.wikipedia.org/wiki/FreeType/ссылка утрачена/
  8. www.www.virtualbox.org/wiki/Downloads /ссылка утрачена/
  9. ubuntu.ru/get
  10. www.aboutubuntu.ru/content/nastroika-virtualnoi-mashiny-virtualbox-s‑gostevoi-ubuntu-na-windows-khoste
  11. www.unicode-table.com/ru/
  12. www.en.wikipedia.org/wiki/Cyrillic_(Unicode_block)/ссылка утрачена/
  13. www.ru.wikipedia.org/wiki/Кириллица_в_Юникоде /ссылка утрачена/
  14. Курниц А. uGFX — графическая библиотека для микроконтроллеров // Компоненты и технологии. 2014. № 11.
  15. ru.wikipedia.org/wiki/Кодирование_длин_серий /ссылка утрачена/
  16. webstyleguide.com/wsg2/type/graphics.html
  17. kit-e.ru/files/ugfx2.2_stm32.zip /ссылка утрачена/
  18. kit-e.ru/files/mcufont.zip /ссылка утрачена/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *