Back

ASCII-арт в браузере и терминале

ASCII-арт в браузере и терминале

Идея проста: взять изображение, измерить яркость каждого пикселя и заменить его символом. Плотные символы вроде @ или # представляют тёмные области, а более светлые, такие как . или (пробел), представляют яркие области. Соберите достаточное количество таких замен в сетку — и вы получите узнаваемое изображение, полностью состоящее из текста.

Эта базовая идея лежит в основе как ASCII-арта в терминале, так и ASCII-арта в браузере, а современные реализации вышли далеко за пределы классической 7-битной ASCII.

Ключевые моменты

  • ASCII-арт сопоставляет яркость пикселей с символами из отсортированной палитры, где плотные глифы вроде @ представляют тёмные области, а разреженные вроде . — светлые
  • Блочные элементы Unicode и паттерны Брайля обеспечивают значительно более высокое разрешение по сравнению с традиционными палитрами ASCII-символов
  • Реализации в браузере опираются на пиксельные данные <canvas> и моноширинный CSS, в то время как терминальные рендереры используют ANSI escape-последовательности для цвета
  • Возможности терминалов сильно различаются — от базовой 16-цветной ANSI до 24-битного true color, SIXEL и графического протокола Kitty

Как работает сопоставление пикселей и символов

Каждый ASCII-рендерер следует примерно одному и тому же конвейеру:

  1. Разбить исходное изображение или видеокадр на сетку ячеек
  2. Вычислить среднюю яркость (luminance) каждой ячейки
  3. Сопоставить это значение яркости с символом из отсортированной палитры
  4. Вывести полученную сетку символов с опциональным цветом

Базовая реализация на JavaScript выглядит так:

const palette = ' .:-=+*#%@';

function brightnessToChar(brightness) {
  const index = Math.floor((brightness / 255) * (palette.length - 1));
  return palette[index];
}

Здесь предполагается, что brightness — это значение от 0 (чёрный) до 255 (белый). Функция нормализует его до индекса в строке палитры, где более ранние символы представляют светлые тона, а более поздние — тёмные.

Качество результата сильно зависит от вашей палитры символов. Классическая ASCII даёт около 10–15 полезных уровней затенения. Современные реализации справляются лучше.

За пределами ASCII: текстовая графика с Unicode

Текстовая графика с Unicode открывает значительно более высокое разрешение. Вместо разреженной ASCII-палитры можно использовать:

  • Блочные элементы (█ ▓ ▒ ░) для четырёх уровней затенения на ячейку
  • Паттерны Брайля (⣿ ⠿ ⠛), которые кодируют до 8 точек в одном символе, обеспечивая более высокое эффективное разрешение по сравнению с традиционными ASCII-палитрами
  • Символы рисования рамок для структурированных макетов и границ

Chafa, программа для просмотра изображений в терминале, использует блочные символы Unicode и символы Брайля для рендеринга изображений почти фотографического качества в терминале. Разница по сравнению с обычным ASCII разительна.

ASCII-арт в браузере: подходы с Canvas и WebGL

JavaScript-рендеринг ASCII в браузере обычно использует элемент <canvas> в качестве источника изображения. Процесс:

  1. Нарисовать изображение или видеокадр на невидимом canvas
  2. Прочитать пиксельные данные с помощью ctx.getImageData()
  3. Разбить сетку пикселей на ячейки и сопоставить каждую с символом
  4. Отрендерить результат в элемент <pre> или обратно на canvas с помощью fillText()

Библиотеки вроде p5.js делают это простым, позволяя обрабатывать живые потоки с веб-камеры или видеокадры в реальном времени. Для более высокой производительности шейдеры WebGL могут обрабатывать выборку яркости и поиск символов на GPU, что важно при рендеринге полноценного видео с частотой 30 кадров в секунду.

Для статического отображения настройка HTML/CSS минимальна, но важна:

.ascii-art {
  font-family: monospace;
  white-space: pre;
  line-height: 1;
  letter-spacing: 0;
}

Без white-space: pre браузер схлопывает пробелы и разрушает макет. Без моноширинного шрифта символы имеют неравную ширину, и сетка разваливается. Установка letter-spacing: 0 предотвращает тонкие горизонтальные промежутки, которые некоторые браузеры добавляют по умолчанию.

ASCII-графика в терминале: ANSI-цвет и вариативность протоколов

В терминальных средах ASCII или Unicode-символы выводятся в стандартный вывод. Цвет добавляется через ANSI escape-последовательности. Современные терминалы поддерживают 24-битный (true color) вывод:

printf '\033[38;2;255;100;0m%s\033[0m\n' "orange text"

Это устанавливает цвет переднего плана в RGB(255, 100, 0) с помощью последовательности 38;2;R;G;B, затем сбрасывает форматирование с помощью \033[0m.

Инструменты вроде jp2a и ascii-image-converter используют этот подход для создания цветной терминальной ASCII-графики из файлов изображений.

Однако возможности терминалов значительно различаются. Некоторые терминалы поддерживают только базовую 16-цветную ANSI. Другие поддерживают 256-цветный режим, полный 24-битный true color, графику SIXEL или графический протокол Kitty, который может рендерить настоящие пиксельные изображения внутри терминала, а не символьные приближения. Обработка ширины Unicode также различается между терминалами, поэтому символы Брайля или широкие символы могут смещаться в зависимости от окружения.

Заключение

Пишете ли вы JavaScript ASCII-рендерер для браузера или передаёте данные изображения через терминальный инструмент, базовая логика идентична: пиксели становятся символами, яркость становится плотностью, а цвет становится escape-кодами или CSS. Браузер даёт вам точный контроль над шрифтами и макетом, в то время как терминал даёт скорость и композируемость. Выбор среды определяет инструментарий, но конвейер преобразования — выборка, измерение, сопоставление, рендеринг — остаётся неизменным.

Часто задаваемые вопросы

Большинство моноширинных символов выше, чем шире, поэтому каждая ячейка символа не является идеальным квадратом. Это вертикальное растяжение искажает изображение. Вы можете компенсировать это, настроив line-height в CSS, масштабировав исходное изображение до неквадратного соотношения сторон перед преобразованием или выбирая меньше строк относительно столбцов.

Упорядочьте символы по их визуальной плотности, от самого светлого к самому тёмному. Более длинная палитра даёт больше уровней затенения и более плавные градиенты. Протестируйте свою палитру, отрендерив градиентное изображение и проверив наличие видимых полос. Блочные элементы Unicode и паттерны Брайля обеспечивают более тонкую детализацию по сравнению со стандартными ASCII-символами.

Да. В браузере рисуйте каждый видеокадр на невидимом canvas, читайте пиксельные данные и сопоставляйте ячейки с символами на каждом кадре анимации. Для приемлемой производительности при 30 кадрах в секунду держите разрешение сетки символов умеренным или переносите вычисление яркости на WebGL-шейдер. Терминальные инструменты вроде Chafa также поддерживают видеовход.

Символы Брайля относятся к Unicode, и их отображаемая ширина зависит от эмулятора терминала и активного шрифта. Некоторые терминалы обрабатывают их как широкие символы, другие — как узкие. Если ваш вывод выглядит сломанным, протестируйте с другим терминалом или шрифтом. Инструменты вроде Chafa определяют возможности терминала и соответственно настраивают режим вывода.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay