Сжатие GIF через gzip
Эксперимент мой сжатию несжатых ГИФ, по сути, провалился — если статические изображения иногда оказываются меньше (или сравнимы) с PNG, то с анимированными изображениями, ради которых всё и затевалось, всё плохо, я не сумел подобрать условия, при которых новоявленный метод обгоняет обычные соптимизированные ГИФы.
Зато я попутно выяснил, что ГИФ, вопреки моим ожиданиям, иногда жмётся gzip, на первой попавшейся анимации я получил выигрыш порядка 9%. Так что вот он метод ещё больше утоптать файлы ГИФ:
#!/bin/sh
which -s defluff
if [ $? -eq 0 ]; then
gifsicle -O3 "$1" | gzip -9nc | defluff 2>&- > "$2".temp
else
gifsicle -O3 "$1" | gzip -9nc > "$2".temp
fi
size=( $(ls -l "$2".temp) )
# срезаем заголовок gzip и контрольную сумму
let 'size=size[4]-10-8'
dd if="$2".temp of="$2" bs=1 skip=10 count=$size 2>&-
rm -f "$2".tempВ настройки Апача надо добавить новое расширение файла:
AddEncoding deflate .gif-def
AddType image/gif .gif-defДля браузера вместо gzip я указываю метод deflate — по факту это тот же gzip, но без заголовка и контрольной суммы, что позволяет сэкономить 18 байт, не бог весть сколько, конечно, но почему бы их не убрать, спрашивается.
Утилита defluff , которая у меня упоминается — это оптимизатор кодов Хаффмана для gzip, PNG и zip, иногда даёт выигрыш в размере.
Комментарии 25
Иногда такой ГИФ занимает меньше ПНГ, например, вот результат по одной из картинок с моего сайта ( https://bolknote.ru/imgs/2011.11.06.png ):
ПНГ сжат при помощи imgo ( https://github.com/imgo/imgo ).
экономим на байтах переданных по сети, но напрягаем броузер на распаковку
Комментарий для Евгения Степанищева:
Видимо пропущено «вот».
Такая оптимизация
Но это лишь «как правило» — есть несколько типичных случаев, с которыми GIF справляется из рук вон плохо. Приведу примеры:
1. «Проявление»/"Угасание", FadeIn/FadeOut — в предельном варианте когда данные не меняются, а меняеться лишь палитра, GIF даст размер_кадра*число_кадров, а zip — примерно размер_кадра+малое_значение*число кадров. Тут даже сжатый GIF сожмётся ZIPом хорошо (если данные о пикселях реально совпадают).
2. Сдвиг картинки. Пиксели те же, но чуть сдвинуты в сторону (MPEG тут умнее).
3. Чередование (как я писал) нескольких повторяющихся или похожих последовательностей картинок; пример: машина едет, рука тянется к рычагу, снова машина едет, рука тянет рычаг, едет машина, дверь (гаражная) начинает опускаться, стредка спидометра движется вправа… и так далее.
4. Последовательность из
Я детально знаю как устроена анимация в GIF. А описанные случаи попробую, может получитсячто-то.
GIF одинаковые кадры хорошо жмёт — он просто оставит прозрачным одинаковые места.
Комментарий для Евгения Степанищева:
Имел в виду три картинки, которые повторяются так, что одинаковые подряд не идут — например,1-2-3-1-2-3-1-2-3-1-2-3-4-5-6, при этом все «1» — совершенно одинаковые, равно как и все «2» и «3».
А, ну попробую. От безнадёги я сейчас что угодно попробую :)
Ну, первый выигрыш :)
Создал анимацию, у которой вот именно так кадры идут (кадры отличаются несильно), в итоге:
просто GIF — 8,6КБ
несжатый, сжатый через gzip — 4КБ
GIF, сжатый gzip — 3,3КБ
т.е. несжатый, но сжатый через gzip
Сейчас попробую ещё сильно отличающиеся кадры.
На сильно отличающихся соседних кадрах сжатие сжатого ГИФа — 67КБ, сжатие несжатого — 626КБ, исходный — 626КБ.
Т.е. сжатый несжатый ГИФ можно хоронить в пользу сжатого обычного, т.е. вот этой утилитой: /all/3713
Чтоб разница была мало чтоб были сильно отличающиеся соседние кадры (от этого просто GIF жмётся плохо), нужно ещё чтоб были сильно похожие НЕсоседние кадры (это будет жать ZIP).
Ну и более общий случай варианта 1. — кадры, совпадающиеся по пикселям, но отличающиеся палитрой (только нужно проследить чтоб конвертор не привёл бы их к общей палитре).
Комментарий для masterspammer.livejournal.com:
Я так и сделал. Взял четыре кадра. Все сильно отличаются и сделал 1+2+1+2+1+2+1+2+1+2+1+2+1+2+3+4.
Это сложнее, надо будет «вручную» сделать.
1+2+1+2+1+2+1+2+1+2+1+2+1+2 может быть относительно хорошо сжато самим GIF — у кадра есть параметр — что с ним делать после показа — а можно его как оставлять, так и удалять и если я правильно помню эту особенность, то последовательность превратится в
тех-же 4-х кадров)
1+2+2+2+2+2+2+2, причём все «2» кроме последнего после показа удаляются, а последний — оставляется.
А что присходит в случае (из
1+2+3+1+2+3+1+2+3+1+2+3+1+2+3+4?
Комментарий для masterspammer.livejournal.com:
Я уж не помню где я взял те кадры, взял другие в этом порядке.
В случае gzipped uncompressed GIF проигрыш 172КБ, в случае DEFLATEd GIF выигрыш в 600 байт.
Уже ничего не понимаю. Можно их увидеть?
Вот: http://zalil.ru/33674961
Да… весело оно всё. Взял я GIMP, который с GIF работает честно (не делает ничего неявного).
Сначала я открыл файл и не увидел там явного криминала
Потом я сделал почти точную копию файла — удалил все слои кроме
Наконец, взял GIF с
Беру RAR — жмётся всё примерно в 5 раз (как и должно было быть).
Возникает догадка — может просто расстояние между схожими фрагментами слишком большое, чтоб GZ заметил и/или сами фрагменты слишком велики, чтоб войти в его словарь.
Уменьшаю ту же картинку что на втором шаге до 80x60 (3 слоя), размножаю слои по 6 раз (чтоб не бояться, что разные слои сожмутся
Получается, что для достаточно больших картинок GZIP не справляется. Параметры -1 … -9 не влияют. Если у модуля апача есть настройки, касающиеся размера словаря, можно с ними поиграть.
Для небольших картинок GZIP несжатого GIFа (а иногда — как в этом примере — и сжатого) работает и так.
P.S. Вот http://zalil.ru/33675627 обычный (сжатый) GIF дополнительно сжатый GZIPом.
FadeIn/FadeOut тоже можно использовать так (оба сжатия).
Картинки со сдвигами — имеет смысл только GZIP (сжатие LZW скроет схожесть кадров).
Может и этот файл лучше сжимать только GZIPом — не проверял.
Комментарий для Евгения Степанищева:
Да, а сжатый обычный получается лучше сжатого несжатого когда несжатый кадр слишком велик (в словарь не лезет), а сжатый уже не слишком. То есть когда сжатый 500к, то не лезет никак, а когда
то скорее всего сжатый кадр в словарь ещё лезет, а несжатый — нет.
Хм… а есть ли у GZIPа вообще словарь? У LZW он точно есть…
Я не
http://pastebin.com/ajxdkwGr
Попробовал пережать один из файлов Bzip2 (алгоритм Барроуза—Уилера), со словарём 9МБ и 10 проходами:
исходный — 259КБ ( http://zalil.ru/33676213 )
исходный, сжатый bzip2 — 126КБ
несжатый — 851КБ
несжатый, сжатый bzip2 — 129КБ
таки да, размер словаря имеет значение, но у DEFLATE этот параметр отсутствует.
А при уменьшении размеров картинки
Как я понимаю, тогда должен начать работать и GZIP?
Не знаю, в обед попробую, вчера уже спать хотелось.
Забыл написать, что попробовал. Вот что вышло:
исходный (кадры из предыдущего моего комментария, ужаты до 50×38) — 17КБ
он же, сжатый DEFLATE — 6,6КБ
сжатый gzip неупакованный GIF — 7,2КБ