Элемент <canvas>
(по-русски — холст) был добавлен в спецификацию html5 еще несколько лет назад. Поэтому он полностью поддерживается IE, начиная с 9-го. Canvas предназначен для создания и обработки различной растровой графики при помощи JavaScript. Кроме этого его можно использовать для работы с анимацииями и даже обработки видео в реальном времени.
Давайте рассмотрим работу с canvas в контексте фильтрации изображений (применения различных эффектов). В этом случае задача сводится к тому, что-бы поместить изображение на canvas и математически описать преобразования, которые нужно сделать с каждым его пикселем.
js
// создаем или находим изображение
var img = document.getElementById('img');
img.onload = function() {
// создаем или находим canvas
var canvas = document.getElementById('canvas');
// получаем его 2D контекст
var context = canvas.getContext('2d');
// помещаем изображение в контекст
context.drawImage(img, 0, 0);
// получаем объект, описывающий внутреннее состояние области контекста
var imageData = context.getImageData(0, 0, 300, 300);
// фильтруем
imageDataFiltered = sepia(imageData);
// кладем результат фильтрации обратно в canvas
context.putImageData(imageDataFiltered, 0, 0);
}
img.src = 'img/girl.png';
Фильтр представляет из себя набор математических опаераций над значениями красного, зеленого и синего канала каждой из точек изображения. Вот, например, простейший эффект сепия.
js
var sepia = function (imageData) {
// получаем одномерный массив, описывающий все пиксели изображения
var pixels = imageData.data;
// циклически преобразуем массив, изменяя значения красного, зеленого и синего каналов
for (var i = 0; i < pixels.length; i += 4) {
var r = pixels[i];
var g = pixels[i + 1];
var b = pixels[i + 2];
pixels[i] = (r * 0.393)+(g * 0.769)+(b * 0.189); // red
pixels[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168); // green
pixels[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131); // blue
}
return imageData;
};
Как мы уже упоминали, pixels
— это одномерный массив в котором последовательно представлены значения красного, зеленого, синего канала, а так-же канала прозрачности для каждого пикселя изображения. Графически его можно представить так:
Результат в демке
Готовые библиотеки и плагины:
… и еще 100500 библиотек, если немного погуглить.
Достоинства фильтрации с Canvas
- поддерживается IE 9-ым и практически всеми мобильными браузерами.
- множество готовых решений, библиотек, плагинов.
- фильтры могут быть настолько сложными и нестандартными, насколько у вас хватит фантазии и насколько вы разбираетесь в цифровой обработке изображений :)
Недостатки фильтрации с Canvas
- Нельзя обработать картинки с других доменов (включая поддомены) из-за ограничений безопасности браузера. Это довольно легко решается проксированием или переводом в base64, но как бы то ни было, создает дополнительные проблемы.
- Если мы говорим про сложные фильтры, то это медленная, последовательная, блокирующая операция. Десктопный браузер при этом подтормаживает, а мобильный браузер серьезно тупит.
Про недостатки:
C других доменов, в общем смысле, конечно, нельзя обрабатывать ресурсы. Но для этого не всегда нужно проксирование — сервер может отдавать заголовки (CORS), которые разрешают конкретному сайту (домену) или всем использовать свои ресурсы. Тогда проблем с другим доменом не будет. Ведь мы можем хранить наши изображения в CDN и проксирование будет не эффективным. Так же конвертация в base64 и обратно — не быстрая операция. И при конвертации base64 -> image такому изображение ставится текущий домен в качестве origin (если не ошибаюсь). Это так же может помешать «смешать» два изображения с разных доменов.
Для того, чтобы не было проблем с быстродействием, можно выносить обработку изображения в Web Worker’ы (например, http://blogs.msdn.com/b/eternalcoding/archive/2012/09/20/using-web-workers-to-improve-performance-of-image-manipulation.aspx). Если обработка не требует соседних пикселей (как серпия, например), то можно даже распараллелить обработку по нескольким worker’ам.
Роман, круто, спасибо за отличный коммент!