TrueColor GIF
Была у меня такая задумка — попробовать сделать полноцветную 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 умеют, один раз отрисовав конечную анимацию, потом мгновенно доставать её из кеша на перезагрузке страницы. «Опера», как и следовало ожидать, постоянно перерисовает анимацию — стоит только вернуться на страницу с другого таба или прокрутить её обратно до анимированного изображения.
зато какой интересный эффект получился
Теоретически «без задержки» (0/100 секунд) означает отрисовать как можно быстрее. Но практически все разработчики браузеров считают, что разгонять анимацию до 1000fps и больше, загружая при этом процессор на 100% было бы глупо.
Комментарий для MaxSt:
Только теоретически, практически в стандарте это место просто опущено.
Наложить 40 изображений и показать все разом — уже слишком для современных процессоров? :) Вы заблуждаетесь, это вообще не проблема.
72 человека проголосовало:
https://bugzilla.mozilla.org/show_bug.cgi?id=595671
Похожие жалобы можно найти и для других браузеров.
Современные процессоры конечно могут и 1000fps выжать, но когда вентилятор в ноутбуке начнет гудеть, только чтобы GIFы разгонять до бешенной скорости — это мало кому понравится...
Комментарий для MaxSt:
Этого делать не нужно. Все последовательные кадры GIF при каком-то пороговом значении в задержке нужно просто собирать в один.
В оригинале (стандарт CompuServe) так и задумывалось: последний кадр был действительно последним, анимация была однократной. Но с тех пор как GIF получил циклическую анимацию (стандарт Netscape2.0), за последним кадром снова идет первый...
Если все кадры «собрать» в один, то как быть если анимацию требуется повторить, причем допустим ровно 3 раза?
Комментарий для MaxSt:
Если каких-то вменяемых задержек нет, то никак — считать статикой.
Комментарий для MaxSt:
Prooflink? Я никогда ничего такого в стандарте не видел.
Если считать статикой — то это будет нарушение формата. Ведь юзер создавал анимацию, и ожидает увидеть анимацию. Если вместо нее он увидит статическую картинку, будет писать жалобы, типа «в вашем браузере баг, он показывает последний кадр вместо анимации». И будет прав.
Насчет рrooflink — общеизвестно, что сначала GIF был статичным. В оригинальной спецификации от CompuServe нет ни слова о том, что за последним блоком надо возвращаться к первому, там также нет слов «cycle» или «loop». Если нет однозначных указаний о том, что делать после последнего блока, значит ничего.
Комментарий для MaxSt:
Ну, если задержка между кадрами ноль, то он должен увидеть кадры с задержкой ноль, то есть статику, по сути.
GIF87 был статичным. Но вы написали «в оригинале (стандарт CompuServe) так и задумывалось: последний кадр был действительно последним, анимация была однократной». В GIF87 не было анимации вообще. Поэтому меня и смутила фраза про то, что последний кадр был последним.
Нет, это не будет статика, потому что какие-то миллисекунды по любому потратятся на скачивание, декомпрессию и отрисовку. Ведь таймер задержки стартует только после окончания отрисовки блока.
Опять же если юзер явно прописал, что анимация должна повториться 100 раз, и только потом остановиться, он именно это и ожидает увидеть. Делать что-то другое — значит обмануть его ожидания, он явно напишет bug report, и будет прав. Потому что он прописал «100 раз» в точном соответствии со спецификацией.
Под стандартом CompuServe я понимаю самый последнюю спецификацию, выпущенную CompuServe. Там все именно так — однократная анимация, последний кадр является действительно последним.
Комментарий для MaxSt:
Конечно. Но если пользователь прописал задержку, которая явно выше его скорости восприятия, он должен увидеть статику. Так как анимацию на такой скорости он увидеть не в состоянии.
Последняя спецификация, выпущенная CompuServe — это GIF89a. Вот она: http://www.w3.org/Graphics/GIF/spec-gif89a.txt ( Copyright CompuServe Incorporated, Columbus, Ohio). Я ошибся, кстати, в 87a уже была анимация, задержки не было. Вроде как ничего с тех пор и не менялось особо. Я не прав?
100*(0/100)=0 статика и никаких обманов =) Действительно неприятный момент.
Кто-то может в состоянии увидеть, а кто-то может нет — в любом случае это не значит, что разрешается грубо нарушать спецификацию. Если спецификация требует отрисовать все кадры, и повторить этот цикл 100 раз, значит это и надо делать.
Комментарий для MaxSt:
Никто не в состоянии увидеть кадры, меняющиеся с задержкой ноль, это физике противоречит. И спецификация обходит стороной значение задержки ноль, я же привёл цитату.
На самом деле это вполне возможно увидеть, время на декомпрессию и прорисовку все равно ведь тратиться. Пусть это миллисекунды, но все равно бешеное мелькание кадров — это не тоже самое что статика.
Общее время анимации: T = P + D, где
P — processing (декомпрессия кадров и вывод их на экран)
D — delay (0/100, 1/100, ...)
Общее время Т всегда будет больше 0, даже если задержка D определена как 0.
Комментарий для MaxSt:
Если мы договорились следовать логике, то смена кадров со скоростью ноль, это смена кадров со скоростью ноль, то есть пользователь не в состоянии должен быть их различить. А это = статика.
Да, но скорость кадров не будет ноль, даже если выставить задержку в 0.
Скорость кадров измеряется от начала одного кадра до начала другого.
А задержка измеряется от конца одного кадра до начала другого.
То есть это немного разные вещи.
Комментарий для MaxSt:
В любом случае, что не считать за скорость кадров, но сейчас она космически далека от нуля. Скорость отображения GIF во много раз выше, чем скорость анимации при задержке ноль в браузерах.
В принципе верхний лимит на скорость кадров конечно нарушает спецификацию, но во-первых, нарушение это минимальное, а во-вторых, крайне необходимое с практической точки зрения (чтобы вентилятор в ноутбуке не гудел, пока процессор пытается разогнать какой-то анимированный смайлик до максимума).
Не случайно этот верхний лимит реализован во всех без исключения браузерах.
Он настолько необходим на практике, что Мозилла даже своему собственному APNG не позволяет слишком разгоняться. По их же спецификации в APNG можно установить любую рациональную (n/m) задержку, но на практике в Firefox он упрется в тот же самый верхний лимит.
Комментарий для MaxSt:
Мы уже это обсуждали. Не будет вентилятор гудеть из-за каких-то там GIFов. Вы в DOOM играли? Он шёл на 386 процессоре с частотой в десятки мегагерц, а сейчас за гигагерцы скоростью уже.
Да просто оптимизацией и развитием GIF не занимается никто.
При этом в Canvas я могу вывести пару сотен изображений без задержки. http://bolknote.ru/all/3302/#35
В спецификации указано время, которое должно тратиться на декомпрессию и прориовку? Если нет — то упоминание оного факта лишено смысла, хотя бы потому, что вчера на это тратилось 100 мс, а завтра — 1 мс, и это никак не противоречит спецификации. Как и здравый смысл, в общем-то.
Не так давно даже миниатюрный 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 всегда будет работа: только успел отрисовать кадр, сразу начинай рисовать следующий...
Комментарий для MaxSt:
Неэффективно можно запрограммировать даже возврат из функции. А FireFox, который сейчас медленнее всех и жрёт памяти больше всех, мне кажется, совершенно не пример для подражания.
Зачем? Он что, устаёт от этого? Ну и не работа это — вывести GIF, это очень быстро по нынешним меркам.
Если улучшить эффективность, анимация будет быстрей, но CPU будет так же работать без отдыха.
CPU должен отдыхать... в наще время пользователи тут же пишут bug report, если видят что программа ест 100% CPU без видимой надобности. Очень много людей сейчас работают на ноутбуках, и не хотят сажать батареи без крайней необходимости. Если они увидят что браузер занимает 100% CPU чтобы отобразить простую web-страничку, они его быстро деинсталлируют.
Комментарий для MaxSt:
Вы как-то аргументы мои не слышите. Вывести кучу гифок — это совсем не работа для современных CPU. Вспомните DOOM и вспомните на каком железе он шёл.
А зачем его на 100% использовать? Для анимации каких-то гифок это без надобности.
Это работа, если хочется выводить их с максимальной возможной скоростью. То есть спецификация требует, чтобы процессор был загружен на 100%, несмотря на то, насколько он мощный.
DOOMу не требовалось загружать процессор на 100%, там тоже был верхний лимит на быстроту смены кадров, которую накладывал монитор. Если процессор успевал подготовить кадр быстрее, то остаток времени он просто ждал v-sync сигнала, ничего не делая.
Комментарий для MaxSt:
Ничего не понимаю. С чего вы взяли, что это потребует загрузки процессора на 100%? Задержка ноль вообще даст сначала небольшой всплеск нагрузки (на декодирование), а потом — нагрузка в пределах погрешности измерения.
DOOM на многие порядки сложнее в обработке и нагрузке на CPU, чем вывод хоть сотни каких-то там гифов.
Комментарий для MaxSt:
Вы либо смеётесь надо мной, либо вообще не понимаете как всё работает.
Да, для декодирования хватит одного прохода, но наложение кадров друг на друга тоже ведь нагружает процессор. Если задача поставлена: не делать пауз, рисовать кадры постоянно, с максимально возможной скоростью, то такая задача нагрузит процессор на 100%. У процессора постоянно будет работа.
Комментарий для MaxSt:
Похоже вы действительно не понимаете как всё работает. Честно сказать, мне не хочется объяснять.
Я и так догадываюсь... Вам кажется что рисование кадров на экране — слишком тривиальная задача для современных процессоров. Это не совсем так. Зачем в погоне за титулом «самый быстрый браузер» они вдруг ринулись реализовывать hardware acceleration? Именно для того, чтобы разгрузить CPU от рисования графики.
Комментарий для MaxSt:
Я думаю не стоит продолжать этот разговор. Именно потому что я знаю подробности, а вы догадываетесь.
Как автор популярных конверторов gif2apng и apng2gif, я знаю подноготную достаточно хорошо. И не стал бы ставить этот эксперимент, потому что мне и так было бы ясно, чем он закончится.
Кстати, при обработке сайта на CPU рендеринг графики отнимает весьма существенную долю времени:
http://blogs.msdn.com/b/ie/archive/2010/08/30/performance-profiling-how-different-web-sites-use-browser-subsystems.aspx
Комментарий для MaxSt:
Не вижу как это связано. Стандарт вы знаете хорошо, верю (и спасибо за конверторы, я хоть и не пользовался, но дело хорошее), но делать конверторы и понимать как всё работает на низком уровне — вещи разные.
Ну я же только что дал ссылку, там на достаточно низком уровне исследуется, какие модули браузера сколько CPU требуют, в частности рендеринг графики. Думаете, я не состоянии такие вещи понять?
Комментарий для MaxSt:
Не думаю. Но я работал с выводом графики, причём и на уровне ассемблера тоже, исследовал GPU и OpenGL, знаю что сколько занимает.
Ну так и я в выводом графики работал, и на ассеблере тоже. Но сейчас же не времена DOSа, когда можно было напрямую видеопямять адресовать. В браузере сначала куча слоев, потом куча библиотек, потом GDI, в итоге это нагромождение сильно тормозит.
Комментарий для MaxSt:
Нам не о чем дальше спорить.
а поподробнее можно, как делалась картинка выше?
Комментарий для funk-rabbit.livejournal.com:
Да я, вроде, описал уже всё. Считаем сколько какие-то цвета встречаются в картинке, сортируем по частоте использования. Разбиваем получившийся массив на отрезки по 255 цветов (256-й нужен для прозрачности). Всего будет общее количество цветов/255 кадров.
Для каждого отрезка на 255 создаём новый кадр с прозрачным фоном, в каждый кладём только те точки, цвета которых есть в выбранном нам отрезке.
О! Ссылка на статью всплыла — http://habrahabr.ru/post/149728/#comment_5066608
Да, а про то, чтоб избавиться от эффекта прорисовки «по частям» — сделать «прогрессивный» GIF — первый кадр во весь экран, показывающий всего в 256 цветах, но всё, а потом — улучшающие его дополнительные.
Комментарий для masterspammer.livejournal.com:
Забавно :)