Этот сайт — моя персональная записная книжка. Интересны мне, по большей части, программирование, история и события из моей жизни.

Рисование азбукой Брайля

Если помните, недавно я, вдохновлённый строчкой из песни «в каждой строчке — только точки», пытался выяснить что вообще можно записать точками, если использовать азбуку Морзе. Мне тогда один из комментаторов напомнил про шрифт Брайля — тактильный шрифт для слепых, состоящий из точек.

Он есть в Юникоде, поэтому на экране им можно написать что угодно и, как и требуется в песне, там будут только точки. Я тогда подумал, что «что угодно» можно трактовать и шире — если постараться, точками этого шрифта можно выводить в консоли любую графику.

Сегодня, как это что-то часто за мной водится в последнее время, мне не спалось и хотелось не просто бездумно лежать, глядя в потолок, а найти себе какой-нибудь занятие. Вот я и вспомнил про эту идею. Оказалось, кстати, что я не один до неё додумался и библиотек, которые таким образом что-то выводят в консоль очень много.

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

Таким образом у нас получается блок 2×4, где мы, подбирая код символа, можем получить любое сочетание точек. Я боялся, что в расположении точек нет никакой системы, но к моему счастью оказалось, что каждая точка, которую надо закодировать, отображается на конкретный бит численного представления нужного символа.

Оставалось только решить, что я, собственно, буду выводить. Это должно быть что-то простое и одноцветное — набор из восьми точек можно покрасить только в один цвет, поэтому лучше цвета не использовать вообще. Поскольку в последнее время я много вожусь с браузером «Виола», где много однобитной графики в формате XBM, то я решил выводить картинки в этом формате — тем более, что он текстовый, что мне на руку.

Так, к примеру, выглядит картинка с логотипом «Виолы» в этом формате:

#define violaLogo_width 32
#define violaLogo_height 20
static char violaLogo_bits[] = {
   0xe0, 0x03, 0x00, 0x00, 0x18, 0x0c, 0x0f, 0x00, 0xe4, 0x8b, 0x30, 0x00,
   0xfa, 0x8f, 0x4f, 0x00, 0xfa, 0xff, 0xff, 0x00, 0xfd, 0xff, 0xff, 0x50,
   0xfd, 0x2f, 0xe9, 0xff, 0xfd, 0x07, 0x00, 0x00, 0x7d, 0xfc, 0xff, 0x50,
   0xbd, 0xfd, 0xff, 0x00, 0xba, 0x3b, 0x7f, 0x00, 0x3a, 0xdb, 0x1e, 0x00,
   0x7c, 0xd7, 0x00, 0x01, 0x78, 0xd6, 0x06, 0x19, 0xe0, 0xce, 0x00, 0x25,
   0x00, 0xcc, 0x32, 0x21, 0x00, 0xd8, 0x5a, 0x39, 0x00, 0xf0, 0x6a, 0x25,
   0x00, 0x60, 0x32, 0x79, 0x00, 0x00, 0x00, 0x00};

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

load_xbm() {
    local file="$1" hex h

    W=$(awk '/^#define.*_width/ {print $3;exit}' "$file")
    H=$(awk '/^#define.*_height/{print $3;exit}' "$file")
    BPR=$(( (W + 7) / 8 ))

    for h in $(sed -n '/{/,/}/{/{/d;s/}.*//;s/0x//g;y/,/ /;p;}' "$file"); do
        BYTES+=($[16#$h])
    done
}

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

Блокнот с моими попытками объяснить себе как будут выводиться точки

В итоге получился небольшой скрипт, в котором, если убрать все пустые строки, около полусотни строчек. Я его выложил, как водится, на «Гитхаб».

Пример вывода двух картинок, взятых из набора браузера «Виола»
2 комментария
hsh 27 дн

Есть ли выигрыш по размеру?

Евгений Степанищев 27 дн

Между чем и чем? Я не понял.

hsh 27 дн

насколько UTF проигрывает XBM?

Евгений Степанищев 27 дн

Он не проигрывает:

890 392 ./xbm/violaIcon.xbm
872 392 ./xbm/WWW.xbm
590 245 ./xbm/violaLogo.xbm
872 392 ./xbm/map.xbm

Первое — размер файла, второе — размер в Брайле