TrueColor GIF

TrueColor GIF (191.75КиБ)

Была у меня такая задумка — попробовать сделать полноцветную GIF-анимацию. Сразу скажу, идея провалилась, к сожалению.

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

Разбиение для начала выбрал простое — исходя из площади покрытия, думал потом взяться за оптимизацию (выбирать площадь, потом брать все цвета, которые в ней содержатся), но этого не понадобилось, оказалось, что если поставить задержку между кадрами ноль, то каждый браузер всё равно будет отрисовывать анимацию с очень заметной на глаз задержкой. Кажется в спецификации вообще не определено что означает нулевая задержка:

Delay Time — If not 0, this field specifies the number of hundredths (1/100) of a second to wait before continuing with the processing of the Data Stream. The clock starts ticking immediately after the graphic is rendered. This field may be used in conjunction with the User Input Flag field.

Но и если поставить задержку в 1/100 секунды, браузеры всё так же неторопливо отрисовывают картинку. Нарезанные кадры я собирал через утилиту gifsicle, она ещё и оптимизирует изображение — ненужны мне области я заливал прозрачным цветом, gifsicle умеет такие области отбрасывать, что уменьшает размер изображения:

gifsicle --delay 0 --crop-transparency -O3 out/*.gif > out.gif

Жаль, что ничего не получилось. Всё-таки надо переходить на APNG.

Зато выяснились любопытные подробности. Не знаю как это выглядит в IE (негде попробовать), а вот FireFox и Chrome умеют, один раз отрисовав конечную анимацию, потом мгновенно доставать её из кеша на перезагрузке страницы. «Опера», как и следовало ожидать, постоянно перерисовает анимацию — стоит только вернуться на страницу с другого таба или прокрутить её обратно до анимированного изображения.

Поделиться
Отправить
43 комментария
Pozadi

зато какой интересный эффект получился

MaxSt

Теоретически «без задержки» (0/100 секунд) означает отрисовать как можно быстрее. Но практически все разработчики браузеров считают, что разгонять анимацию до 1000fps и больше, загружая при этом процессор на 100% было бы глупо.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Теоретически «без задержки» (0/100 секунд) означает отрисовать как можно быстрее.

Только теоретически, практически в стандарте это место просто опущено.

Но практически все разработчики браузеров считают, что разгонять анимацию до 1000fps и больше, загружая при этом процессор на 100% было бы глупо

Наложить 40 изображений и показать все разом — уже слишком для современных процессоров? :) Вы заблуждаетесь, это вообще не проблема.

MaxSt

72 человека проголосовало:
https://bugzilla.mozilla.org/show_bug.cgi?id=595671
Похожие жалобы можно найти и для других браузеров.

Современные процессоры конечно могут и 1000fps выжать, но когда вентилятор в ноутбуке начнет гудеть, только чтобы GIFы разгонять до бешенной скорости — это мало кому понравится...

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Современные процессоры конечно могут и 1000fps выжать

Этого делать не нужно. Все последовательные кадры GIF при каком-то пороговом значении в задержке нужно просто собирать в один.

MaxSt

В оригинале (стандарт CompuServe) так и задумывалось: последний кадр был действительно последним, анимация была однократной. Но с тех пор как GIF получил циклическую анимацию (стандарт Netscape2.0), за последним кадром снова идет первый...

Если все кадры «собрать» в один, то как быть если анимацию требуется повторить, причем допустим ровно 3 раза?

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Если все кадры «собрать» в один, то как быть если анимацию требуется повторить, причем допустим ровно 3 раза?

Если каких-то вменяемых задержек нет, то никак — считать статикой.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

В оригинале (стандарт CompuServe) так и задумывалось: последний кадр был действительно последним

Prooflink? Я никогда ничего такого в стандарте не видел.

MaxSt

Если считать статикой — то это будет нарушение формата. Ведь юзер создавал анимацию, и ожидает увидеть анимацию. Если вместо нее он увидит статическую картинку, будет писать жалобы, типа «в вашем браузере баг, он показывает последний кадр вместо анимации». И будет прав.

Насчет рrooflink — общеизвестно, что сначала GIF был статичным. В оригинальной спецификации от CompuServe нет ни слова о том, что за последним блоком надо возвращаться к первому, там также нет слов «cycle» или «loop». Если нет однозначных указаний о том, что делать после последнего блока, значит ничего.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Ведь юзер создавал анимацию, и ожидает увидеть анимацию

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

Насчет рrooflink — общеизвестно, что сначала GIF был статичным.

GIF87 был статичным. Но вы написали «в оригинале (стандарт CompuServe) так и задумывалось: последний кадр был действительно последним, анимация была однократной». В GIF87 не было анимации вообще. Поэтому меня и смутила фраза про то, что последний кадр был последним.

MaxSt

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

Опять же если юзер явно прописал, что анимация должна повториться 100 раз, и только потом остановиться, он именно это и ожидает увидеть. Делать что-то другое — значит обмануть его ожидания, он явно напишет bug report, и будет прав. Потому что он прописал «100 раз» в точном соответствии со спецификацией.

Под стандартом CompuServe я понимаю самый последнюю спецификацию, выпущенную CompuServe. Там все именно так — однократная анимация, последний кадр является действительно последним.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Опять же если юзер явно прописал, что анимация должна повториться 100 раз, и только потом остановиться, он именно это и ожидает увидеть.

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

Под стандартом CompuServe я понимаю самый последнюю спецификацию, выпущенную CompuServe. Там все именно так — однократная анимация, последний кадр является действительно последним.

Последняя спецификация, выпущенная CompuServe — это GIF89a. Вот она: http://www.w3.org/Graphics/GIF/spec-gif89a.txt ( Copyright CompuServe Incorporated, Columbus, Ohio). Я ошибся, кстати, в 87a уже была анимация, задержки не было. Вроде как ничего с тех пор и не менялось особо. Я не прав?

funk_rabbit (funk-rabbit.livejournal.com)

100*(0/100)=0 статика и никаких обманов =) Действительно неприятный момент.

MaxSt

Кто-то может в состоянии увидеть, а кто-то может нет — в любом случае это не значит, что разрешается грубо нарушать спецификацию. Если спецификация требует отрисовать все кадры, и повторить этот цикл 100 раз, значит это и надо делать.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

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

MaxSt

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

Общее время анимации: T = P + D, где
P — processing (декомпрессия кадров и вывод их на экран)
D — delay (0/100, 1/100, ...)

Общее время Т всегда будет больше 0, даже если задержка D определена как 0.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Если мы договорились следовать логике, то смена кадров со скоростью ноль, это смена кадров со скоростью ноль, то есть пользователь не в состоянии должен быть их различить. А это = статика.

MaxSt

Да, но скорость кадров не будет ноль, даже если выставить задержку в 0.

Скорость кадров измеряется от начала одного кадра до начала другого.
А задержка измеряется от конца одного кадра до начала другого.

То есть это немного разные вещи.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

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

MaxSt

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

Не случайно этот верхний лимит реализован во всех без исключения браузерах.

Он настолько необходим на практике, что Мозилла даже своему собственному APNG не позволяет слишком разгоняться. По их же спецификации в APNG можно установить любую рациональную (n/m) задержку, но на практике в Firefox он упрется в тот же самый верхний лимит.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

крайне необходимое с практической точки зрения (чтобы вентилятор в ноутбуке не гудел, пока процессор пытается разогнать какой-то анимированный смайлик до максимума).

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

Не случайно этот верхний лимит реализован во всех без исключения браузерах.

Да просто оптимизацией и развитием GIF не занимается никто.

Он настолько необходим на практике, что Мозилла даже своему собственному APNG не позволяет слишком разгоняться. По их же спецификации в APNG можно установить любую рациональную (n/m) задержку, но на практике в Firefox он упрется в тот же самый верхний лимит.

При этом в Canvas я могу вывести пару сотен изображений без задержки.  http://bolknote.ru/all/3302/#35

SiMM (mr-simm.livejournal.com)

На самом деле это вполне возможно увидеть, время на декомпрессию и прорисовку все равно ведь тратиться.

В спецификации указано время, которое должно тратиться на декомпрессию и прориовку? Если нет — то упоминание оного факта лишено смысла, хотя бы потому, что вчера на это тратилось 100 мс, а завтра — 1 мс, и это никак не противоречит спецификации. Как и здравый смысл, в общем-то.

MaxSt

Не так давно даже миниатюрный 16x16 throbber создавал проблемы для Firefox:
https://bugzilla.mozilla.org/show_bug.cgi?id=437829
Цитата оттуда из комментария 10:
The effect is that the fan of my laptop spins like crazy, while the laptop is drawing a simple animation.

Опять же, даже если они все супер-оптимизируют, какая-то разумная частота обновления Web-странички все же должна быть, правильно? Должен же CPU хоть немного отдыхать? Ведь если строго следовать спецификации, у CPU всегда будет работа: только успел отрисовать кадр, сразу начинай рисовать следующий...

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Неэффективно можно запрограммировать даже возврат из функции. А FireFox, который сейчас медленнее всех и жрёт памяти больше всех, мне кажется, совершенно не пример для подражания.

Должен же CPU хоть немного отдыхать?

Зачем? Он что, устаёт от этого? Ну и не работа это — вывести GIF, это очень быстро по нынешним меркам.

MaxSt

Если улучшить эффективность, анимация будет быстрей, но CPU будет так же работать без отдыха.

CPU должен отдыхать... в наще время пользователи тут же пишут bug report, если видят что программа ест 100% CPU без видимой надобности. Очень много людей сейчас работают на ноутбуках, и не хотят сажать батареи без крайней необходимости. Если они увидят что браузер занимает 100% CPU чтобы отобразить простую web-страничку, они его быстро деинсталлируют.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Если улучшить эффективность, анимация будет быстрей, но CPU будет так же работать без отдыха.

Вы как-то аргументы мои не слышите. Вывести кучу гифок — это совсем не работа для современных CPU. Вспомните DOOM и вспомните на каком железе он шёл.

видят что программа ест 100% CPU без видимой надобности

А зачем его на 100% использовать? Для анимации каких-то гифок это без надобности.

MaxSt

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

DOOMу не требовалось загружать процессор на 100%, там тоже был верхний лимит на быстроту смены кадров, которую накладывал монитор. Если процессор успевал подготовить кадр быстрее, то остаток времени он просто ждал v-sync сигнала, ничего не делая.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

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

Ничего не понимаю. С чего вы взяли, что это потребует загрузки процессора на 100%? Задержка ноль вообще даст сначала небольшой всплеск нагрузки (на декодирование), а потом — нагрузка в пределах погрешности измерения.

DOOMу не требовалось загружать процессор на 100%

DOOM на многие порядки сложнее в обработке и нагрузке на CPU, чем вывод хоть сотни каких-то там гифов.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Вы либо смеётесь надо мной, либо вообще не понимаете как всё работает.

MaxSt

Да, для декодирования хватит одного прохода, но наложение кадров друг на друга тоже ведь нагружает процессор. Если задача поставлена: не делать пауз, рисовать кадры постоянно, с максимально возможной скоростью, то такая задача нагрузит процессор на 100%. У процессора постоянно будет работа.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Похоже вы действительно не понимаете как всё работает. Честно сказать, мне не хочется объяснять.

MaxSt

Я и так догадываюсь... Вам кажется что рисование кадров на экране — слишком тривиальная задача для современных процессоров. Это не совсем так. Зачем в погоне за титулом «самый быстрый браузер» они вдруг ринулись реализовывать hardware acceleration? Именно для того, чтобы разгрузить CPU от рисования графики.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Я думаю не стоит продолжать этот разговор. Именно потому что я знаю подробности, а вы догадываетесь.

MaxSt

Как автор популярных конверторов gif2apng и apng2gif, я знаю подноготную достаточно хорошо. И не стал бы ставить этот эксперимент, потому что мне и так было бы ясно, чем он закончится.

Кстати, при обработке сайта на CPU рендеринг графики отнимает весьма существенную долю времени:
http://blogs.msdn.com/b/ie/archive/2010/08/30/performance-profiling-how-different-web-sites-use-browser-subsystems.aspx

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Как автор популярных конверторов gif2apng и apng2gif, я знаю подноготную достаточно хорошо.

Не вижу как это связано. Стандарт вы знаете хорошо, верю (и спасибо за конверторы, я хоть и не пользовался, но дело хорошее), но делать конверторы и понимать как всё работает на низком уровне — вещи разные.

MaxSt

Ну я же только что дал ссылку, там на достаточно низком уровне исследуется, какие модули браузера сколько CPU требуют, в частности рендеринг графики. Думаете, я не состоянии такие вещи понять?

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Не думаю. Но я работал с выводом графики, причём и на уровне ассемблера тоже, исследовал GPU и OpenGL, знаю что сколько занимает.

MaxSt

Ну так и я в выводом графики работал, и на ассеблере тоже. Но сейчас же не времена DOSа, когда можно было напрямую видеопямять адресовать. В браузере сначала куча слоев, потом куча библиотек, потом GDI, в итоге это нагромождение сильно тормозит.

Евгений Степанищев (bolknote.ru)

Комментарий для MaxSt:

Нам не о чем дальше спорить.

funk_rabbit (funk-rabbit.livejournal.com)

а поподробнее можно, как делалась картинка выше?

Евгений Степанищев (bolknote.ru)

Комментарий для funk-rabbit.livejournal.com:

Да я, вроде, описал уже всё. Считаем сколько какие-то цвета встречаются в картинке, сортируем по частоте использования. Разбиваем получившийся массив на отрезки по 255 цветов (256-й нужен для прозрачности). Всего будет общее количество цветов/255 кадров.

Для каждого отрезка на 255 создаём новый кадр с прозрачным фоном, в каждый кладём только те точки, цвета которых есть в выбранном нам отрезке.

masterspammer (masterspammer.livejournal.com)

О! Ссылка на статью всплыла — http://habrahabr.ru/post/149728/#comment_5066608

Да, а про то, чтоб избавиться от эффекта прорисовки «по частям» — сделать «прогрессивный» GIF — первый кадр во весь экран, показывающий всего в 256 цветах, но всё, а потом — улучшающие его дополнительные.

Евгений Степанищев (bolknote.ru)

Комментарий для masterspammer.livejournal.com:

Забавно :)

Популярное