Веб-программист
0,0
рейтинг
20 мая 2011 в 18:12

Дизайн → Анимированный PNG в Firefox, Opera и WebKit? Легко! из песочницы

Однажды, от скуки, мне захотелось создать красивую полноцветную анимацию с 8-битной прозрачностью. Понятно, что GIF для этой цели никак не подходил и я стал искать альтернативы. Flash в этом качестве даже не рассматривался – слишком нагружает процессор, плохо встраивается в страницу поверх других элементов, да и стоит не у всех.

Сперва мой взгляд пал на MNG, родственника PNG. «Спецификация формата выпущена ещё в 2001 году, поэтому он наверняка реализован во всех современных браузерах!». И тут меня ждало первое разочарование. Формат оказался слишком сложным для реализации – реализация Mozilla, по их словам, содержала столько же строк кода, сколько все остальные форматы вместе взятые, за что и была удалена из их продуктов. Другие производители браузеров, похоже, даже не пытались внедрить у себя этот формат. Конечно, существует плагин для браузеров, поддерживающих плагины Netscape, но это ничем не лучше Flash. Отмечу лишь, что, возможно, формат слишком опередил свое время. Судя по описанию возможностей, это такой растровый SVG.

Дальше поиски привели меня к формату APNG. Формат прост, как два рубля: в файле записаны изменения в кадре от предыдущего с некоторыми мелкими нюансами. Но самое главное, что браузеры, не поддерживающие этот формат, отобразят статичную картинку. В целом, по возможностям формат схож с GIF. Он был предложен Mozilla как замена монструозному MNG. Проверяю в Firefox – все отлично работает. Opera – также. Открываю в Chrome и… получаю статичную картинку. Что произошло: Mozilla предложила включить APNG в спецификацию PNG. Путем голосования эта идея была отвергнута. И теперь часть браузеров поддерживает этот формат, а часть – нет.

Предо мной явственно предстала картина:
Mozilla: Ваш формат плохой, вы ничего не понимаете в анимированных PNG! Мы сделали свой, без шахмат и поэтесс. Включите его в спецификацию!
Группа разработчиков PNG: А вот вам!

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

И тут меня посетила идея: вроде же в SVG можно вставлять растровые изображения?!

Если гора не идет к Магомету


Для экспериментов я одолжил картинку у Mozilla:
Spinfox


Разбиваем картинку на отдельные кадры:
Кадр 1Кадр 2Кадр 3
И так далее. Получилось 25 кадров.

Указываем размеры SVG, равные размеру самого большого кадра, и вставляем изображения. Порядок, кстати, не важен.
<svg xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink" width="148" height="148">
  <image x="0" y="0" width="148" height="148" xlink:href="spinfox_001.png" />
  <image x="0" y="0" width="148" height="148" xlink:href="spinfox_002.png" />
  <image x="0" y="0" width="148" height="148" xlink:href="spinfox_003.png" />
  …
  <image x="0" y="0" width="148" height="148" xlink:href="spinfox_024.png" />
  <image x="0" y="0" width="148" height="148" xlink:href="spinfox_025.png" />
</svg>

Дальше я было попытался просто накладывать последовательно кадры друг на друга, но не учел прозрачности и получил солнышко из уха лисы (этот же эффект можно пронаблюдать в IE9):
Солнышко

Эффект можно использовать для реализации одного из режимов APNG: отрисовка следующего кадра поверх предыдущего.

Теперь анимируем свойство прозрачности (opacity). Можно анимировать и координаты и сдвигать кадры за пределы видимости.
Тут проблема может проявиться в том, что прозрачность будет меняться плавно и появится шлейф или мерцание. Для этого мы указываем calcMode как «discrete».
Список опорных значений: values=«1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0». Как видно, это первый кадр. Первое значение – 1 – изображение не прозрачно. На всех остальных кадрах – полностью прозрачно.
Продолжительность анимации (dur) выбираем так, чтобы при делении на число кадров получить время одного кадра. Если какой-то кадр должен находиться на экране вдвое большее время, список опорных значений придется удваивать, либо менять длительность одного значения, что несколько сложнее.
<svg xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink" width="148" height="148">
  <image x="0" y="0" width="148" height="148" xlink:href="spinfox_001.png">
    <animate attributeType="CSS" attributeName="opacity" dur="1.25s"
    values="1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0"
    calcMode="discrete" repeatCount="indefinite" />
  </image>
<image x="0" y="0" width="148" height="148" xlink:href="spinfox_002.png">
    <animate attributeType="CSS" attributeName="opacity" dur="1.25s"
    values="0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0"
    calcMode="discrete" repeatCount="indefinite" />
  </image>
<image x="0" y="0" width="148" height="148" xlink:href="spinfox_003.png">
    <animate attributeType="CSS" attributeName="opacity" dur="1.25s"
    values="0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0"
    calcMode="discrete" repeatCount="indefinite" />
  </image>
…
<image x="0" y="0" width="148" height="148" xlink:href="spinfox_024.png">
    <animate attributeType="CSS" attributeName="opacity" dur="1.25s"
    values="0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0"
    calcMode="discrete" repeatCount="indefinite" />
  </image>
<image x="0" y="0" width="148" height="148" xlink:href="spinfox_025.png">
    <animate attributeType="CSS" attributeName="opacity" dur="1.25s"
    values="0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1"
    calcMode="discrete" repeatCount="indefinite" />
  </image>
</svg>

Теперь у нас остается лишь одно неудобство – анимация состоит из множества файлов. Эту проблему мы решим с помощью data:URL, встроив изображения прямо в SVG.

Итоговый результат

Размер исходного APNG: 613321 байт;
Размер SVG: 799692 байт;
Размер SVG, сжатого gzip: 601409 байт. Даже меньше исходного!
Кадры PNG были оптимизированы при помощи pngout.

Внимательный читатель мог заметить, что данная «тайная техника» не работает в IE. Могу посоветовать только отдавать ему другой код с GIF или Flash, ждать IE10 и готовить лопату.
Ефремов Андрей @Lord_D
карма
17,0
рейтинг 0,0
Веб-программист
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Дизайн

Комментарии (56)

  • +1
    Интересно конечно, но у меня оно отъедает ~12% одного ядра.
    Chromium 11, Linux.
    • 0
      Opera 11.11, linux, Sempron 2500+: 5-7%.
  • +1
    Красивая реализация apng…
    Жалко…
    • +1
      Действительно, очень занятно.
      И, действительно, жаль что:

      С Ubuntu 11.04 + Firefox 4.0.1 сжирает больше 65% ядра…
  • +13
    Что-то «Кроссбраузерный» в заголовке топика плохо вяжется с последним абзацем
    Внимательный читатель мог заметить, что данная «тайная техника» не работает в IE. Могу посоветовать только отдавать ему другой код с GIF или Flash, ждать IE10 и готовить лопату.
    • 0
      Вы правы. Дело в том, что обнаружил этот «подарок» я уже в самом конце процесса написания статьи. Был уверен, что раз IE9 поддерживает SVG, то такая простая анимация там заработает. Соответственно, название статьи решил уже не менять.
  • +7
    Остроумное решение:) Но на практике — не проще ли анимировать спрайт? Тем более, что работать будет и в IE. Ну да, будет нужен JS, зато не будет нужен SVG:)
    • +4
      Мы не ищем простых путей! :)
      • 0
        Не так… «Мистер знает толк в извращениях» ;-)
    • +2
      Можно дополнительно задействовать спрайт персонально для IE.
      • +2
        Разумеется, можно.
        Но смотрите, что получается — у нас один костыль для браузеров, и другой для IE. Мне кажется, это как-то неизящно. Не проще ли сделать один костыль, но уж который работает везде?
        • 0
          Способ, работающий без JavaScript, всегда зачастую (при прочих равных) предпочтительнее способа, работающего с помощью JavaScript. И если в большинстве браузеров можно обойтись без JS, то применять JS имеет смысл только в оставшихся.
          • +1
            Всегда предпочтительнее иметь и поддерживать одно решение, а не два — потому что это проще в поддержке.
            Всегда сначала ищется кроссбраузерное решение, а потом добавляются хаки. Противоположная стратегия приводит к масштабному головняку, как правило.

            Тем более, что в данном случае вариант со спрайтами по объему примерно равен исходному варианту с SVG.

            Это, конечно, дело вкуса отчасти, но я свои причины думать именно так, изложил выше:)
            • –1
              Если на первом месте не потребительские качества сайта, а простота его сопровождения для разработчика, тогда единое решение, конечно, может иметь преимущество.
              • 0
                Когда разработчик тратит время на поддержку двух костылей вместо одного — вот тогда потребительские качества сайта и начинают страдать. Потому что время тратится контрпродуктивно.

                Я согласен, что решение без JS в общем случае лучше. Это баян, собственно. Но одно решение, даже с JS, всяко лучше, чем два.

                KISS и DRY.
                • –1
                  Разные решения применяются в разных нишах (ценовых, качественных и проч.), это нормально.

                  А следуя парадигме «одно решение для всех браузеров», недолго дойти и до того, чтобы, например, для всех браузеров использовать таблицу вместо списка для резинового меню шириной 100%, когда {display: table} в действительности не поддерживается лишь менее чем 10% браузеров (IE 6/7). Graceful degradation, progressive enhancement. ;-)
                  • 0
                    Следуя вашей логике, для IE такое меню надо сверстать таблицей, а для браузеров — списком:)
                    • 0
                      Для браузеров и IE8+ (более 90% браузеров) — список, для IE6/7 — нерезиновое меню при помощи float либо динамическая генерация таблицы из списка средствами JS. Правильным браузерам — правильное решение, остальным — приемлемое. ;-)
  • +28
    > получил солнышко из хвоста лисы

    Это ухо.
  • +1
    У меня эта картинка ест 5% процессора. Аналогичная анимация на флеш будет грузить процессор не больше (а скорей всего сильно меньше).
    • +3
      кроме того вместо 25 изображений будет достаточно 2х. планеты и лисы.
      • +2
        Если уж говорить о вращении — это вообще идеально делается на чистом CSS, например:

        s3.amazonaws.com/37assets/svn/463-single_spinner.html

        Здесь всё-таки человек делал анимацию из переключающихся кадров…
        • 0
          что-то не работает ссылка (
        • +2
          По ссылке одна серость. В смысле вся страница залита светло-серым и ничего на ней нет.
          • 0
            У меня там крутится анимация загрузки. Видимо, это и есть демонстрация поворота средствами CSS.
            Chrome.
            • 0
              FF4/ Как я уже говорил — абсолютно ничего не вижу на странице.
              А вот исходный APNG — отлично крутится =)
              Кроссбраузерность — миф.
              • 0
                В FF4 этих CSS keyframe animations еще нет. Есть внушительный баг в мозилловской багзилле на эту тему, там уже второй десяток патчей люди пишут для того, чтобы реализовать этот функционал. В ближайшее время (4.1-4.2) по идее должны принять — правда, разумеется, не с "-webkit-" префиксами свойств.
      • +1
        Это также можно сделать и на CSS, как уже сказали, и на том же SVG. Я хотел показать наиболее близкую замену простому анимированному PNG.
        • +1
          Я про то что в статье сказано «Flash слишком нагружает процессор». Это как минимум некорректно. А если по честному — просто неправда.
          • 0
            Ответил тут.
  • +7
    Такие вещи можно реализовать на JS:
    Берем PNG, в котором все кадры анимации расставлены в ряд.
    Создаем DIV размером с 1 кадр и overflow: hidden;
    Пихаем в него наш PNG с position: absolute, и изменением left: меняем кадры по таймеру.
    • 0
      Тогда уже background-image и background-position.
      • 0
        Вариант с отдельным img лучше, если надо обеспечить кликабельность картинки (именно картинки, а не всего дива).
        • 0
          Проще только получить урл картинки, остальное одинаково.
          Лишних сущностей без надобности не надо плодить.
          • 0
            А как вы собрались отличить клик по диву в месте, где бэкграунда нет, от клика в месте, где бэкграунд есть?
            • 0
              Создаем DIV размером с 1 кадр и overflow: hidden;
              • 0
                ок ок, для случая обычной анимации вариант с бэкграундом дива лучше.
  • +1
    Кстати, через JS реализовал Google для своего логотипа.
    animatedpng.com/index.php/samples/latest-google-logo/
  • +7
    Дисклеймер: я, конечно, за прогресс, но давайте смотреть фактам в лицо.

    > Flash в этом качестве даже не рассматривался – слишком нагружает процессор (1), плохо встраивается в страницу поверх других элементов(2), да и стоит не у всех(3).

    Пункт раз — спорно. Не поленитесь, сделайте бенчмарк. Из собственного опыта могу сказать, что флэш реально тормозит или совсем криво написаный, или очень большой и под сафари на маке, и то есть варианты. Опять-таки, последние версии плеера используют хардварное ускорение как для 2d, так и для 3d и видео.

    Пункт два — гм, возможно. Но пробовали ли вы использовать wmode? kb2.adobe.com/cps/155/tn_15523.html

    Пункт три — у меня нет анимации в Хроме 11 и Сафари 5 на Mac OS 10.6.7. Позвольте на этом моменте попедантствовать.
    Прошу внимания к следующим ссылкам: www.adobe.com/products/player_census/flashplayer/version_penetration.html
    Ну или en.wikipedia.org/wiki/Adobe_Flash#User_experience, если угодно.
    Минимальная цифра, которую я увидел тут — 92%. Действительно, восемь процентов — это существенно.

    Давайте посчитаем сколько мы могли потерять только на хроме и сафари.
    Источник — та же Википедия: en.wikipedia.org/wiki/Usage_share_of_web_browsers
    Исхожу из того, что картинка не работает во всех версиях и на всех платформах браузеров — честно, лень искать и считать обратное. Если кому-то будет действительно интересно, погуглите.
    Google Chrome (14.6%)
    Safari (6.3%)
    Итого, даже округлив, 20%.

    PS. Ах да, еще какие-то версии IE не работают…
    PSS. Ожидаю слив кармы. На здоровье. Только давайте так — минус в карму сопровождается коментарием. Сможете?
    • 0
      Google Chrome 13.0.767.1 dev, Linux, лис отлично крутится.
    • 0
      За что же вам карму сливать, право слово? Конструктивная критика только приветствуется.

      > Из собственного опыта могу сказать, что флэш реально тормозит или совсем криво написаный, или очень большой и под сафари на маке, и то есть варианты.
      Видите, вы сами сказали, что есть проблемы со скоростью на маке. От себя могу добавить, что на линуксе на Core 2 и GF 260 я могу играть только в очень простые игры на Flash. Сложные безбожно тормозят. Открытие параллельно 10 флешек (на одной странице или вкладок с YouTube) убивает процессор в ноль. Можно даже уронить иксы. Может быть, я делаю что-то не так, но ведь не от хорошей жизни появились Gnash, Swfdec и Lightspark? Каждый из которых также пока малоюзабелен.

      > Но пробовали ли вы использовать wmode?
      Конечно. На сколько я помню, есть проблемы с другими объектами, наложенными поверх такой флешки.

      > Пункт три — у меня нет анимации в Хроме 11 и Сафари 5 на Mac OS 10.6.7.
      Вот это уже серьезно. Тут я ничего не могу сказать, т.к. не имею мака, но оснований вам не верить у меня нет.
      • +1
        Я тоже каждый раз недоумеваю сливу кармы. Но я, собственно, не об этом.

        Про тормоза.
        Имхо вопрос очень и очень спорный. Линукс — да, это не целевая платформа, и Adobe не замечен в затачивании своего плагина под нее. Мое мнение, что флэш на андроиде будет работать лучше, чем под линуксом. Просто потому, что он важнее. Увы, увы. Какие следует сделать выводы? Если вы пишете хитрое приложение преимущественно под линукс, имеет смысл искать альтернативы. Если же линукс-пользователи планируются в долях процентов — лучшее враг хорошего. Тот же Youtube html5 сделал, но по умолчанию там флэш. И, кстати — вы Youtube смотрите с флэшем, ругаясь, или с html5? Но это тоже так, не по теме на самом деле.

        По теме — есть такой бренд, Angry Birds. И у них недавно появилось html5 приложение. Признаться, у меня оно отъедает весь процессор в Хроме (MacOS, 2.5 core i5). Хотя по флэш-меркам, игра ничего особого не представляет. Ну про то, что флэш-игры у меня не тормозят, я боюсь просто говорить.

        Про wmode:
        Индивидуально. Спорить не буду. Сколько флэша использовал в своих проектах пока, это ни разу не являлось непреодолимым препятствием. Не уверен, что рассматривал все случаи.

        Про анимацию.
        Выше был коментарий, что в Хроме 13 под линуксом работает. Так что мои исходные 20% можно как минимум уменьшить до 10%. Все еще не считая IE.
        • 0
          Мое мнение, что флэш на андроиде будет работать лучше, чем под линуксом.

          К сожалению, вы вполне можете оказаться правы. И здесь я, как разработчик, не-по-ни-маю! Ведь тот же линукс. Как можно заточить код под одну и не использовать его под другой платформой?

          вы Youtube смотрите с флэшем, ругаясь, или с html5?

          HTML5.
      • 0
        В любом случае замечание про тормознутость флеша некорректно. У меня на маке, если сделать аналогичный ролик аналогичным способом во флеш он будет отжырать 0% процессора, ваш ест 5%. Что меньше 5 или 0?
        Ваши аргументы звучат примерно так «на флеше тормозят игры с физикой и сложной анимацией, а простенькая картинка на хтмл не тормозит — значит флеш тормознутый, а хтмл нет».

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

      И на айпадике не заработает.

      Тут все же проще сделать PNG со спрайтами и яваскриптом менять background-position: — именно так делает Гугл на своих анимированных логотипах. Правда, для ИЕ6 придется извратиться — там прозрачный фоновый пнг нельзя двигать, обходится созданием огромной картинки и сменой у нее свойств margin-left, margin-top и clip. Ну или сделать не совсем прозрачный GIF — а вот нефиг юзать такой страый браузер.
  • +4
    780КБ для такой простой анимации — это, по-вашему, нормально?
    Где, как вам кажется, может найти применение данная наработка?
    • +1
      > 780КБ для такой простой анимации — это, по-вашему, нормально?
      Во-первых, 587 КБ — SVGZ с сайта понимается всеми браузерами. Локально Файрфокс пока не открывает, в багзилле висит баг насчет этого.
      Во-вторых, исходя из того, что в PNG применяется беспотерьное сжатие — вполне нормальный размер. Никто не запрещает использовать в кадрах JPEG.

      > Где, как вам кажется, может найти применение данная наработка?
      Для примера, если кодировать кадры в JPEG, можно реализовать превью видеороликов с плавной сменой кадров пока плеер не грузит видео/на паузе или в результатах поиска.
  • +1
    А если увеличить масштаб страницы в браузере, то анимация безбожно тормозит… Chrome 11.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Убрал.
      • НЛО прилетело и опубликовало эту надпись здесь
  • +2
    В хроме тоже не заработало, в фф и опере нормально…
  • +1
    Вместо тега animate (или по по условию, что браузер его не поддерживает) можно использовать встроенный JS в SVG.
  • 0
    ff4 Ubuntu 11.04… тоже заметное подтормаживание (типа фпс низкий) и нагрузка проца высокая, будто он это изображение рендерит в реальном времени
  • +1
    Раз уж это практически единственный на Хабре топик про APNG, то напишу сюда (надеюсь, и автору интересно будет):

    Библиотека для показа APNG при помощи canvas: github.com/davidmz/apng-canvas (БЕЗ предварительного раскладывания APNG на кадры)

    Расширение для Хрома, включающее в нём показ APNG: chrome.google.com/webstore/detail/ehkepjiconegkhpodgoaeamnpckdbblp
    • 0
      Премного благодарен!

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