Как стать автором
Обновить

Комментарии 51

А скачущие "p", "q", "ц", "у" и все элементы с нижней выступающей частью (не помню как это правильно называется), это какое-то непреодолимое техническое ограничение или просто так проще было? Выглядит ужасно, если честно. Стив Джобс наверное в гробу переворачивается.

Выхода два, уменьшить заглавные буквы, что даст возможность сдвинуть верхний уровень строчных букв выше или использовать битовые матрицы с пропорцией 1/2 (ширина/высота).
Например:


Но тут заглавная буква W выглядит куцо. Шрифт при ограниченных ресурсах — это компромисс, можно рисовать текст как графику и это будет медленно, но красиво. Если пытаться вписаться в битовые матрицы, то это будет выбор между общим размером букв и сдвигом некоторых букв типа q,p,y относительно горизонтальной оси.

Но 12 на 24 это не такие уж и ограниченные ресурсы. В терминале Windows 7 (FAR) много лет работаю со шрифтом 10x18 и он выглядит очень даже хорошо. 2 пикселя снизу хватает на выносные элементы.


На картинке сверху чуть лучше, но что-то явно не то с заглавной T. R и S имеют разное основание. k и l тоже скачут.

Согласен, но тема поста не про разработку шрифта. Я сделал эти шрифты, чтобы показать возможность использования собственных внешних шрифтов с RA8875, и если честно, это отняло очень много времени. До того, как я написал программу на Python для создания hex файла, ручная компиляция прошивки EEPROM тоже было делом очень не быстрым.
Было бы интересно, если бы кто-то написал статью про последовательность разработки битовых шрифтов. Я для себя выработал такую схему, сначала рисуются буквы q,g,y,p,j,W и выбирается средняя линия букв, потом уже все остальные буквы. Наверняка есть еще много тонкостей, чтобы сделать шрифт красивым и потратить на это приемлемое количество времени.
Я в фотошопе набираю строку из всех печатаемых символов (с кодами от 32 до 255), по желанию корректирую ее (сдвигаю если попадаются большие промежутки, подправляю какие-то символы):
Заголовок спойлера


Размер шрифта подгоняю так, чтобы в нужную мне высоту укладывалась полная высота всех символов:
Заголовок спойлера


Затем в текстовый файл записываю Y-координаты последней колонки пикселей каждого символа:
Заголовок спойлера


После чего сохраняю файл в черно-белом режиме в формат RAW. И скармливаю этот файл и текстовик с координатами своей утилите, которая из них формирует.с-файл с битовым массивом символов, массивом ширин символов и структурой, описывающей шрифт:
Заголовок спойлера


И потом этими шрифтами «пишу» на дисплее микроконтроллером с помощью своей UI-библиотеки :) Предусмотрена возможность ссылок внутри шрифта с одного символа на другой (например, кириллическая «А» может не иметь свой битовый массив, а ссылаться на битовый массив латинской «A»), что заметно экономит объем шрифта в памяти :) Символы кодируются по строкам, при этом если символ имеет ширину 9 пикселей, то каждая строка пикселей и будет занимать в массиве 9 бит, выравнивание до границы 8 бит осуществляется только в конце битового массива символа.
Библиотека может писать текст с выравниванием по левой стороне, правой стороне или по центру заданного окна, может переносить текст автоматически или принудительно (символом \n), писать подчеркнутый или зачеркнутый текст, зарисовывать старый фон под буквами или оставлять его.
И, кстати, отрисовывается шрифт очень шустро. Дисплей 480х320 (подключен по параллельной шине как внешняя память) полностью заполняется шрифтом высотой 12 за долю секунды. Заметно подтормаживать начинает только при выводе текста с сохранением фона — там уже сам вывод в дисплей идет по-другому, гораздо более медленным способом. Буфера дисплея при этом нет, все рисуется сразу в дисплей. Контроллер, правда, молотит при этом на 168 МГц.
Вот пример, синим — текст моим пропорциональным шрифтом через мою библиотеку, нижняя строка белым — текст одной из стандартных распространенных библиотек стандартным моноширинным шрифтом. Верхняя строка белым — промежуточный эксперимент, не участвующий в сравнении :) Мой текст вывелся в 15 раз быстрее стандартного:
Заголовок спойлера

Спасибо за развернутый комментарий, было бы интересно узнать какая ширина шины по которой идет обмен с контроллером дисплея и какой контроллер дисплея используется. На моем видео я вывожу по 192 символа 16х16, 24х24, 32х32 битовых шрифта, хотелось бы увидеть видео с выводом у вас хотя бы половины этого объема чтобы оценить скорость.
Шина 16 бит, контроллер был вроде бы SSD1963. Вот с тестом вывода не выйдет — этот проект был полгода назад.
Но смотрите: ниже Вы пишете, что для каждого пикселя каждого символа Вам нужно вычислить и задать координаты и отправить 3 байта цвета. А 24-битный цвет обязательно? Контроллер не позволяет переключиться в 16-битный цвет?
И второй момент: нет нужды для каждого пикселя задавать координаты, достаточно задать контроллеру дисплея окно вывода, соответствующее положению и размеру символа, и потом просто в цикле вогнать в дисплей подряд все байты этого символа. Конечно, если контроллер дисплея поддерживает такой режим, но RA8875 по беглому взгляду в его даташит поддерживает. Это здорово ускоряет вывод текста
Тут не о чем спорить, у вас не было возможности подключить внешнее EEPROM со шрифтами, поэтому вы использовали 16 битную шину для обмена данными и усиленно оптимизировали код формирования обмена данными с дисплеем. У меня была такая возможность, и я предпочел внешнее EEPROM. И да, у RA8875 нет 16 битного режима, только 8 и 24 бита. На счет окна вывода, есть блочный перенос между слоями изображения, между внешней EEPROM и изображением, но вот записи блока микроконтроллером я не нашел, может быть плохо искал.
У меня была такая возможность, и я предпочел внешнее EEPROM

Да я не спорю, если у Вас есть возможность аппаратной поддержки шрифтов, то глупо не воспользоваться ею. Просто говорю, что «ручная» отрисовка шрифтов может быть гораздо более быстрой и разница уже не будет такой колоссальной как у Вас на видео :)
И да, у RA8875 нет 16 битного режима, только 8 и 24 бита.

Странно, может быть есть две версии RA8875? Я вот вижу в даташите прямое указание, что имеется поддержка 8- и 16-битного цвета, а про 24 бита ни слова: "RA8875 supports the 8-bit/16-bit color depth TFT-LCD Panel, i.e. 256 and 65K colors TFTLCD panel.". И там же цветная картинка как передаются 16-битные значения цвета по 8- и 16-битной параллельной шине :)
Да и в описаниях регистров есть настройка на 8 и 16 бит, но нет 24:
Заголовок спойлера


но вот записи блока микроконтроллером я не нашел, может быть плохо искал.

Не вдавался в детали, но в даташите описана фича «Active Window», которая очень похожа на то что нужно.
Прикинул примерно разницу во времени, затрачиваемом на отрисовку символа 24х24 при попиксельной отрисовке и при потоковой отрисовке с установкой активного окна — все по 8-битной шине.
Попиксельная отрисовка
24х24х3=1728 обращений к дисплею для записи пикселей (1 команда записи и 2 байта цвета для каждого пикселя)
24х24х6=3456 обращений к дисплею для установки координат пикселя (два регистра по 3 обращения — адрес регистра и 2 байта его значения)
Всего: 5184 обращений к дисплею.

Потоковая отрисовка с установкой активного окна
24 обращения для установки активного окна (8 регистров по 3 обращения)
1 обращение для выдачи команды начала потоковой записи
24*24*2=1152 обращения для записи пикселей
Всего: 1177 обращений.

Более, чем в 4 раза быстрее. С 16-битной шиной разница становится еще больше — примерно 4608 против 593 обращений.
Кстати, у этого видеоконтроллера есть функция «Color Expansion» или «Color Expansion with Transparency» — они прямо напрашиваются на то, чтобы с их помощью выводить тексты — с закрашенным или прозрачным фоном соответственно. Там вообще в него вгоняется не байтовый поток, а битовый, то есть количество обращений сокращается чуть ли не на порядок даже по сравнению с потоковым выводом в активное окно :) Навскидку — около 178 обращений для символа 24х24.

Но все равно это на много больше чем 3 обращения на 1 символ :)

Согласен, но так снимаются все ограничения на количество и виды шрифтов :)

Их обычно немного надо, разнообразие шрифтов — дурной тон в дизайне.

Пункты меню — одним размером, строка статуса — вторым, список файлов — третьим, подробная информация о файле — четвертым, вводимые в поля ввода значения — пятым. Вот уже как минимум 5 шрифтов разного размера :) А еще бывает полезно где-то что-то выделить жирным или курсивом :)
Вот, к примеру, список используемых в моем проекте шрифтов:
extern LCDUI_FONT font_fnt12;
extern LCDUI_FONT font_fnt12bold;
extern LCDUI_FONT font_fnt18;
extern LCDUI_FONT font_fnt18bold;
extern LCDUI_FONT font_fnt24;
extern LCDUI_FONT font_fnt24bold;
extern LCDUI_FONT font_fnt36;
extern LCDUI_FONT font_fnt36num;
extern LCDUI_FONT font_fnt170num_lcd;

В EEPROM смело уместиться 6 шрифтов, некоторые, редко используемые можно и программно вывести. Другими словами не надо выбирать, можно и то и то использовать.

Ну вот у меня 8 пропорциональных шрифтов используется, при этом под стандартную высоту, загоняемую в EEPROM, подходит только один из них. Остальные только программно выводить и тут как раз не надо тупо следовать распространенным библиотекам, которые несчастные 100 символов выводят целую секунду :)

Я и не претендую на единственное "правильное", решение :)Просто может кому-то вариант со шрифтами в EEPROM окажется в тему.

Разумеется, вот даже мне может быть окажется в тему в будущем :) До этой статьи я даже и не знал о таком видеоконтроллере, а он ведь может здорово облегчить жизнь мелким микроконтроллерам :)
Добрался таки до тестов вывода своего шрифта :)
Дисплей — 480х320, использованный шрифт — пропорциональный 12 пикс высотой. На дисплей поместилось 1755 символов текста (в выводимой строке их задано больше, но библиотека обрезает то, что выходит за пределы экрана). При этом в выводе используется автоперенос, обработка символов перевода строки и т.п.

Контроллер — STM32F407 с тактовой частотой 168 МГц. Время отрисовки — около 0.066 секунды.

Красиво, я так понимаю используется встроенный в чип контроллер дисплея и отрисовка происходит во внутренней памяти микроконтроллера?

Нет, встроенный контроллер не при делах и все отрисовывается на лету сразу в дисплей :) Дисплей подключен к шине внешней памяти по 16-битному интерфейсу.
	for (i = 0; i < cw*ch; i++)
	{
		csh = (c >> sh);
		LCD_WriteRAM(cres[(csh&0x01)]);
			
		sh ++;
		if (sh == 8)
		{
			c = data[ptr++];
			sh = 0;
		}
	}
Ну да, вывод в режиме активного окна существенно снижает накладные расходы.
Да, я об этом и писал Вам ранее :)

Я использовал для дисплея с этим контроллером библиотеку LVGL https://www.youtube.com/watch?v=4R3RbyYZE3I без микросхем для шрифтов, там есть разные варианты, шрифты вроде и по spi не тормозят или нужно предельное быстродействие?

На данном видео мало текста, и не видно, на сколько медленно и печально рисуется текст. Я сделаю видео для контраста, вывод того же текста, что в моем видео только с программными шрифтами. И тогда вы почувствуете разницу.

Интересно сравнить, текст выводился в тесте который идет для разных дисплеев, на вид быстро.

Обновил видео в статье, теперь можно сравнить два способа вывода текста, программный и из EEPROM.

Странно, на 50MHz еще и на параллельной шине, мне кажется со шрифтами вообще проблем быть не должно, надо тоже посмотреть как у меня покажет, у меня spi и скорость около 20MHz.

Ничего странного, шрифт рисуется по одной точке, по три байта каждая. Координаты и цвет этой точки надо еще вычислить, это не полигон залить. Если грубо прикинуть, цикл записи в память по параллельной шине eZ80, при тактовой частоте 50МГц — 80ns. Вывод буквы 24х24х3 занимает 138µs. И это просто вывод, без вычислений места и цвета точки.
По SPI вообще получается почти 700µs для символа 24х24.
Раньше было популярно кодировать шрифты (и не только) по типу фрагмента под спойлером. И не надо было никаких комментариев с картинками и редактировать удобно.

Пример фрагмента шрифта
const char NBigFont[]= {
10,18,

------- 8< --------

10,			//49 '1'
________,________,
________,________,
____OO__,________,
___OOO__,________,
_OOOOO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
_OOOOOOO,O_______,
________,________,
________,________,
10,			//50 '2'
________,________,
________,________,
___OOOO_,________,
__OO__OO,________,
_OO____O,O_______,
_OO____O,O_______,
_______O,O_______,
_______O,O_______,
______OO,________,
_____OO_,________,
____OO__,________,
___OO___,________,
__OO____,________,
_OO_____,________,
_OO_____,________,
_OOOOOOO,O_______,
________,________,
________,________,
10,			//51 '3'
________,________,
________,________,
___OOOO_,________,
__OO__OO,________,
_OO____O,O_______,
_OO____O,O_______,
_______O,O_______,
______OO,________,
___OOOOO,________,
______OO,________,
_______O,O_______,
_______O,O_______,
_OO____O,O_______,
_OO____O,O_______,
__OO__OO,________,
___OOOO_,________,
________,________,
________,________,

--------- 8< ----------

Даже в специализированной программе и то очень муторно создавать шрифт, а в ASCII это будет вообще жуть.
Не, я не про создание. Это отдельная история, особенно когда размер шрифта большой.
Я писал именно про кодирование в исходнике. Наглядно и удобно.
Я не понимаю о чем вы говорите, что значит «кодирование шрифта в исходнике»?
Обычно это массив констант или вы знаете какой-то другой способ?
Это и есть массив констант. Просто вместо скучных столбцов чисел в исходном коде программы из которых надо «в голове» восстанавливать вид закодированной ими картинки мы видим и даже можем легко подредактировать саму картинку.

Столбцы чисел
0x00,0x00,
0x00,0x00,
0x0C,0x00,
0x1C,0x00,
0x7C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x0C,0x00,
0x7F,0x80,
0x00,0x00,
0x00,0x00,


Картинка
________,________,
________,________,
____OO__,________,
___OOO__,________,
_OOOOO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
____OO__,________,
_OOOOOOO,O_______,
________,________,
________,________,


Для этого всего лишь требуется определить
небольшую таблицу
#define ________ 0
#define _______O 1
#define ______O_ 2
#define ______OO 3
#define _____O__ 4
#define _____O_O 5
#define _____OO_ 6
#define _____OOO 7
#define ____O___ 8
#define ____O__O 9
#define ____O_O_ 10
#define ____O_OO 11
#define ____OO__ 12
#define ____OO_O 13
#define ____OOO_ 14
#define ____OOOO 15
#define ___O____ 16
#define ___O___O 17
#define ___O__O_ 18
#define ___O__OO 19
#define ___O_O__ 20
#define ___O_O_O 21
#define ___O_OO_ 22
#define ___O_OOO 23
#define ___OO___ 24
#define ___OO__O 25
#define ___OO_O_ 26
#define ___OO_OO 27
#define ___OOO__ 28
#define ___OOO_O 29
#define ___OOOO_ 30
#define ___OOOOO 31

и т.д. до 255

И кто так делает? Мне лично больше нравяться скучные символы, тем более что сейчас шрифты разрабатывают в специализированных программах и выводят в том виде в котором необходимо. А вот так колитить по биту каждый символ это надо иметь очень много свободного времени.
Самому рисовать 255 дефайнов лениво, но если бы программа создания шрифта представляла возможность экспорта в таком вот графическом виде, было бы удобно.
За сомнительное удобство редактирования шрифта прямо в коде наступает расплата в виде большего объема массива шрифта и более медленной скорости вывода. Ну и так обычно делают моноширинные шрифты, с пропорциональными уже не все так просто будет :)
Извините, но Вы чушь в данном случае написали. Я писал всего лишь о кодировании чисел константами. Если написать в исходном коде константу 0x55 как _0_0_0_0, то от этого занимаемый ею объем не изменится. В обоих случаях один байт.
Как вы храните шрифт в памяти (в каких структурах, с выравниванием или без) к этому не имеет никакого отношения. Так же, впрочем, как и моноширинность шрифта. В моем примере, кстати, шрифт пропорциональный. Числа 10 между символами как раз определяют ширину конкретного символа. Из этого шрифта у меня реально были только цифры и несколько спец. символов. Остальные шрифты были не шире 8 бит. В данном случае экономить память небыло никакого смысла. Зато использовалась одна общая функция для вывода.

Кстати, в Вашем варианте хранения никто не запрещает записать массив так же в виде констант (разве что он будет слишком широкий). В результате размер получится абсолютно такой же.

Вообще, удобство редактирования шрифта или картинок прямо в коде наступает лет через… надцать после написания кода. Не нужны лишние утилиты для преобразования, можно сразу видеть в исходном коде графику.
Тому фрагменту кода, что я приводил 19 лет от роду.

Вот этому где то 22 года
; 48 '0'
DB __OOOO__
DB _O____O_
DB _O____O_
DB __OOOO__
DB ________
; 49 '1'
DB ________
DB _O___O__
DB _OOOOOO_
DB _O______
DB ________
; 50 '2'
DB _O___O__
DB _OO___O_
DB _O_O__O_
DB _O_O__O_
DB _O__OO__
; 51 '3'
DB __O__O__
DB _O____O_
DB _O__O_O_
DB _O__O_O_
DB __OO_O__
; 52 '4'
DB __OOO___
DB __O__O__
DB __O___O_
DB _OOOOOO_
DB __O_____
; 53 '5'
DB __O_OOO_
DB _O__O_O_
DB _O__O_O_
DB _O__O_O_
DB __OO__O_
; 54 '6'
DB __OOOO__
DB _O__O_O_
DB _O__O_O_
DB _O__O_O_
DB __OO____
; 55 '7'
DB ______O_
DB _OO___O_
DB ___O__O_
DB ____O_O_
DB _____OO_
; 56 '8'
DB __OO_O__
DB _O__O_O_
DB _O__O_O_
DB _O__O_O_
DB __OO_O__
; 57 '9'
DB ____OO__
DB _O_O__O_
DB _O_O__O_
DB _O_O__O_
DB __OOOO__
; 58 ':'
DB ________
DB _OO_OO__
DB _OO_OO__
DB ________
DB ________
; 59 ';'
DB ________
DB O_O_OO__
DB _OO_OO__
DB ________
DB ________
; 60 '<'
DB ________
DB ___O____
DB __O_O___
DB _O___O__
DB ________
; 61 '='
DB ___O_O__
DB ___O_O__
DB ___O_O__
DB ___O_O__
DB ___O_O__
; 62 '>'
DB ________
DB ________
DB _O___O__
DB __O_O___
DB ___O____
; 63 '?'
DB _____O__
DB ______O_
DB _O_O__O_
DB ____O_O_
DB _____O__
; 64 '@'
DB __OOOO__
DB _O____O_
DB _O_OO_O_
DB _O_OO_O_
DB ___OOO__
; 65 'A'
DB _OOOO___
DB ___O_O__
DB ___O__O_
DB ___O_O__
DB _OOOO___
; 66 'B'
DB _OOOOOO_
DB _O__O_O_
DB _O__O_O_
DB _O__O_O_
DB __OO_O__
; 67 'C'
DB __OOOO__
DB _O____O_
DB _O____O_
DB _O____O_
DB __O__O__
; 68 'D'
DB _OOOOOO_
DB _O____O_
DB _O____O_
DB __O__O__
DB ___OO___
; 69 'E'
DB _OOOOOO_
DB _O__O_O_
DB _O__O_O_
DB _O__O_O_
DB _O____O_
; 70 'F'
DB _OOOOOO_
DB ___O__O_
DB ___O__O_
DB ___O__O_
DB ______O_
; 71 'G'
DB __OOOO__
DB _O____O_
DB _O____O_
DB _O_O__O_
DB _OOO_O__
; 72 'H'
DB _OOOOOO_
DB ___O____
DB ___O____
DB ___O____
DB _OOOOOO_
; 73 'I'
DB ________
DB _O____O_
DB _OOOOOO_
DB _O____O_
DB ________
; 74 'J'
DB __O___O_
DB _O____O_
DB _O____O_
DB _O____O_
DB __OOOOO_
; 75 'K'
DB _OOOOOO_
DB ____O___
DB ___O_O__
DB __O___O_
DB _O____O_
; 76 'L'
DB _OOOOOO_
DB _O______
DB _O______
DB _O______
DB _OO_____
; 77 'M'
DB _OOOOOO_
DB _____O__
DB ___OO___
DB _____O__
DB _OOOOOO_
; 78 'N'
DB _OOOOOO_
DB ____O___
DB ___O____
DB __O_____
DB _OOOOOO_
; 79 'O'
DB __OOOO__
DB _O____O_
DB _O____O_
DB _O____O_
DB __OOOO__
; 80 'P'
DB _OOOOOO_
DB ___O__O_
DB ___O__O_
DB ___O__O_
DB ____OO__
; 81 'Q'
DB __OOOO__
DB _O____O_
DB _O_O__O_
DB __O___O_
DB _O_OOO__
; 82 'R'
DB _OOOOOO_
DB ___O__O_
DB ___O__O_
DB __OO__O_
DB _O__OO__
; 83 'S'
DB __O__O__
DB _O__O_O_
DB _O__O_O_
DB _O__O_O_
DB __OO____
; 84 'T'
DB ______O_
DB ______O_
DB _OOOOOO_
DB ______O_
DB ______O_
; 85 'U'
DB __OOOOO_
DB _O______
DB _O______
DB _O______
DB __OOOOO_


Естественно они генерировались не вручную, а самописными программками (еще под DOS). Зато, чтобы сейчас что то изменить в графике (шрифтах, картинках) те программки не нужны.

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

Еще как имеет. В Вашем варианте символ шириной 12 пикс и высотой 16 пикс займет 256 бит (32 байта), в моем — 192 бита (24 байта).
Кстати, в Вашем варианте хранения никто не запрещает записать массив так же в виде констант (разве что он будет слишком широкий)

Нет, никто не запрещает. Только толку от этого не будет, потому что читаемости не будет. Вот Вам байты символа «открывающая (левая) круглая скобка» шириной 5 пикс и высотой 12 пикс: 0x44,0x88,0x10,0x42,0x08,0x41,0x08,0x02
Можете попробовать перевести это в Ваш вариант крестиков-ноликов и посмотреть что получится. Заодно посмотреть на сколько байт больше будет занимать в памяти этот символ в популярном виде, которому «19 лет от роду».
В результате размер получится абсолютно такой же.

Нет, размер одного и того же шрифта в моем варианте будет меньше, чем в Вашем (который популярен в инете). Даже с учетом доп. таблицы с шириной символов и даже без использования моей возможности ссылок вместо битовых массивов, которые тоже экономят размер — можно убрать из массива изображения как минимум 17 символов в шрифте с латинницей и кириллицей — А, В, С, Е и т.д.
Как вы храните шрифт в памяти (в каких структурах, с выравниванием или без) к этому не имеет никакого отношения.

Еще как имеет. В Вашем варианте символ шириной 12 пикс и высотой 16 пикс займет 256 бит (32 байта), в моем — 192 бита (24 байта).

Еще раз приведу то что Вы пропустили:
Я писал всего лишь о кодировании чисел константами. Если написать в исходном коде константу 0x55 как _0_0_0_0, то от этого занимаемый ею объем не изменится. В обоих случаях один байт.

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

Вот Вам байты символа «открывающая (левая) круглая скобка» шириной 5 пикс и высотой 12 пикс: 0x44,0x88,0x10,0x42,0x08,0x41,0x08,0x02
Можете попробовать перевести это в Ваш вариант крестиков-ноликов и посмотреть что получится

Вы не уточняли структуру хранения массива шрифта. Судя по приведенным числам Вы храните битовый массив посимвольно, я предполагал, что построчно, как в данном фрагменте
Пример символов как на Вашем скриншоте
________,O_______,________,_____O__,________,OOO_____,
________,O_______,________,_____O__,_______O,________,
________,O_______,________,_____O__,_______O,________,
___OOO__,O_OOO___,__OOO___,_OOOOO__,_OOO__OO,OO______,
__O___O_,OO___O__,_O___O__,O____O__,O___O__O,________,
______O_,O_____O_,O______O,_____O_O,____O__O,________,
___OOOO_,O_____O_,O______O,_____O_O,OOOOO__O,________,
__O___O_,O_____O_,O______O,_____O_O,_______O,________,
_O____O_,O_____O_,O______O,_____O_O,_______O,________,
_O___OO_,O____O__,_O___O__,O___OO__,O___O__O,________,
__OOO_O_,OOOOO___,__OOO___,_OOO_O__,_OOO___O,________,
________,________,________,________,________,________,
________,________,________,________,________,________,
________,________,________,________,________,________,



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

Вы написали хорошую реализацию, которая Вас устроила. Я рад за Вас (кроме шуток). Просто я с Вами и не спорил по этому поводу если что.

PS. Я оценил шутку "(который популярен в инете)", учитывая возраст исходников. :)
Еще раз приведу то что Вы пропустили:

Ну и я тогда еще раз повторю свою мысль: «За сомнительное удобство редактирования шрифта прямо в коде наступает расплата в виде большего объема массива шрифта и более медленной скорости вывода.». Это означает, что если хранить символы не байтами, а битами, то уже не получится так красиво рисовать символы в коде, зато сократится занимаемый шрифтом объем и во многих случаях многократно возрастет скорость отрисовки.
Судя по приведенным числам Вы храните битовый массив посимвольно, я предполагал, что построчно, как в данном фрагменте

Нет, посимвольно и к тому же битовым массивом, а не байтовым. То есть я не выравниваю по байтам каждую строку или колонку символов. А хранение построчно не дает никакого выигрыша, да еще и заставляет носиться указателем по массиву во время вывода символа, что не способствует скорости отрисовки :)
PS. Я оценил шутку "(который популярен в инете)", учитывая возраст исходников. :)

Этот способ хранения шрифта (не константы с ноликами и подчеркиваниями, а сама структура) известна очень давно, весь инет ею забит и используется он в 99% проектах на мелких контроллерах, которые не способны на рендер векторных шрифтов :) Я еще минимум лет 12 назад уже натыкался на такой способ хранения шрифтов. А может быть и больше, точно не помню.
Если Вам совсем непонятно, то мой исходный комментарий:
Раньше было популярно кодировать шрифты (и не только) по типу фрагмента под спойлером. И не надо было никаких комментариев с картинками и редактировать удобно.

относился вот к этой картинке автора статьи
картинка автора статьи
image

А я имел в виду вот такое кодирование (специально для делающих вид что не понимают о чем речь, те же символы и без указания каких-либо структур для хранения:
вариант кодирования
________,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OO______,________,
OOOOOOOO,________,
OOOOOOOO,________,
________,________,

________,________,
OOO_____,__OOO___,
OOOO____,_OOOO___,
OOOO____,_OOOO___,
OOOO____,_OOOO___,
OO_OO___,OO_OO___,
OO_OO___,OO_OO___,
OO_OO___,OO_OO___,
OO_OO___,OO_OO___,
OO__OO_O,O__OO___,
OO__OO_O,O__OO___,
OO__OO_O,O__OO___,
OO___O_O,___OO___,
OO___OOO,___OO___,
OO___OOO,___OO___,
________,________,

________,________,
OO______,_OO_____,
OOO_____,_OO_____,
OOOO____,_OO_____,
OOOO____,_OO_____,
OO_OO___,_OO_____,
OO__OO__,_OO_____,
OO__OO__,_OO_____,
OO___OO_,_OO_____,
OO___OO_,_OO_____,
OO____OO,_OO_____,
OO_____O,OOO_____,
OO_____O,OOO_____,
OO______,OOO_____,
OO______,_OO_____,
________,________,


Можете высказать претензии автору статьи, что он хранит данные неоптимально. Я здесь вообще о хранении даже не упоминал.

PS. Буквально пару замечаний напоследок.

Судя по приведенным числам Вы храните битовый массив посимвольно,…

Нет, посимвольно и к тому же битовым массивом,…

Хм. Я же вроде так и написал? По приведенным Вами байтикам как раз сразу стало понятно как Вы храните данные символа.

Что касается скорости работы в попиксельном режиме, то для цветного экрана, где один пиксель это 1-3 байта это будет оптимальный способ. Для монохромного экрана работа сразу со строкой символа будет в разы быстрее попиксельного режима. С этим надеюсь согласитесь?

Что касается экономии места, занимаемого крупными шрифтами и графикой (спрайтами) то сжатие тем же LZSS адаптированным под небольшой размер блока достаточно эффективно. Вот пример из того же исходника что и в первом комментарии. Экономия порядка 3-х кратной.
Пример
//const char spBigMicro_Data[] = {	/* Size:120 */
/*________,________,________,________,	//1
________,________,________,________,	//2
________,________,________,________,	//3
________,________,________,________,	//4
________,________,________,________,	//5
________,________,________,________,	//6
________,________,________,________,	//7
________,________,________,________,	//8
_____OOO,OOO_____,__OOOOOO,________,	//9
_____OOO,OOO_____,__OOOOOO,________,	//10
_____OOO,OOO_____,__OOOOOO,________,	//11
_____OOO,OOO_____,__OOOOOO,________,	//12
_____OOO,OOO_____,__OOOOOO,________,	//13
_____OOO,OOO_____,__OOOOOO,________,	//14
_____OOO,OOO_____,__OOOOOO,________,	//15
_____OOO,OOO_____,__OOOOOO,________,	//16
_____OOO,OOO_____,__OOOOOO,________,	//17
_____OOO,OOO_____,__OOOOOO,________,	//18
_____OOO,OOO_____,__OOOOOO,________,	//19
_____OOO,OOO_____,__OOOOOO,________,	//20
_____OOO,OOO_____,__OOOOOO,________,	//21
_____OOO,OOO_____,__OOOOOO,________,	//22
_____OOO,OOO_____,__OOOOOO,________,	//23
____OOOO,OOO_____,_OOOOOOO,________,	//24
____OOOO,OOOO____,_OOOOOOO,________,	//25
___OOOOO,OOOOO___,OOOOOOOO,________,	//26
_OOOOOOO,OOOOOOOO,OOOOOOOO,________,	//27
OOOOOOO_,OOOOOOOO,OO_OOOOO,________,	//28
OOOOOO__,_OOOOOOO,O__OOOOO,________,	//29
_OOOO___,__OOOOO_,___OOOOO,________ 	//30
};
const struct TSprite spBigMicro = {27,30,COMPRESS_NONE,spBigMicro_Data};
*/
const char spBigMicro_Data[] = {	/* Size:42 (35%) */
0x28,0x00,
0x00,0xF0,0xE0,0x02,0x07,0xE0,0x3F,0xF3,0xF3,0xF3,0x83,0x02,0x0F,0xE0,0x7F,0x13,
0x00,0xF0,0x13,0x05,0x1F,0xF8,0xFF,0x00,0x7F,0xFF,0x13,0x0B,0xFE,0xFF,0xDF,0x00,
0xFC,0x7F,0x9F,0x00,0x78,0x3E,0x1F,0x00};
const struct TSprite spBigMicro = {27,30,COMPRESS_LZSS,spBigMicro_Data};

//------------------------------------------------------------------

//const char spBigMili_Data[] = {	/* Size:120 */
/*________,________,________,________,	//1
________,________,________,________,	//2
________,________,________,________,	//3
________,________,________,________,	//4
________,________,________,________,	//5
________,________,________,________,	//6
________,________,________,________,	//7
________,OOOOO___,___OOOOO,________,	//8
OOOOO__O,OOOOOOO_,__OOOOOO,OO______,	//9
OOOOO_OO,OOOOOOOO,_OOOOOOO,OOO_____,	//10
OOOOOOOO,OOOOOOOO,OOOOOOOO,OOO_____,	//11
OOOOOOOO,__OOOOOO,OOO__OOO,OOOO____,	//12
OOOOOOO_,___OOOOO,OO____OO,OOOO____,	//13
OOOOOOO_,___OOOOO,OO____OO,OOOO____,	//14
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//15
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//16
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//17
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//18
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//19
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//20
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//21
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//22
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//23
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//24
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//25
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//26
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//27
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//28
OOOOOO__,___OOOOO,O_____OO,OOOO____,	//29
OOOOOO__,___OOOOO,O_____OO,OOOO____ 	//30
};
const struct TSprite spBigMili = {31,30,COMPRESS_NONE,spBigMili_Data};
*/
const char spBigMili_Data[] = {	/* Size:36 (30%) */
0x22,0x00,
0x00,0xF0,0xB0,0x0B,0xF8,0x1F,0x00,0xF9,0xFE,0x3F,0xC0,0xFB,0xFF,0x7F,0xE0,0xFF,
0x10,0x13,0x05,0x3F,0xE7,0xF0,0xFE,0x1F,0xC3,0x43,0x02,0xFC,0x1F,0x83,0xF3,0xF3,
0xF3,0xC3};
const struct TSprite spBigMili = {31,30,COMPRESS_LZSS,spBigMili_Data};

А я имел в виду вот такое кодирование (специально для делающих вид что не понимают о чем речь

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

Нет, не соглашусь. Что для монохромного, что для цветного экрана быстрее будет задать один раз координаты и потом передать подряд все байты символа, чем задавать координаты перед передачей каждого пикселя или перед каждой строкой/колонкой символа.
Что касается экономии места, занимаемого крупными шрифтами и графикой (спрайтами) то сжатие тем же LZSS адаптированным под небольшой размер блока достаточно эффективно.

Это уже скорее работа с небольшими картинками, то отдельная тема :)
Можно спорить о лучшем решении в каком-то конкретном случае, с четко оговоренными параметрами, которые надо оптимизировать. Но спорить на тему, как лучше хранить шрифт в памяти вообще, по крайней мере — пустая трата времени.
Ну если надо отрисовывать всего десяток символов, или если у контроллера много лишней памяти и много мегагерц и дисплей тоже умеет много мегагерц, то можно хранить общепринятым байтовым способом и выводить попиксельно :) В этом случае мой способ практического выигрыша не даст, это да :)
Извините, хабр не дает просто плюсануть комментарий.
Полностью с Вами согласен. Без конкретных условий реализации это разговор ни о чем.
Можете высказать претензии автору статьи, что он хранит данные не оптимально.
Способ хранения шрифта в EEPROM продиктован производителем видеоконтроллера RA8875 и от автора статьи никак не зависит.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации