Create autocards in a browser using a webcam


Hello. Not so long ago at one of the web projects, I needed the opportunity to get a photo from a webcam. After a while, on another project, the same need arose, and again a third project loomed on the horizon, with similar functionality. In order not to go to html5 Rocks every time , and to watch, “what's there and what,” I decided to write a plugin.
Actually, in this article I want to present the result of my work: html5-webcam-avatar - a jquery plugin for creating avatars from a webcam.



What can a plugin do?
  • Take a photo, and then crop it with a square “like in contact”.
  • Just cut any other pictures from the site.

What does not know how?
  • Work in browsers that do not support usermedia api, and work with canvas.

That is, the plugin uses only javascript and native browser features, no fallbacks are provided.
I would recommend using it as an additional feature on my site. We check if the corresponding capabilities are supported and connect the plugin.

How it works?
Modern browsers are already trying to work with a webcam and microphone. In javascript, this is implemented through the corresponding api.
Sample code from 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.
}

Everything is simple. We check whether the function is defined navigator.getUserMediaand execute the corresponding code. Otherwise, we perform some kind of fallback function. You can read more about all this on the above site. I want to talk about some things that are not obvious and not described there.

Firstly , the behavior of the object streamis different in different browsers. In chrome, in order to pass it to a src tag parameter video, it must be converted to objectURLwith window.URL.createObjectURL. In opera, as I understand it, the object is stream converted automatically, and for example properties window.URL- I just did not find it. Therefore, we write directly to: video.src = stream. Well, firefox has a property window.URL and a method createObjectURL. However, such a code window.URL.createObjectURL(stream)- gives an error, but like that video.src = stream- it works.
NB
In general, in firefox 18 I was not able to get my plugin to work, although the getUserMedia property was already there, but firefox 19 recently came out and my plugin worked.

Therefore, my code turned out like this:
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('веб-камера не найдена на этом устройстве'); });


The second point that I would like to talk about is working with the player itself. The fact is that for convenience, I decided to make it possible to stop the video, and then do a snapshot. So, stopping the video in chrome and firefox is normal. In opera, along with stopping the video, the stream from the webcam stops. That is, when we do a snapshot in opera during a pause, we get a version of the work of a famous artist (black square). The solution to this problem is, in principle, obvious. Before pausing the video, we save the dataUrl to some temporary storage, and then, when creating the snapshot, we get it out of the storage if the video is paused, or create dataUrl again.
It looks something like this for me:
// 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;
}

Here getSnapshotDataUrlis a function that throws the current frame of the video into an element canvas,and then the method is called on canvas toDataURL.

Now perhaps I’ll talk about the plugin itself.
In general, here it turns out not one, but two plugins. The first is to get a photo from a webcam html5WebCam. The second - to crop the photo html5Crop. Yes, they can be used separately.
Everything works as follows - we hang the plugin on some element. for example button. Now the element listens to the event click and starts the procedure for creating an avatar. When the avatar is ready, we will get it in callbackfunction onCrop, or onsnapshot.
$(document).ready(function() {
    $("#create_snapshot").html5WebCam({
        oncrop: function(cropped_url) { 
            // cropped_url - base64 image 
            var $img = $("");
            $img.attr('src', cropped_url);
            $('body').append($img);
        },
    });
});

The plugin uses simple modal windows that are easily customizable via the attached css file. If this solution does not suit you, you can use your modal windows (there is an example with jquery-ui Dialog on the demo site).

There are other customizable options, here is a list of them
//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'

I think from the names it’s clear why they are needed. I just want to note that all the parameters for html5Crop - need to be set in html5WebCam - when they are used together, that is, if use_crop: true(by default it is).

Demo and plugin - here
I am waiting for questions, suggestions, criticism and advice in the comments.

Also popular now: