Хотя GIF (Graphics Interchange Format, формат для обмена изображениями) не слишком полезен в современном Интернете, он является хорошим введением в основные концепции кодирования изображений.
GIF можно рассматривать как обёртку для данных изображения. У него есть своего рода область просмотра, называемая «логическим экраном», на которую наносятся отдельные кадры изображения — это немного похоже на слои в Фотошопе. Именно так GIF поддерживает анимацию, напоминающую флипбук: один кадр рисуется на логическом экране, затем он заменяется другим, затем ещё одним. Конечно, это различие не важно, когда мы имеем дело со статичным GIF, состоящим из одного кадра, нарисованного на логическом экране.
GIF использует метод сжатия данных без потерь — вариант алгоритма Лемпеля-Зива-Велча, если вам интересно. В тонкости работы этого алгоритма мы вдаваться не станем, но вкратце: он работает примерно так же, как и минификация JavaScript, где повторяющиеся строки символов во всём файле сохраняются в своего рода внутреннем словаре, чтобы на них можно было ссылаться, а не повторять каждый раз по мере их появления.
Конечно, алгоритм не так прост, как «раскраска по номерам». Он просматривает сгенерированную таблицу цветовых кодов, чтобы найти повторяющиеся последовательности цветов пикселей, и создаёт вторую таблицу кодов, на которую можно ссылаться. При этом данные изображения не теряются — они просто сортируются и реорганизуются таким образом, чтобы их можно было прочитать без существенных изменений.
Хотя технически GIF использует сжатие без потерь, у него есть серьёзное ограничение, которое сильно влияет на качество изображений: сохранение изображения в формате GIF всегда приводит к снижению чёткости, если только в изображении не используется 256 цветов или меньше.
Каждый кадр, выводимый на логический экран GIF, может содержать не более 256 цветов. GIF также поддерживает «индексную прозрачность», когда прозрачный пиксель ссылается на индекс прозрачного «цвета» в таблице цветов.
Практика сокращения диапазона значений до меньшего, аппроксимированного набора выходных значений называется квантованием — этот термин вы будете часто встречать, изучая кодирование изображений. Результаты такого квантования палитры обычно очевидны.
Чтобы лучше понять этот процесс, вспомните сетку растрового изображения, которую вам удалось воссоздать по моему описанию.
На этот раз добавьте чуть больше деталей к исходному изображению: ещё несколько пикселей, один из которых отличается более тёмным оттенком синего.
Без всякого сжатия, так сказать, вы можете описать эту сетку следующим образом:
Строка один, столбец один — #0000FF. Строка один, столбец два — #0000FF. Строка один, столбец три — #0000FF. Строка один, столбец четыре — #FF0000. Строка два, столбец один — #0000FF. Строка два, столбец два — #000085. Строка два, столбец три — #0000FF. Строка два, столбец четыре — #FF0000.
Используя сжатие данных без потерь и индексацию цветов как в GIF, вы можете описать это так:
A: #0000FF, B: #FF0000, C: #000085. Строка один, столбцы с первого по третий — A. Строка один, столбец четыре — B. Строка два, столбец один — A. Строка два, столбец два — C. Строка два, столбец три — A. Строка два, столбец четыре — B.
Это позволяет сократить попиксельное описание в нескольких местах («столбцы с первого по третий — это…») и сэкономить несколько символов за счёт определения повторяющихся цветов в своеобразном словаре. Визуальная точность не изменилась. Информация сжата без каких-либо потерь.
Однако, как видите, один-единственный тёмно-синий пиксель оказывает чрезмерное влияние на размер нашего кодирования. Если бы я ограничился квантованной цветовой палитрой, то её можно было бы уменьшить ещё больше.
A: #0000FF, B: #FF0000. Строка один, столбцы с первого по третий — A. Строка один, столбец четыре — B. Строка два, столбцы с первого по третий — A. Строка два, столбец четыре — B.
К сожалению, в результате экономии этих байтов вы теряете пиксельное совершенство.
Конечно, механизм отображения не знает этого — все детали тёмно-синего пикселя не учитывались при кодировании моего исходного изображения. Изображение отобразилось именно так, как я его закодировал, основываясь на общем понимании имеющихся у нас цветов.
Теперь, в этом утрированном примере, сокращение трёх цветов до двух даёт очевидную разницу в качестве. На более крупном и детализированном изображении эффект может быть не столь очевиден, но всё равно будет заметен.
При кодировании в GIF тонкие градиенты, например тени, становятся пёстрыми, а отдельные пиксели выделяются на фоне окружающего пространства.
На практике сочетание сжатия без потерь и квантования палитры означает, что GIF не очень полезен в современной веб-разработке. Сжатие без потерь не позволяет уменьшить размер файла, а уменьшение палитры означает очевидное снижение качества.
В конечном счёте, GIF — это эффективный формат для кодирования простых изображений, в которых уже используются ограниченные цветовые палитры, чёткие края, а не сглаживание, и сплошные цвета, а не градиенты — вот те случаи использования, для которых гораздо лучше подходят другие форматы. Меньший по размеру и более функциональный PNG часто является лучшим выбором для растровых изображений, хотя оба они значительно уступают SVG по размеру файла и визуальной достоверности для таких случаев использования, как иконки или линейные рисунки, где векторные изображения просто великолепны. Наиболее распространённым современным вариантом использования GIF является анимация, но для этой цели существуют гораздо более эффективные и доступные современные форматы видео.