Рисуем код из «Матрицы» на PHP

Однажды мне пришла в голову идея сделать динамически создаваемый фон для блога в виде пресловутого кода из фильма «Матрица». После убийства вечера и половины ночи я-таки достиг желаемого результата, и решил поделиться им с народом. К сожалению, я не нашёл подобной реализации, а иметь динамически создаваемую «матрицу» как фон бложика таки хочется.
Итак, пишем генератор кода «Матрицы» на PHP с использованием библиотеки gd.

Итак, поставлены следующие требования к генерируемой картинке:
1. Столбики кода не должны быть равны по длине, длина должна выбираться случайно
2. Яркость цвета должна нарастать сверху вниз
3. Расположение столбиков должно быть случайным, но они не должны налезать друг на друга
4. Полученная картинка не должна кэшироваться браузерами, дабы при каждом обновлении получался новый код
5. Код не должен улетать за пределы картинки.

Приступим, собственно, к генерации картинки.

Для начала надо придумать, что будет выступать в роли элементов кода. В «Матрице» использовались как цифры, так и кана (слоговая азбука японского языка). Последняя выглядят более эффектно, следовательно, её и возьмём.
Создадим функцию getJapanSym(), возвращающую HTML-Entity код (его использует функция imagettftext(), но о ней позже).
В Unicode кана расположена в диапазоне кодов от 0x3040 до 0x30FF. Из этого диапазона и требуется брать случайный код символа. В результате получаем вот такую функцию:
function getJapanSym()
{
	$rnd = rand(hexdec("3040"), hexdec("30FF")); // то-ли лыжи не едут, то-ли у меня кривой сервер, но с числами в формате 0xXXXX он работать отказался
	return "&#x".dechex($rnd).";"; // формат HTML-Entity, нечто вроде ア
}


Далее нам требуется отрисовать собственно картинку. Давайте по порядку.
Первым делом нам нужно нарисовать столбик с каной с заданным количеством знаков. Для отрисовки будем использовать упомянутую ранее функцию imagettftext() из библиотеки gd. Более того, цвет каждого символа должен отличаться от предыдущего, так что простым \n тут не обойтись, придётся писать целый цикл.
Саму кану можно найти в шрифте Arial Unicode MS, который мы, собственно, и используем.
Функция для рисования каны в столбик выглядит так:
for ($i = 0; $i < $symCount; $i++) // переменная $symCount отвечает за количество знаков в столбике
	{
		imagettftext(
				$img, // ресурс картинки
				10, // размер шрифта
				0, // угол наклона, нам он не нужен, так что 0
				$codePlacement, // ось X, она же начальная координата столбика
				$symPadding, // ось Y, она должна меняться для каждого символа
				hexdec("00".dechex($printCol)."00"), // цвет, о нём мы поговорим позже
				"./arial.ttf", // указание файла шрифта. Маны PHP рекомендуют абсолютный путь
				getJapanSym() // собственно, элемент, записанный в формате HTML-Entity
			    );

		$symPadding += 15; // прибавляем к значению оси Y для следующего символа. Значение подбирается экспериментально, в зависимости от размера шрифта и самих символов
	}

Для удобочитаемости и комментирования каждый параметр вынесен на отдельную строку.

Описанный выше код нарисует просто столбик с каной. Но нам нужно его ещё и раскрасить, причём первый символ должен быть еле виден на чёрном фоне, а последний, соответственно, должен быть самым ярким. Для этого введена переменная $printCol, отвечающая за зелёный компонент в RGB-представлении.
Допишем перед циклом несколько переменных:
	$colorIncrement = round(254 / $symCount);
	$printCol = 16;


Первая переменная — инкремент цвета — рассчитывается как отношение всех возможных цветов к количеству иероглифов в столбце. Этот инкремент будет плюсоваться после отрисовки каждого иероглифа.
Вторая переменная, $printCol — собственно, сам цвет. Начальным цветом выбран 16, и не случайно. 16 в шестнадцатеричной системе счисления равно 10, то бишь два символа, и это нужно, чтобы не «сломать» вид кода цвета «00XX00», ровно 6 символов в шестнадцатеричной системе.
Теперь используем наше нововведение в основном цикле:
$colorIterate = round(254 / $symCount);
$printCol = 16;
for ($i = 0; $i < $symCount; $i++)
	{
		imagettftext($img, 10, 0, $codePlacement, $symPadding, hexdec("00".dechex($printCol)."00"), "./arial.ttf", getJapanSym());
		$symPadding += 15;
		$printCol += $colorIncrement; // прибавляем к цвету коэффициент пропорциональности для следующего символа
	}


Вот теперь этот участок выведет уже готовый столбик красивых символов каны с правильной цветовой окраской. Заметьте, что для задания цвета используется конструкция
hexdec("00".dechex($printCol)."00")
. Возможно, это выглядит глупо, но в php инкремент выполняется в десятичной системе счисления, а нам нужно число в шестнадцатеричной, причём, как сказано ранее, меняем только зелёный цвет.

Итак, теперь нам нужно нарисовать несколько таких столбиков, чтобы получился полноценный «матричный» код. Думаю, здесь потребуется меньше разъяснений, и хватит кода с комментариями.
$img = imagecreatetruecolor (500, 500); // создание картинки размером 500x500. Фон у неё по умолчанию чёрный.

$position = 4; // начальная позиция первого столбика с каной
for ($rows = 0; $rows < 50; $rows++) // рисуем 49 столбиков с кодом (число подбирается также экспериментально, сколько влезет на картинку)
{
	$symPadding = rand(3, 450); // выбираем положение по координате Y для самого первого символа. Не меньше трёх и не больше 450, иначе нет смысла рисовать
	$symCount = round((rand($symPadding + 100, 500) - $symPadding) / 17); // рассчитываем, сколько надо нарисовать символов, чтобы не залезть за пределы картинки и при этом выбрать случайное кол-во
	$colorIncrement = round(254 / $symCount); // инкремент цвета, был описан ранее
	$printCol = 16; // первоначальный цвет, также описан ранее
	$codePlacement = rand($position - 4, $position + 1); // размещение столбика с каной по оси X, всегда постоянно, но выбирается в промежутке, причём таком, чтобы столбики не наползали друг на друга

	for ($i = 0; $i < $symCount; $i++) // рисуем столбик. Это описано ранее.
	{
		imagettftext($img, 10, 0, $codePlacement, $symPadding, hexdec("00".dechex($printCol)."00"), "./arial.ttf", getJapanSym());
		$symPadding += 15;
		$printCol += $colorIncrement;
	}

	$position += 20; // прибавляем 20 пикселов к возможному расположению следующего столбика

}


Итак, мы уже имеем готовый код «Матрицы» в переменной $img, осталось только его вывести. Но здесь маленькая хитрость: браузеры любят кэшировать фон. Следовательно, чтобы юзер каждый раз видел новый фон, требуется запретить кэширование при помощи заголовков. Делаем это вот так:

header("Cache-Control: no-store"); // попытка запрета номер "раз"
header("Expires: " . date("r")); // попытка запрета номер два
header("Content-Type: image/png"); // сообщаем, что сейчас будет картинка, а не текст
imagepng ($img); // выводим картинку
imagedestroy($img); // уничтожаем картинку и удаляем её из памяти.


В результате получаем вот такое вот изображение:
image
Можете пообновлять страничку, каждый раз скрипт выдаст новый код

К сожалению, браузер Firefox не умеет правильно отображать фон после обновления, и получается слияние двух версий, остальные же браузеры подобным не страдают.

[UPD]: исходник Матрицы со шрифтом и без оного.
Поделиться публикацией
Комментарии 59
    +14
    Симпатично. Однако, кажется, в фильме если и использовались каны, то зеркально отраженные. Там создавалось впечатление какого-то непонятного кода, а в данной реализации четко видны иероглифы.
      –48
      Честно сказать, я не смотрел фильм, видел только его заставку. Тем не менее, кану я там усмотрел.
        +59
        Вы только что подписали свой смертный приговор…
            0
            Черд, придется теперь пересматривать… Только на этот раз я знаю английский
              0
              Спасибо за идею. Понял что тоже не смотрел в оригинале.
            +4
            Из Википедии:
            This code includes mirror images of half-width kana characters and Latin letters and numerals.


            Так что кроме катаканы действительно есть латиница и цифры, и все это зеркально отраженное.

            В общем-то в сети можно найти кучу готовых шрифтов, состоящих из символов, максимально близких к оригиналу.
            +13
            Просто мы с вами знаем кану. Для остальных людей, что зеркаль, что не зеркаль — одинаково странные значки.
              0
              ЕМНИП, там еще не было хираганы, а катакана была не вся.
              +1
              Ссылкой на демо не поделитесь ли?
              +2
              А сколько время выполнения скрипта и генерации этой всей штуки?
                +2
                Не тестировал, хотя, в принципе, можно и подписать. Сейчас попробую.
                  +5
                  image

                  Время генерации картинки по запросу masterr.
                  +2
                  Честно говоря не понял, в чем проблема с фоном в фф — у меня на win7 и фф 10.0.2 всё ок
                    +1
                    Если просто фон — то да. Но если на странице есть динамические объекты, и, не закрывая страницу, нажать F5, а потом использовать объекты, получается нечто вроде этого:
                    image

                    Здесь малозаметно, но получаются огрызки от двух фонов.
                      0
                      Очень трудно было поймать баг, даже при создании скриншота фон выравнивался. Пришлось фотографировать.
                      Выглядит этот глюк вот так:
                      image
                        +4
                        О, здравствуйте, конфликтер. )
                        Приятно видеть в Есениных айтишников. :)
                          +1
                          Если что, фото не с моего блога.
                            0
                            Понятно. Ну ладно, что ж. :)
                              +2
                              «Есенин» — это что-то из соционики?
                                0
                                да, это Интуитивно-этический интроверт…
                            0
                            Приятно видеть любого айтишника, увлекающегося соционикой и психологией =)
                            Я, кстати, дост)
                              +1
                              А я не понимаю соционику.
                                0
                                Да, именно. Дуал-айтишник — как это прекрасно! )
                        +46
                        Там с вами саппорт хочет побеседовать насчет нагрузки на сервер
                          +3
                          Если вы видите эту страницу значит ваш сайт превысил все допустимые лимиты на потребляемые ресурсы. Обратитесь в техподдержку за разъяснениями.
                          А вот и хабраэффект.
                          Тем не менее посмотреть успел. Очень неплохо.
                            +1
                            Хостинг за 40 рублей, как же без хабраэффекта…
                            +2
                            ИМХО, этот скрипт использовать на продакшене нельзя. А вот с его помощью сгенерировать тысячу статичных картинок, и их уже раздавать — это можно.
                              +1
                              главное, что он пригодится.
                              0
                              Вам не кажется, что символы слишком быстро и слишком плавно затухают?
                                +1
                                Динамики, динамики не хватает.
                                  +2
                                  Ждем от автора генерацию анимированного GIF в следующей статье.
                                    0
                                    Хм, многие спрашивали про GIF. Но изначально это писалось для фона, а анимированный фон — зло.
                                    Если будет желание и время, а так же хватит познаний — сделаем и GIF.
                                    А может, меня кто-то опередит, вроде Alexufo.
                                  0
                                  Катакана и хирагана — это не иероглифы. Для стороннего человека разницы, наверное, нет. Но всё равно, называть их так — неправильно :)
                                    0
                                    Можно это назвать каной? Я исправлю статью.
                                      0
                                      Да, это называют каной.
                                        0
                                        Спасибо за поправку, убрал «иероглифы».
                                          0
                                          Не везде :)
                                    +44

                                    :-)
                                      +3
                                      Нужно было контур из сочетания "パンのローフ" составить, а то без буханки хлеба и троллейбус не троллейбус.
                                        0
                                        Спасибо. Поднял настроение.
                                          0
                                          Я чего-то снова не понимаю.
                                        +1
                                        Если мне не изменяет память, в матрице символы двигались…
                                          +9
                                          Она зависла.
                                          +1
                                          Плохо, что сам файл с кодом не выложили
                                            0
                                            Последний код полностью генерирует картинку.
                                              0
                                              На хабре вроде бы принято, что если пост о коде, то нужно выкладывать исходник
                                                +1
                                                Ну, я здесь совершенно новый. Извините. Сейчас исправим сию ошибку. Только приготовлю оригинальный код, а то там ужас творится в комментариях.
                                                  +1
                                                  Исправился.
                                                    0
                                                    Спасибо
                                              0
                                              А реализовать таки динамическую матрицу на JS слабо? :)
                                              0
                                              В настоящей Матрице используется полуширинная катакана (0xFF61-0xFF9F), отраженная по вертикали.
                                                0
                                                Вы меня прям вдохновили на Canvas-версию!
                                                ramzes.name/
                                                  0
                                                  Эпично!

                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                Самое читаемое