Если в шрифте определять все 256 символов, он будет занимать приличное количество флеша, который можно использовать в более благих целях. Поэтому я решил подойти со стороны индексирования лишь тех символов, которые реально в шрифте определены (а в тех же МК зачастую определяется лишь очень скудный набор - все символы таблицы КОИ8-Р обычно не нужны).
Мне как-то mbr подсказал программку "lcd image converter" (в ответ на мое описание веб-морды велосипеда для генерирования шрифтов). Пока вожусь со светодиодной панелью, мне понадобилось сделать набор из нескольких шрифтов для цифр разного размера, вот я и вспомнил про эту штуку. Она достаточно хорошо преобразует в растр разные шрифты, а дальше остается лишь набить вручную все в файле с исходниками.
Саму идею (как и основной шрифт величиной 12 пикселей) я стащил где-то на просторах интернета (Nadyrshin Ruslan, youtube). Но там подход был "в лоб": надо 256 символов — значит, столько места и займем (хоть половина пустая). Меняем подход.
Итак, нужно нам не так уж и много. Сначала заведем заголовочный файл fonts.h, где определим перечень имеющихся шрифтов, базовые функции и структуру, характеризующую шрифт:
Глобальная постоянная curfont является указателем на текущий используемый шрифт (задается он командой choose_font, далее описываю содержимое файла fonts.c):
Если шрифт не найден, возвращается единица. Если все ОК — нуль.
Функция font_char позволяет получить доступ к нужному символу:
Если символ не найден, возвращается NULL. Если найден — указатель на него (первым байтом идет ширина символа в пикселях, далее — данные самого символа).
Еще в файл fonts.c нужно поместить массив — все существующие шрифты:
(ну и сам указатель на текущий шрифт).
Но в самом начале этого файла надо перечислить дефайны для удобства рисования. Я не буду все эти 256 строк включать, а только приведу скрипт, генерирующий их:
Сразу после этого включаем все файлы со шрифтами:
Ну а потом уже пишем то, что я выше привел.
Содержимое каждого файла со шрифтами несложно нарисовать. Во-первых, это нужные дефайны:
Во-вторых, таблица для перекодировки (своя для каждого шрифта):
Здесь определены маленькие цифры (10 пикселей высотой), поэтому почти вся таблица — нули. Зато очень приличная экономия памяти получается.
Сам этот шрифт — в константе fontNumb10_table[]. Первым ее элементом обязательно должен идти символ-пустышка с нулевой шириной, а дальше — определяемые символы. Скажем, для этого шрифта начало данного массива имеет вид
Руслан Надыршин подсказал превосходнейший способ визуализации данных! Мы просто определяем 256 макросов для каждого числа, вместо нуля симпол подчеркивания, вместо единицы — X. И можно прямо в исходниках рисовать символы.
Другой шрифт с цифрами имеет высоту 16 пикселей — на всю высоту экрана. Поэтому там символы выглядят как-то так:
А в оригинальном шрифте буквы занимают по высоте почти все 16 пикселей (у некоторых вниз выползает хвостик, у некоторых — вверх). И выглядят они уже вот так:
Здесь, правда, приходится разделять байты запятыми, что немножко ломает наглядность. Но определять 65536 макросов что-то не хочется: боюсь, что сборка в этом случае затянется...
Вот на таких широченных шрифтах 16х16 пикселей экономия флеша при индексации получается вполне приличной: ведь один символ занимает 33 байта, а таблица с индексами — 256. Если в шрифте не определено 8 символов, индексация уже экономит немного места. А если там определено лишь полтора десятка, так совсем прилично!
Мне как-то mbr подсказал программку "lcd image converter" (в ответ на мое описание веб-морды велосипеда для генерирования шрифтов). Пока вожусь со светодиодной панелью, мне понадобилось сделать набор из нескольких шрифтов для цифр разного размера, вот я и вспомнил про эту штуку. Она достаточно хорошо преобразует в растр разные шрифты, а дальше остается лишь набить вручную все в файле с исходниками.
Саму идею (как и основной шрифт величиной 12 пикселей) я стащил где-то на просторах интернета (Nadyrshin Ruslan, youtube). Но там подход был "в лоб": надо 256 символов — значит, столько места и займем (хоть половина пустая). Меняем подход.
Итак, нужно нам не так уж и много. Сначала заведем заголовочный файл fonts.h, где определим перечень имеющихся шрифтов, базовые функции и структуру, характеризующую шрифт:
// type for font choosing
typedef enum{
FONT_T_MIN = -1, // no fonts <= this
FONT14, // 16x16, font height near 14px
FONTN16, // numbers 16x8, font height 16px
FONTN10, // numbers 10x8, font height 10px
FONT_T_MAX // no fonts >= this
} font_t;
int choose_font(font_t newfont);
const uint8_t *font_char(uint8_t Char);
typedef struct{
const uint8_t *font; // font inself
const uint8_t *enctable; // font encoding table
uint8_t height; // full font matrix height
uint8_t bytes; // amount of bytes in font matrix
uint8_t baseline; // baseline position (coordinate from bottom line)
} afont;
extern const afont *curfont;
Глобальная постоянная curfont является указателем на текущий используемый шрифт (задается он командой choose_font, далее описываю содержимое файла fonts.c):
int choose_font(font_t newfont){
if(newfont >= FONT_T_MAX || newfont <= FONT_T_MIN) return 1;
curfont = &FONTS[newfont];
return 0;
}
Если шрифт не найден, возвращается единица. Если все ОК — нуль.
Функция font_char позволяет получить доступ к нужному символу:
const uint8_t *font_char(uint8_t Char){
uint8_t idx = curfont->enctable[Char];
if(!idx) return NULL; // no this character in font
return &(curfont->font[idx*(curfont->bytes+1)]);
}
Если символ не найден, возвращается NULL. Если найден — указатель на него (первым байтом идет ширина символа в пикселях, далее — данные самого символа).
Еще в файл fonts.c нужно поместить массив — все существующие шрифты:
static const afont FONTS[] = {
[FONT14] = {font14_table, font14_encoding, FONT14HEIGHT, FONT14BYTES, FONT14BASELINE},
[FONTN16] = {fontNumb16_table, fontNumb16_encoding, FONTNUMB16HEIGHT, FONTNUMB16BYTES, FONTNUMB16BASELINE},
[FONTN10] = {fontNumb10_table, fontNumb10_encoding, FONTNUMB10HEIGHT, FONTNUMB10BYTES, FONTNUMB10BASELINE},
};
const afont *curfont = &FONTS[FONT14];
(ну и сам указатель на текущий шрифт).
Но в самом начале этого файла надо перечислить дефайны для удобства рисования. Я не буду все эти 256 строк включать, а только приведу скрипт, генерирующий их:
#!/bin/bash
function bits(){
Ans=""
for x in $(seq 7 -1 0); do
B=$((1<<$x))
if [ $(($1&$B)) -ne 0 ]; then Ans="${Ans}X"
else Ans="${Ans}_"
fi
done
echo $Ans
}
for x in $(seq 0 255); do
printf "#define $(bits $x)\t0x%02x\n" $x
done
Сразу после этого включаем все файлы со шрифтами:
#include "font14.h"
#include "fontNumb16.h"
#include "fontNumb10.h"
Ну а потом уже пишем то, что я выше привел.
Содержимое каждого файла со шрифтами несложно нарисовать. Во-первых, это нужные дефайны:
#define FONTNUMB10BYTES 10
#define FONTNUMB10HEIGHT 10
#define FONTNUMB10BASELINE 0
Во-вторых, таблица для перекодировки (своя для каждого шрифта):
const uint8_t fontNumb10_encoding[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0..31
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, // 47
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 0, 0, // 63
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 95
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 111
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 127
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 143
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 159
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 175
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 191
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 207
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 223
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 255
};
Здесь определены маленькие цифры (10 пикселей высотой), поэтому почти вся таблица — нули. Зато очень приличная экономия памяти получается.
Сам этот шрифт — в константе fontNumb10_table[]. Первым ее элементом обязательно должен идти символ-пустышка с нулевой шириной, а дальше — определяемые символы. Скажем, для этого шрифта начало данного массива имеет вид
const uint8_t fontNumb10_table[] = {
// 0x00 - empty
0,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
// 0x20 - ' '
4,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
// 0x30 - '0'
7,
__XX____,
_X__X___,
X____X__,
X____X__,
X____X__,
X____X__,
X____X__,
X____X__,
_X__X___,
__XX____,
Руслан Надыршин подсказал превосходнейший способ визуализации данных! Мы просто определяем 256 макросов для каждого числа, вместо нуля симпол подчеркивания, вместо единицы — X. И можно прямо в исходниках рисовать символы.
Другой шрифт с цифрами имеет высоту 16 пикселей — на всю высоту экрана. Поэтому там символы выглядят как-то так:
// 0x32 - '2'
7,
__XX____,
_XXXX___,
XX_XXX__,
X___XX__,
____XX__,
____XX__,
____XX__,
____XX__,
___XX___,
___X____,
__XX____,
__X_____,
_XX_____,
XX______,
XX___X__,
XXXXXX__,
А в оригинальном шрифте буквы занимают по высоте почти все 16 пикселей (у некоторых вниз выползает хвостик, у некоторых — вверх). И выглядят они уже вот так:
// 0x40
,
16,
_____XXX,XXX_____,
___XXXXX,XXXXX___,
__XXX___,___XXX__,
_XXX__XX,X_XXXX__,
_XX_XXXX,XXXX_XX_,
XXX_XX__,_XXX_XX_,
XX_XX___,_XX__XX_,
XX_XX___,_XX__XX_,
XX_XX___,_XX__XX_,
XX_XX___,XXX_XX__,
XX_XXXXX,XXXXX___,
_XX_XXXX,_XXX____,
_XXX____,_____XX_,
__XXX___,___XXX__,
___XXXXX,XXXXX___,
_____XXX,XXX_____
Здесь, правда, приходится разделять байты запятыми, что немножко ломает наглядность. Но определять 65536 макросов что-то не хочется: боюсь, что сборка в этом случае затянется...
Вот на таких широченных шрифтах 16х16 пикселей экономия флеша при индексации получается вполне приличной: ведь один символ занимает 33 байта, а таблица с индексами — 256. Если в шрифте не определено 8 символов, индексация уже экономит немного места. А если там определено лишь полтора десятка, так совсем прилично!