Пони в консоли или Bash is Magic

+117
Qwizв блоге IT Pony!17 февраля 2013, 19:27
Всем привет.
Вот и нашлась наконец идея для моего первопоста. Увидев посты essir о консольных украшательствах, решил, наконец, воплотить в жизнь идею рисования в консоли Linux.
U MAD?u_mad_python
Так же подумал и я, но останавливаться было поздно.
Кому интересно, чем все закончилось — прошу под кат.



Первый рисунок решено было создать именно на bash, т.к с ним я знаком лучше всего. Так как разрешение стандартной консоли в Linux составляет 720х400 пикселей (при отсутствии X-сервера) и каждый символ имеет размер 8х16 пикселей, то максимальное разрешение картинки будет составлять всего 90х25 пикселей. Поэтому было решено делать рисунок в разрешении 32х16 символов, чтобы максимально уместить его на зкране и при этом не делать слишком мелким.

Исходное изображение было позаимствовано на deviantart у DShou
Создание рисунка заняло 20 минут изучения теории и примерно 2 часа монотонной писанины и подсчета пикселей в GIMP'е. Зато результат оправдал все ожидания.
Вот, что в итоге получилось:
Флаттершайfluttershy_in_bash
Код. Смотреть осторожно.
#!/bin/bash

export TERM=xterm-256color

# colors

mane1=213 #outline
mane2=225 #inner
body1=227 #outline
body2=229 #inner
eye1=23 #dark
eye2=30 #medium
eye3=43 #light
white=255 #white

# drawing

function draw {
case $2 in
	1) echo -ne "\E[48;05;${mane1}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";; 
	2) echo -ne "\E[48;05;${mane2}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	3) echo -ne "\E[48;05;${body1}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	4) echo -ne "\E[48;05;${body2}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	5) echo -ne "\E[48;05;${eye1}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	6) echo -ne "\E[48;05;${eye2}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	7) echo -ne "\E[48;05;${eye3}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	8) echo -ne "\E[00;00m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
	9) echo -ne "\E[48;05;${white}m"; for i in $(seq 1 $1); do echo -ne " "; done; tput sgr0;; #echo -ne "\E[48;05;${bcg}m";;
esac
}

draw 22 8
draw 7 1
draw 3 8
echo
draw 19 8
draw 1 1
draw 2 3
draw 3 2
draw 1 1
draw 4 2
draw 1 1
draw 1 8
echo
draw 18 8
draw 1 1
draw 1 3
draw 1 4
draw 5 3
draw 1 1
draw 4 2
draw 1 1
echo
draw 17 8
draw 1 1
draw 1 3
draw 8 4
draw 1 3
draw 1 2
draw 1 1
draw 1 2
draw 1 1
echo
draw 16 8
draw 1 1
draw 1 2
draw 1 1
draw 2 4
draw 2 8
draw 1 9
draw 1 7
draw 1 8
draw 1 4
draw 1 3
draw 1 1
draw 1 2
draw 1 1
draw 1 8
echo
draw 3 8
draw 6 1
draw 7 8
draw 1 1
draw 1 2
draw 1 1
draw 3 4
draw 1 9
draw 1 6
draw 1 5
draw 1 8
draw 2 4
draw 1 3
draw 1 1
draw 2 8
echo
draw 1 8
draw 1 1
draw 8 2
draw 1 1
draw 5 8
draw 1 1
draw 1 2
draw 1 1
draw 1 2
draw 1 1
draw 6 4
draw 1 3
draw 4 8
echo
draw 1 1
draw 3 2
draw 1 1
draw 4 2
draw 1 1
draw 1 2
draw 1 1
draw 4 3
draw 1 8
draw 1 1
draw 1 2
draw 1 1
draw 1 2
draw 1 1
draw 2 4
draw 1 3
draw 1 2
draw 2 1
draw 1 8
draw 2 1
draw 1 8
echo
draw 1 1
draw 2 2
draw 1 1
draw 2 2
draw 1 1
draw 2 8
draw 1 1
draw 1 3
draw 2 4
draw 1 2
draw 2 3
draw 2 4
draw 1 1
draw 3 2
draw 1 1
draw 1 3
draw 1 8
draw 1 1
draw 1 2
draw 1 1
draw 2 2
draw 1 1
draw 1 8
echo
draw 1 8
draw 1 1
draw 2 2
draw 1 1
draw 1 2
draw 1 1
draw 3 8
draw 1 3
draw 1 4
draw 1 3
draw 3 4
draw 1 3
draw 2 4
draw 1 1
draw 1 2
draw 2 1
draw 1 2
draw 1 1
draw 2 8
draw 2 1
draw 3 8
echo
draw 2 8
draw 1 1
draw 2 2
draw 1 1
draw 1 2
draw 1 1
draw 3 8
draw 1 3
draw 1 4
draw 1 3
draw 1 4
draw 1 3
draw 2 4
draw 2 3
draw 1 1
draw 3 2
draw 1 1
draw 7 8
echo
draw 3 8
draw 1 1
draw 2 2
draw 1 1
draw 1 2
draw 1 1
draw 1 8
draw 2 3
draw 3 4
draw 1 3
draw 1 8
draw 3 1
draw 3 2
draw 1 1
draw 8 8
echo
draw 2 8
draw 2 1
draw 2 2
draw 1 1
draw 1 2
draw 1 1
draw 2 3
draw 3 4
draw 1 3
draw 2 8
draw 2 3
draw 3 1
draw 1 3
draw 9 8
echo
draw 1 1
draw 1 2
draw 1 1
draw 2 2
draw 1 1
draw 1 2
draw 1 1
draw 1 8
draw 2 3
draw 3 4
draw 1 3
draw 2 8
draw 2 3
draw 3 4
draw 1 3
draw 9 8
echo
draw 1 8
draw 1 1
draw 1 2
draw 1 1
draw 6 8
draw 5 3
draw 3 8
draw 5 3
draw 9 8
echo



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

Сначала скрипт был тупой и умел только вырезать указанную часть изображения фиксированного размера и преобразовать её в консольные коды.
Флаттершайfluttershy_in_python
Пинки Пайpinkie_in_python
Рэйнбоу Дэшrainbow_in_python
Да, выглядит довольно коряво, но не так-то просто нарисовать нормальную картинку, которая содержала бы всего 512 пикселей.

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

UPD: Скрипт доступен на Github. Для запуска необходимы пакеты python и python-imaging. Инструкция по использованию скоро будет в readme там же.

Оригиналы картинок доступны по клику.
Пиксельная графика, как и ожидалось, переводится с минимальными потерями:
Пинки в консоли. Оригинал уменьшен в 4 разаpinkie_in_python_2
С векторами сложнее, для нормального качества нужно разрешение монитора около 2-3к пикселей в высоту.
Рарити в консоли. Оригинал уменьшен в 7 разrarity_python
На этом, пожалуй, я и закончу.
That's all folksthats_all_folks

19 комментариев

(В попытках написать консольный Paint на C++) Хмм… По-моему, echo умел брать escape-комбинации из файла, нет?
cab404
0
Да, так и есть. Для echo нет разницы, откуда к нему поступают данные, из файла или из stdin.
Qwiz
0
Дык тогда не легче в гимпе сохранить в escape, а потом echo?
cab404
0
Gimp умеет сохранять только в Ч/Б ASCII, или я чего-то не знаю.
Qwiz
0
Как-то так)
cab404
0
Ага, и получается (по крайней мере у меня) ч/б ascii-рисунок, к тому же вытянутый в высоту из-за неквадратности символов. А это совсем не то.
Qwiz
+1
Вот и задача для реализации!
cab404
0
Сделать цветной ascii? Можно, но уже не так интересно…
Qwiz
0
Аффтар, пеши есчо! Кросавчег!
Gwiny
0
Я не знаю почему пиксельные картинки поняшек вызвали у меня именно такую реакцию. Слишком многое хотелось выразить: и радость от узнавания собратьев-кодеров, и желание поощрить автора в продолжении его дела, да и вполне справедливую оценку рисунков. И каким-то невообразимым образом это все сложилось у меня в вышеупомянутую фразу.
Gwiny
0
Хех, спасибо. Вот только я не знаю, куда еще продолжать именно в этом направлении.
Буду благодарен, если подскажете интересную задачку для реализации =)
Qwiz
0
Анимированные пони в фоновом режиме, управление сигналами из другого процесса.
Hario
0
А вот это уже интереснее. Попробую.
Qwiz
0
молодца, все подробно и доходчиво, приятно осознавать, что мои посты кому-то интересны и полезны)
код изначально довольно длинный, но он стоит потраченных на него часов работы, яростно плюсую.
по поводу того, что предложил hario — SciencePony — он пилит чат-бота в консоли линуха ( на с++). делать интерфейс он не хочет, но если совместить ваши наработки, то цены такому проекту не будет!
могу еще посоветовать распатронить пакет ponysay, который я ранее описывал. там содержится довольно много изображений с понями, выполненных именно цветными блоками. может пригодиться.
так же могу посоветовать допилить в код твик для сохранения получившегося изображения как отдельный txt или png файл.
на этом пожалуй все, откланиваюсь и желаю тебе удачи в дальнейших наработках)
/me свалил запасаться PNG-пикчами с понями для перевода их в блоковое ascii.
essir
0
В txt его и сейчас можно переводить.
./big.py some_image.png > image txt

Потом командой cat image.txt его можно будет вывести.
Можно вместо image.txt направить вывод в /etc/motd, тогда при каждом логине будет выводиться картинка.

А по поводу интерфейса — его нет смысла делать таким способом. Есть много других более пригодных для этого библиотек. Например ncurses.
Qwiz
0
Можно вместо image.txt направить вывод в /etc/motd

об этом и был один из моих постов)
этого мало, надо еше делать строку cat /etc/motd.tail в bash.bashrc.
— а при таком переводе цвета ведь не сохраняются?
лучше тогда делать функцию перезаписи изображения с исходного на получившееся.
essir
0
Цвета должны сохраниться, если в начало bashrc добавить строчку
export TERM=xterm-256color


И да, насколько мне известно, добавлять /etc/motd.tail в bashrc не надо, т.к /etc/motd автоматически выполняется при каждом логине.
Qwiz
0
в tty да, а в bash нет. в любом случае, немного шаманства не помешает.
essir
0
Как это мило! ^^
a1batross
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.