Прикручиваем определение поддержки формата APNG к Modernizr

Несмотря на то, что все говорят о возможностях HTML5, такой элементарный элемент дизайна сайта как прелоадер с прозрачностью до сих пор приходится делать с использование Animated GIF. Использование 8-битного анимированного GIF не даёт возможности реализовывать полупрозрачные переходы. В качестве современной альтернативы анимированному GIF можно было бы предположить два конкурирующих формата — MNG и APNG, но MNG не имеет и скорее всего уже никогда не получит нативной поддержки со стороны браузеров, а формат APNG мы уже можем использовать в Firefox и Opera ещё со второй половины 2008 года. К сожалению, Chrome, Safari и Internet Explorer, остались в стороне, для них по прежнему придется использовать угловатые картинки в старом формате GIF. Тем не менее, сегодня у нас есть такая замечательная штука как Modernizr — инструмент перехода к практике определения возможностей браузера, вместо использования порочной практики определения наименования и версии браузера.



Собственно сам APNG Modernizr Test


После нахождения небольшого кусочка javascript-кода определяющего поддержку APNG, мне как-то сразу захотелось прикрутить его к Modernizr, благо у последнего для этого есть специальное простое API:

/**
 * APNG Modernizr Test Workaround
 */
(function(){
    var testImage = new Image();
    var canvasContext = document.createElement('canvas').getContext('2d');
    var isApngSupported = false;

    testImage.onload = function () {
        canvasContext.drawImage(testImage, 0, 0);
        isApngSupported = canvasContext.getImageData(0, 0, 1, 1).data[3] === 0;
        if (typeof isApngSupported !== "boolean") {
            var isApngSupported = false;
        }
        Modernizr.addTest('apng', function() {
            return isApngSupported;
        });
    };
    testImage.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";
})();


В зависимости от того поддерживает ли браузер APNG или нет, у тега html появится дополнительный класс apng или no-apng. Из CSS мы можем это использовать так:

.no-apng .preloader {
    background-image: url(some.gif);
}
.apng .preloader {
    background-image: url(some.png); 
}


Программами, не понимающими анимацию, APNG отображается как статичный PNG.

За эту информацию спасибо моему коллеге SeVit`у.
+17
10 августа 2011, 18:51
19
artifex 79,3

комментарии (26)

–1
RiderSx #
Эх, думал что тут хак чтоб APNG и в хроме показывался нормально :( Но все равно полезная штука :)
0
VakarimaZ #
Попробуйте вот это расширение
+1
JhaoDa #
Как я понимаю, вся сила в строке isApngSupported = canvasContext.getImageData(0, 0, 1, 1).data[3] === 0; Разъяснили бы кратко, что там к чему.
0
SeVit #
Эли Грей сам не расписывает свой метод,
как я понял «вся сила» в анимированной картинке завёрнутой в dataUri.
Могу только предположить, что drawImage размещает в canvas последний, а не первый, кадр из анимированной картинки.
Главное же, что CanvasPixelArray возвращаются разные, для анимированной и неанимированной картинок.

Добавил ссылку на автора кода.
+3
bolk #
Просто догадаться. Я когда увидел заголовок сразу придумал как бы я это сделал.

В Data URI находится APNG с двумя кадрами, которые меняются без задержки и не закальцованы. В браузерах с поддержкой APNG будет виден последний кадр, без оной — первый. Кадры 1×1 пиксель и различаются одной цветовой компонентой. Её и проверяем.
0
JhaoDa #
Не, логика такая: canvasContext.getImageData(0, 0, 1, 1) возвращает объект ImageData для левого верхнего пикселя canvas. ImageData же содержит объект data типа CanvasPixelArray (по факту это массив Uint8ClampedArray), размерностью height × width × 4 (4 байта на пиксель, ибо RGBA). Ну и судя по data[3], смотрим на Alpha-компонент это одинокого пикселя.
0
TheShock #
Вообще-то все браузеры поддерживают первый кадр APNG, тк он обратно совместим с обычным PNG. Вопрос в том, почему в браузерах, которые поддерживают APNG отрисовывается другой кадр,
0
bolk #
Потому что там конечная анимация из двух кадров.
0
bolk #
А! Совсем забыл. В APNG есть такая фишка — первый кадр можно совсем не использовать, а браузеры, понимающие только PNG, будут использовать только первый кадр.
+1
KAndy #
Только одно маленькое замечание: Этот скрипт проверяет не «поддержку поддержку APNG» а «поддержку поддержку Canvas API + Data protocol + APNG „
0
SeVit #
К сожалению, более удобного способа без использования canvas и data Uri я не знаю.
0
torbasow #
Ну как же? Есть же ещё «порочная практика определения наименования и версии браузера».
0
TheShock #
Нууу. Все браузеры, которые не поддерживают Canvas — не поддерживают APNG ;)
0
torbasow #
Чем полагаться на такие вещи лучше, чем полагаться на версии браузеров? Практически то же самое выходит.
0
TheShock #
Тем, что если в новой версии Хрома добавится возможность проигрывать APNG — будем использовать нативную реализацию.
0
torbasow #
И то верно. Но не было бы разумней сначала отсеивать уже заведомо поддерживающие APNG браузеры, не заставляя их выполнять лишний код, и уже потом прогонять тест на остальных?
0
TheShock #
оно выполняется один раз за 0.1 микросекунды. Если отсеем «уже заведомо поддерживающие APNG браузеры», то в них будет выполнятся за 0.08 микросекунды, а в остальных — за 0.14 микросекунды. Думаете, имеет смысл?
0
torbasow #
Правда? Есть замеры? Как-то не верится. По-моему, Javascript вообще работает скорее в масштабах миллисекунд, чем микросекунд. Да вот и профилирование Firebug’ом на тестовой странице рапортует мне о 1,5 миллисекунд.

Да, тоже очень немного. Но я бы для очистки совести попробовал добавить предварительную фильтрацию и сравнить.
+2
TheShock #
+1
SeVit #
Надо было добавить «Анимация APNG с помощью canvas в Google Chrome, Internet Explorer 9, Apple Safari»
apng-canvas demo

Спасибо, однозначно в закладки.
0
SeVit #
забыл про не отражённую визуально невозможность оставлять ссылки недостойными,
вот ссылка на apng-canvas demo
davidmz.github.com/apng-canvas/
0
TheShock #
Ну да. Только в браузерах, где есть Canvas. Это вполне логично, что в браузерах, где нету Canvas нельзя сделать анимацию с помощью Canvas.

Тем не менее, это замечательно, т.к. уже все современные браузеры могут поддерживать apng.
+1
TheShock #
isApngSupported = canvasContext.getImageData(0, 0, 1, 1).data[3] === 0;
if (typeof isApngSupported !== "boolean") {
    var isApngSupported = false;
}

А какой тип кроме «boolean» может вернуть операция "==="
0
ArtyV #
На будущее: полупрозрачный лоадер можно сделать с помощью сдвига PNG-спрайта джаваскриптом, даже красивее будет
0
vault #
мало того — анимированный гиф можно сохранять с альфа-прозрачностью, что полностью решает проблему.
0
ArtyV #
Интересно. Как это сделать и где это работает?

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