Сложный способ GIF анимации.

Перевод статьи:  Animated GIFs the Hard Way.
Автор:  Jon Skinner.

Разрабатывая новый веб-сайт для релиза текстового редактора Sublime Text 2.0, с целью демонстрации его отдельных возможностей, вместо обычных скриншотов я решил применить элементы анимации. Один из критериев, которыми я руководствовался на тот момент, был направлен на то, чтобы анимация была доступна на всех устройствах – от IE6 до iPad, что исключало два распространенных способа включения видео — Flash и <video> элемент. Одним из возможных кандидатов на эту роль могли бы быть анимированные GIF изображения, но в этом случае имеются два препятствия, а именно: ограничение на глубину цвета (256 цветов), что значительно бы снизило качество анимации; и неприемлемо большой объем файлов, полученных после кодирования (почти 1 Мбайт на каждую анимацию).

В итоге я создал небольшой Python скрипт, принимающий в качестве исходников набор PNG фреймов и результатом работы которого является упакованный PNG файл, содержащий все требуемые различия между его фреймами (статическими картинками), а также метаданные в формате JSON, содержащие информацию о битах соответствующих каждому кадру упакованногоPNG файла. Далее, JavaScript скрипт на основе PNG файла и JSON метаданных создает требуемую анимацию, используя при этом элемент <canvas> или же эмулирует его с помощью наложенных друг на друга элементов <div> для старых браузеров.

Вот короткий фрагмент работы анимации такого типа:

которая упакована в этот PNG файл:

В результате объем данных, необходимых для анимации составляет 96 Кбайт плюс 725 байт на сжатые в формате gzip метаданные. Это соизмеримо с объемом статического PNG файла, являющегося в нашем случае одним фреймом. Помимо того, что данный метод имеет преимущество над анимированными GIF файлами в плане качества, используемый в данном случае JavaScript позволяет более гибко управлять процессом анимации. Именно этот подход используется для синхронизации текста и анимации на сайте Sublime Text, а также для автоматического переключения между анимационными кадрами.

Блок мета данных имеет следующий вид:

timeline =
[
{
"delay":623,
"blit":
[
[0,0,800,450,0,0]
]
},
{
"delay":182,
"blit":
[
[0,450,322,16,182,40],
[771,482,23,10,738,96],
[720,527,23,16,244,100],
[51,526,21,16,729,128],
[586,527,20,10,738,196],

]
},
{
"delay":194,
"blit":
[
[0,526,51,15,0,100],
[777,450,23,16,244,100],
[794,488,4,2,738,104],
[608,512,112,13,4,434]
]
},

]

Каждая запись в определенном выше фрагменте timeline описывает отдельный кадр данных. При помощи атрибута delay определяется время показа фрейма в миллисекундах, а второй атрибут blit определяет прямоугольные области изображения, которые подвергаются изменениям. В этих описаниях присутствует шесть цифр. Первые две определяют смещение в рамках общего упакованного PNG файла, следующая пара цифр указывает на ширину и высоту необходимой прямоугольной области и последние две являются координатами ее позиционирования в изображении.

Сам JavaScript код необходимый для создания анимации сравнительно небольшой. В случае применения элемента <canvas> прорисовка каждого прямоугольного фрагмента производится при помощи метода drawImage, а в режиме обратной совместимости со старыми версиями браузеров для создания необходимых фрагментов скрипт использует абсолютно позиционированные <div> элементы.

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

Получение кодировщика.

Вы можете загрузить модуль кодирования, перейдя по ссылке https://github.com/sublimehq/anim_encoder, применение которого ограничено весьма снисходительной BSD лицензией из трех пунктов. Но имейте в виду, что по существу скрипт был создан исключительно как стартовый вариант и поэтому могут возникнуть некоторые трудности в процессе работы с ним.

Необходимые условия.

Скрипт anim_encoder.py применялся исключительно в системе Ubuntu. Для его корректной работы необходимо расширение NumPy и библиотеки SciPy, OpenCV, которые доступны через консольную утилиту apt-get как python-numpy, python-scipy и python-opencv. Кроме того требуется установка утилиты Pngcrush в корневом каталоге системы.

Использование кодировщика.

В качестве входящих данных для скрипта необходимо использовать ряд PNG файлов, имена которых представлены в следующем формате — screen_([0-9]+).png. (*Согласно регулярному выражению [0-9]+ в имени файла должна присутствовать как минимум одна цифра.) Данное число является временным штампом определенного фрейма (конкретного файла) выраженное в миллисекундах. При этом абсолютные значения временных штампов не имеют значения, а учитывается только разница между ними. Вот пример:

example/screen_660305415.png
example/screen_660306038.png
example/screen_660306220.png
example/screen_660306414.png
example/screen_660306598.png
example/screen_660306790.png
example/screen_660307644.png
example/screen_660307810.png
example/screen_660307875.png
example/screen_660308049.png
example/screen_660308235.png
example/screen_660308285.png
example/screen_660309704.png

Запуск процесса кодирования в этом случае производится следующим образом:

./anim_encoder.py example

В результате будут сгенерированы два файла example_packed.png и example_anim.js, в который включены необходимые метаданные.

Как можно улучшить скрипт.
  • Сделать его более удобным в обращении. На данный момент кодировщик не выводит какую-либо справочную информацию в режиме командной строки, процесс сжатия анимации занимает много времени, к тому же, скрипт очень чувствителен к тому, какие данные ему предоставляются (к примеру, если входящий PNG файл содержит альфа канал, то произойдет сбой).
  • Включить в результирующий JavaScript код метод requestAnimationFrame, что позволит улучшить анимационные характеристики.
  • Повысить его быстродействие. Время работы скрипта не являлось критичным вопросом при его использовании для небольших анимационных элементов, для которых я, собственно, и применял его, но если использовать кодировщик для более сложных случаев, то время необходимое для его работы значительно увеличится.
  • Позаботиться о прогрессивной загрузке. На данный момент до тех пор пока все элементы анимации не будут полностью загружены, в браузере ничего не отображается. Но, тем не менее, учитывая то, что первый кадр анимации всегда находится в верхней части общего упакованного изображения, то не составит никакого труда отобразить его, пока все остальные компоненты подгружаются.
* Примечание переводчика.

Комментариев: 2 на Сложный способ GIF анимации.

    1. Ты тоже молодец! Заходил, тема бомба. Ты делаешь, а я пишу. Один — на дизайн пока времени не хватает.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *