- PVSM.RU - https://www.pvsm.ru -
Эта история началась, когда я узнал о существовании bpytop [1]. Меня поразила детализация графиков и я начал разбираться как это сделано. Оказалось, что для вывода графиков использовались символы алфавита Брайля, представляющие из себя комбинацию из 8 точек: 2 точки в ширину и 4 точки в высоту. Поискав готовые решения, использующие этот подход, я нашел на реддите анонс [2] такого проекта [3]. В первом же комментарии анонса я прочитал:
Это конечно круто, но почему люди просто не переоткроют для себя ReGIS (векторную графику в терминале) и sixel (пиксельную графику в терминале).
До этого момента я ничего не знал про sixel. Копнув глубже я выяснил, что в теории sixel должен поддерживаться xterm-ом. Я запустил xterm на своей ubuntu 20.04 в режиме эмуляции vt340
xterm -xrm "XTerm*decTerminalID: vt340" -xrm "XTerm*numColorRegisters: 256"
выполнил вот такую команду (convert это команда из пакета imagemagick)
clear && convert <(curl -s https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png) sixel:-
и увидел вот это:

Вау, работает!
Первым делом я проверил, что по sixel можно найти на хабре. Оказалось, что не много. Есть очень краткая статья [4] 2010-го года без технических подробностей и упоминание в комментариях к статье [5] о портировании Far на линукс. Давайте разберемся, как работает sixel и как с его помощью можно рисовать в совместимом терминале.
Включение режима sixel осуществляется escape последовательностью DCSp1;p2;p3;q, где DCS это Device Control Sequence (может быть либо восьмибитным символом с десятичным значением 144, либо последовательностью двух семибитных символов «Escape», «P». Параметры p1, p2 и p3 необязательны.
| p1 | Pixel Aspect Ratio (Vertical:Horizontal) |
| Не указан | 2:1 (default) |
| 0, 1 | 2:1 |
| 2 | 5:1 |
| 3, 4 | 3:1 |
| 5, 6 | 2:1 |
| 7, 8, 9 | 1:1 |
Этот параметр является устаревшим. В современном коде его надо выставлять в 0 и использовать атрибут управления растром в sixel строке. Подробности можно посмотреть в документации [6].
p2 может принимать 3 значения и определяет как терминал рисует фоновый цвет.
| p2 | Что делает |
| 0 or 2 (default) | Пикселы со значением 0 рисуются текущим фоновым цветом. |
| 1 | Цвет пикселов со значением 0 не меняется. |
Параметр p3 управляет горизонтальным шагом сетки (расстоянием между соседними пикселями). Этот параметр игнорируется если у устройства вывода неизменяемый шаг сетки.
В своих экспериментах в xterm-е я всегда входил в sixel режим при помощи последовательности 0x1bPq (0x1b — escape) не используя опциональные параметры.
Выключение sixel режима осуществляется последовательностью ST (String Terminator). ST может быть либо восьмибитным символом с десятичным значением 156 либо последовательностью двух семибитных символов «Escape, backslash» (ESC ).
После перевода устройства вывода в sixel режим нам нужно подать на него графические данные. Название sixel является производной от six pixels. В режиме sixel мы рисуем за раз столбик из 6-ти пикселов (младший бит является верхним). Отрисовка осуществляется выбранным цветом (об этом чуть позже). Значение одного сиксела может быть от 0 (все биты 0) до 63 (все биты 1). Это значение прибавляется к 63 (ascii ‘?’). Таким образом пустой сиксел представляется символом ‘?’, а сиксел у которого все биты выставлены в 1 символом ‘~’.
Формат sixel предусматривает примитивную компрессию. Конструкция ‘!42~’ означает, что мы хотим вывести сиксел ‘~’ 42 раза. В официальной документации не упомянуты ограничения на значения счетчика. При этом известно [7], что vt240 при дампе графических данных не использует значения больше 255.
При выводе sixel строки есть 2 способа управления курсором. Символ ‘$’ переводит курсор в начало той же строки. Это позволяет выводить пикселы разного цвета. Можно выбрать цвет, вывести набор сикселов, вернуться в начало той же строки, выбрать другой цвет, вывести другой набор сикселов. После того, как текущая строка прорисована как надо можно воспользоваться символом ‘-’ и перевести курсор на следующую строку.
Управлением цветом осуществляется 2 этапа. Сперва нам надо определить цветовые регистры. Это можно сделать командой #NN;p1;p2;p3;p4. Здесь
Теперь для переключения на определенный цвет нам надо использовать команду вида #NN.
Вооруженные этой информацией мы можем написать код [8], который выведет нам вот такое изображение:

Для сравнения вот как будет выглядеть то же изображение выведенное кодом [9] с использованием символов алфавита Брайля:

И то же изображение выведенное кодом [10] с использованием простого ascii:

Автор: kt97679
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/nenormal-noe-programmirovanie/361826
Ссылки в тексте:
[1] bpytop: https://github.com/aristocratos/bpytop
[2] анонс: https://www.reddit.com/r/tinycode/comments/ahriz5/pixel_graphics_in_terminal_with_unicode_braille/
[3] проекта: https://github.com/asciimoo/drawille
[4] статья: https://habr.com/ru/post/102315/
[5] статье: https://habr.com/ru/post/524370/
[6] документации: https://vt100.net/docs/vt3xx-gp/chapter14.html
[7] известно: https://www.digiater.nl/openvms/decus/vax90b1/krypton-nasa/all-about-sixels.text
[8] код: https://github.com/kt97679/misc/blob/master/terminal-graphics/mandelbrot-sixel.py
[9] кодом: https://github.com/kt97679/misc/blob/master/terminal-graphics/mandelbrot-utf8.py
[10] кодом: https://github.com/kt97679/misc/blob/master/terminal-graphics/mandelbrot-ascii.py
[11] Источник: https://habr.com/ru/post/543594/?utm_source=habrahabr&utm_medium=rss&utm_campaign=543594
Нажмите здесь для печати.