Конвертер растровой графики для монохромного LCD (128х64)
В продолжение маленьких историй о путешествиях по миру микроконтроллеров предлагается рассказ о моей простенькой, но полезной утилитке, позволяющей быстро получить код графического файла в виде массива байтов для встраивания в среду разработки программ для микроконтроллеров (на ассемблере или С/С++), для вывода изображения на экран LCD с разрешением в 128x64 точек.
О чем пойдет речь: Зачем сейчас нужны эти монохромные LCD? Постановка задачи Что нашлось на просторах интернета Делаем свой конвертор Проверяем конвертор в действии, или Руководство по эксплуатации
Зачем сейчас еще нужны монохромные LCD дисплеи?
Конечно, при прочих равных условиях (разрешение, размер, цена, потребление энергии), монохромные дисплеи явно проигрывают своим цветным собратьям, прежде всего по потребительским качествам. И растущие объемы производства, постоянное развитие новых технологий вообще не оставляют им никаких шансов, по крайней мере, в сегменте бытового ширпотреба. Сейчас монохромные дисплеи в новых изделиях можно найти разве что в читалках электронных книг, переводчиках, электронной «бумаге» и самом дешевом мультимедийном секторе. Хотя иногда их ставят и в совсем не дешевые изделия, например, в продвинутые корпуса для сборки PC Home Theater.
С другой стороны, для любительского изучения и конструирования требуются единичные экземпляры дисплеев и возможная экономия вместе с более простым подключением и программированием дают сегодня право на жизнь монохромным графическим дисплеям.
Я тоже проголосовал деньгами за сохранение рынка монохромных дисплеев и уже их несколько штук скопилось, не считая недокументированного мусора от уже отживших свой век сотовых телефонов. Впрочем, и дисплеи с документами были обойдены моим вниманием, после написанной 9 месяцев назад статьи «Моя борьба», все уромянутые в ней дисплеи так больше никуда и не подключались.
Волею случая интерес к этой теме вновь появился и появилось желание обеспечить графическим материалом свои простенькие монохромные дисплеи с разрешением 128x64 точек. Под графическим материалом в данном случае понимаются шрифты с высотой символа более 16 пикселов и графические изображения.
Тип интерфейса в данном случае значения не имеет.
Постановка задачи
Требуется найти быстрый способ встроить в исходный файл программы для микроконтроллера несжатое растровое графическое изображение с глубиной цвета в один бит. Говоря проще, нужно иметь возможность сконвертировать файл из популярных многоцветных графических форматов в монохромный, отсечь все ненужные заголовки и метаданные исходного графического файла и записать его уже в текстовом виде, в формате последовательности hex-кодов, с необходимыми атрибутами для ассемблерной программы или программы на C/C++.
Эта потребность родилась после самостоятельного создания нескольких шрифтов для LCD, высота символов которых не превышает 8 точек. Была написана программа, выводящая в произвольную точку экрана сообщение шрифтом любого размера. Но вот создание большеразмерных шрифтов стало проблемой, так как требует серьезных художественных навыков, которыми господь просто не наделил. Вернее, они еще дремлют где-то очень глубоко.
Поскольку монохромный вывод специально созданного растрового шрифта это просто вывод битовой карты, то крупные надписи или рисунки вполне могут быть взяты из отдельно подготовленных графических файлов.
Разумеется, проблема не новая и давно решена. Но вот того, что нужно именно мне, как-то не попалось. Правда, не было рассмотрено несколько платных вариантов, но платить деньги за то, что можно написать за несколько часов работы, к тому же покупая чужого кота в мешке, не хотелось. Мы и сами с усами.
Что нашлось на просторах интернета
Поверхностный пробег по интернету ничем не порадовал, разве что нашлась в закоулках сайта Amontec заброшенная бесплатная программка FastLCD.
Вот как выглядит интерфейс этой программы с загруженной картинкой размером 128х64:
(кликните по картинке для увеличения) FastLCD В программе много интересных возможностей в плане создания битовых карт, но нет опций конвертирования. Сохранение в виде программной вставки возможно только под два дисплея, один из который от Nokia 3310 c разрешением 84х48 точек, а второй требует шестибитовой сетки.
В целом, программа может пригодиться, креативность на первый взгляд просматривается.
Также существует куча исходников на разных языках для конвертации графики, но меня интересовала не столько конвертация, сколько быстрое получения программного блока, готового к непосредственному встраиванию в исодный файл.
Для примера, конвертация описана на этом сайте, но это тоже не то, что мне надо было.
Возможно плохо искал, но так или иначе, а пришлось все делать самому.
Делаем свой конвертор
Люблю я С#. Поэтому будем делать на нем. Впрочем, легко и быстро эту безделушку можно сделать на любом языке общего назначения. У меня это все заняло полдня. А написание статьи об этом — в четыре раза больше.
Облегчим себе задачу. Программа будет воспринимать и обрабатывать графические файлы (bmp, jpeg, png) размером 128х64 точки. При попытке загрузить файл другого размера, программа предложить повторить загрузку. Поэтому заготовку другого размера придется сначала обработать в любом графическом редакторе. Глубина цвета значения не имеет. Теоретически, можно было бы снять ограничения на размер, как в большую, так и в меньшую стороны, однако это повлечет за собой выход на новый уровень универсальности с вытекающими временными затратами, так как захочется сделать больше, красивше, генерацию фонтов и т.д. Поэтому отложим другие размеры до лучших времен (хотя делать любые форматы и нарезки можно и на этой программе). Лучшие времена могут наступить в конце года, когда я планирую вплотную заняться цветными TFT-дисплеями. Но могут и не наступить никогда.
Пропускаем описание обычной инициализации и объявление переменных, сосредоточимся на узловых моментах (а в программе по сути и нет узлов, всего одна функция, кнопки да вызов диалоговых окон).
Алгоритм очень простой. Получаем через OpenFileDialog ofdисходный файл, делаем из вредности проверку на размер, затем выводим исходный файл на экран и приступаем к конвертации (DX и DY - константы, определяющие размер обрабатываемого изображения):
Конвертация в черно-белый формат в происходит в единственной функции ConvertToMonochrome() и это тривиальная задача. Загруженный графический файл с точки зрения программной модели, представляет собой массив, доступ к каждому пикселу картинки осуществляется простым вызовом в цикле метода
рекламаПравильнее было бы использовать метод LockBits() для самого быстрого доступа к данным, но в виду небольшого размера графического файла это не обязательно.
Наша задача — заменить цвет каждого пиксела на черный или белый. Не стоить определять для этого выходной объект типа Bitmap с заранее установленным пиксельным форматом 1bpp, так как тогда будет трудно обойтись без интероперабельных функций, поскольку 1-битный формат является индексированным (так же, как и 8-битный), т.е. цвет получается из палетты, а метод SetPixel() с индексированными цветами не работает. К тому же выходной файл с однобитным цветом нам ни к чему на диске и отпадает необходимость работы с заголовками.
Поэтому создаем объект типа Bitmap, без явного задания глубины цвета, для формирования на экране монохромной картинки, но вместо исходного цвета надо будет установить новый, черный или белый, который дополнительно дублируем в битовый массив с размерностью, соответствующей числу пикселов изображения (128х64 = 8192). В программе будет добавлена возможность использовать два любых цвета, чтобы проверить, как будет выглядеть итоговая картинка на любом типе дисплея (негативном, позитивном) и с любым цветом подсветки, также добавим и кнопочку инверсии цвета.
Объявляем битовый массив:
Нужно иметь в виду, что массив содержит данные типа Boolean и в языке С# автоматического кастинга на тип int, как в С, не будет.
Выходной монохромный объект типа Bitmap используется только для визуального представления конвертированной картинки, его реальный размер и формат нас не интересует, достаточно того, что это изображение будет идентично монохромному, которое мы будем получать в среде разработки под микроконтроллер.
Инициировав массив, перебираем все пикселы исходного файла в цикле, получаем их цвет и определяем, достаточна ли интенсивность света в данной точке, чтобы считать ее «зажженой» на монохромном дисплее.
Использовано два подхода, классический, с «правильными» весовыми коэффициентами цетовых составляющих R,G,B: