
Здравствуйте. Не так давно на одном из веб-проектов, мне понадобилась возможность получить фото с веб-камеры. Через некоторое время, на другом проекте, появилась такая же необходимость, и опять же замаячил на горизонте третий проект, с похожей функциональностью. Дабы не ходить каждый раз на html5 Rocks, и смотреть, «как там и чего», решил написать плагин.
Собственно, в данной статье я хочу представить результат своего труда: html5-webcam-avatar — jquery плагин для создания аватарок с веб-камеры.
Что умеет плагин?
- Делать фото, а потом обрезать его квадратиком «как в контакте».
- Просто резать любые другие картинки с сайта.
Что не умеет?
- Работать в браузерах которые не поддерживают usermedia api, и работу с canvas.
То есть, плагин использует только javascript и нативные возможности браузера, никаких fallback-ов не предусмотрено.
Я бы рекомендовал его использовать, как дополнительную фичу на своем на сайте. Проверяем поддерживаются ли соответствующие возможности и подключаем плагин.
Как это работает?
Современные браузеры уже пытаются работать с веб-камерой и микрофоном. В javascript это реализовано через соответствующее api.
Пример кода с сайта html5 Rocks
window.URL = window.URL || window.webkitURL; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; //... if (navigator.getUserMedia) { navigator.getUserMedia({audio: true, video: true}, function(stream) { video.src = window.URL.createObjectURL(stream); }, onFailSoHard); } else { video.src = 'somevideo.webm'; // fallback. }
Все просто. Проверяем, определена ли функция
navigator.getUserMedia и выполняем соответствующий код. Иначе, выполняем какую-либо fallback функцию. Обо всем этом можно почитать подробнее на вышеописанном сайте. Я же хочу рассказать о некоторых не очевидных и неописанных там вещах.Во первых, поведение объекта
stream, отличается в разных браузерах. В chrome, для того чтобы передать его в параметр src тега video, его необходимо преобразовать в objectURL с помощью window.URL.createObjectURL. В opera, насколько я понял, объект stream преобразуется автоматически, и например свойства window.URL — я просто не нашел. Поэтому пишем напрямую: video.src = stream. Ну и firefox, имеет свойство window.URL и метод createObjectURL. Однако такой код window.URL.createObjectURL(stream) — выдает ошибку, а вот так video.src = stream — работает. NB
Вообще в firefox 18 мне так и не удалось заставить работать мой плагин, хотя свойство getUserMedia — там уже было, но недавно вышел firefox 19 и мой плагин заработал.
Поэтому у меня код получился таким:
navigator.getUserMedia && navigator.getUserMedia({video: true}, function(stream) { try { video.src = window.URL.createObjectURL(stream); //for webkit } catch (e) { video.src = stream; //for opera and firefox } }, function() { alert('веб-камера не найдена на этом устройстве'); });
Второй момент, про который хотелось бы рассказать, это работа с самим плеером. Дело в том, что для удобства, я решил сделать возможность остановить видео, а потом уже сделать snapshot. Так вот, остановка видео в chrome и firefox — происходит нормально. В opera же, вместе с остановкой видео происходит и остановка потока с веб-камеры. То есть, когда мы делаем snapshot в opera во время паузы — получаем вариант произведения известного художника (черный квадрат). Решение данной проблемы в принципе очевидно. Перед тем как поставить видео на паузу — мы сохраняем dataUrl в какое-то временное хранилище, ну а после, при создании снапшота — достаем его из хранилища, если видео на паузе, либо создаем dataUrl заново.
У меня это выглядит как то так:
// play/pause - при клике на само видео video.addEventListener('click', function() { if (video.paused) { video.play(); } else { $(video).data('data-url', getSnapshotDataUrl()); // здесь сохраняем данные в data-url video.pause(); } }); ... var getDataUrl = function() { var data_url = video.paused ? $video.data('data-url') : getSnapshotDataUrl(); return data_url; }
Здесь
getSnapshotDataUrl — функция которая перекидывает текущий кадр видео в элемент canvas, а затем у canvas вызывается метод toDataURL.Теперь пожалуй расскажу о самом плагине.
Вообще, тут получается не один, а два плагина. Первый для получения фото с веб-камеры
html5WebCam. Второй — для обрезки фото html5Crop. Да их можно использовать отдельно. Работает все следующим образом — мы навешиваем плагин на какой либо элемент. например
button. Теперь элемент слушает событие click и запускает процедуру создания аватара. Когда аватар будет готов, мы получим его в callback функции onCrop, или onsnapshot. $(document).ready(function() { $("#create_snapshot").html5WebCam({ oncrop: function(cropped_url) { // cropped_url - base64 image var $img = $("<img/>"); $img.attr('src', cropped_url); $('body').append($img); }, }); });
В плагине используются простые модальные окна, которые легко настраиваются через прилагающийся css файл. Если такое решение не устраивает, можно использовать свои модальные окна (на демо сайте есть пример с jquery-ui Dialog).
Есть и другие настраиваемые параметры, вот их список
//html5WebCam NOT_SUPPORT_FEATURE: 'Этот браузер не поддерживает захват с камеры', CAMERA_NOT_FOUND: 'Камера не найдена на этом устройстве', CLICK_TO_PAUSE: 'Нажмите для воспроизведения/остановки', TAKE_SNAPSHOT: 'Сделать снимок', CANCEL: 'Отмена', max_video_size: 600, modal_class: 'html5-webcam-avatar-modal', use_native_modal: true, use_native_button: true, onDomCreated: function($html) { }, onsnapshot: function(snapshot) {}, use_crop: true, oncrop: function(cropped_url) {}, oncancel: function() {}, alertFn: function(msg) { alert(msg); } //html5Crop CROP_NAME: 'резать', CANCEL: 'отмена', MIN_IMG_SIDE_ERROR: 'Слишком маленькое изображение по ширине или выстоте', CANVAS_NOT_SUPPORTED: 'canvas not supported in this browser', square_mode: true, max_crop_side: 400, min_crop_side: 50, max_img_side: 600, min_img_side: 100, init_crop_side: 100, dot_side: 10, use_native_modal: true, use_native_button: true, onDomCreated: function($ui) {}, oncancel: function() {}, oncrop: function(cropped_url) {}, alertFn: function(msg) { alert(msg); }, modal_class: 'html5-webcam-avatar-modal'
Думаю из названий понятно, для чего они нужны. Хочу только отметить, все параметры для html5Crop — нужно задавать в html5WebCam — при их совместном использовании, то есть если
use_crop: true (по умолчанию именно так).Демо и плагин — здесь
Жду вопросы, пожелания, критику и советы в комментариях.
