Здравствуйте. Не так давно на одном из веб-проектов, мне понадобилась возможность получить фото с веб-камеры. Через некоторое время, на другом проекте, появилась такая же необходимость, и опять же замаячил на горизонте третий проект, с похожей функциональностью. Дабы не ходить каждый раз на 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
— работает.
Поэтому у меня код получился таким:
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
(по умолчанию именно так).
Демо и плагин — здесь
Жду вопросы, пожелания, критику и советы в комментариях.
Автор: kromxr