Создание анимированных GIF средствами Java

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

Для начала упомяну платное решение — библиотеку Gif4J. Согласно приведенной на главной странице проекта информации, библиотека позволяет не только создавать анимированные GIF-изображения, но и изменять их размер, настраивать цветовой баланс, ставить водяные знаки, получать метаданные из изображений, добавлять текст и т.п. Словом, охватывает весь спектр необходимых действий по работе с GIF-изображениями.

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

Класс GifSequenceWriter, разработанный Эллиотом Кру, который можно скомпилировать и запустить (он содержит метод main), преобразует несколько файлов одинакового размера в GIF-анимацию. В качестве настроек можно указать, нужно ли зацикливать анимацию или нет, и длительность каждого кадра. Именно им я и воспользовался для решения своей задачи:

Прим. В комментариях в коде неверно описаны параметры:

На самом деле третий параметр задает задержку перед сменой кадра в сотых долях секунды, а четвертый — нужно ли зацикливать анимацию, и значение false указывает, что зацикливания не будет. Поэтому по умолчанию анимация не зацикливается и кадры сменяются каждую сотую долю секунды.

Коротко поясню, как работает GifSequenceWriter. В нем GIF-файл описывается через метод setAttribute класса IIOMetadataNode в соответствии со спецификациями w3.org, после чего результат записывается ImageWriter’ом в выходной файл.

Однако у реализованного подхода есть два недостатка. Во-первых, он совершенно не сжимает выходной файл, а потому его размер оказывается неоправданно большим. Помочь справиться с этой проблемой вам может один из специальных инструментов, доступных онлайн — например, Compressor.io.

Во-вторых, GifSequenceWriter, как и многие другие реализации, не решает проблемы с прозрачными пикселями: в каждом следующем кадре сквозь них просвечивают пиксели предыдущего. Например, вот эти две картинки:

pic3  pic5

Объединяются в следующую анимацию:

Иногда это может быть неудобно. Для решения этой проблемы существует класс GifFrame. Он индексирует один из цветов как прозрачный (по умолчанию в примере это 0xFF00FF, то есть пурпурный). Результат для вышеупомянутой пары изображений будет иметь следующий вид:

Кстати, в коде, приведенном по ссылке не хватает import‘ов. Для вашего удобства перечислю их здесь:

Для обеспечения аналогичной функциональности вышеупомянутому классу GifSequenceWriter можете добавить следующий метод main:

Также набор интересных сниппетов по работе с GIF изображениями на Java приведен по этой ссылке.

Антон Машков, глав.вред Tproger