在网页中访问摄像头

5
我正在开发一个网络应用程序。
在我的客人注册页面上,我需要 访问网络摄像头 来拍摄客人的图像。
我所拍摄的图像可以存储在指定的位置。
哪种方法是最好的呢?
使用Java、JSP、HTML、JavaScript或任何其他方法都可以。

2
请查看签名的Java小程序。我曾为Topaz签名板完成过此操作,效果非常好。我甚至能够让签名的小程序安装签名板的驱动程序,这样他们只需将其插入并访问带有小程序的页面即可。 - Zoidberg
那么您将希望访问客户端上的网络摄像头,因此服务器上的技术变得无关紧要。 - Quentin
@Quentin,这是否意味着无法访问客户端摄像头? - Sarin Jacob Sunny
@SarinJacobSunny — 不,这意味着你在服务器上使用Java并不重要。 - Quentin
@Quentin。在一些网站上,他们会访问我们的网络摄像头来设置我们的个人资料照片。实际上,这启发了我采用这种方法。 - Sarin Jacob Sunny
显示剩余3条评论
2个回答

7

作为回答自己的问题,因为有更好的方法可以使用 HTML5。

选项1,从系统访问默认摄像头

HTML

Video Tag
<br/>
<div class="camera">
    <video id="video">Video stream not available.</video>
    <button id="startbutton">Take photo</button>
</div>
<br/>
Canvas
<br/>
<canvas id="canvas"></canvas>

脚本

var width = 320;
var height = 0;
var streaming = false;

navigator.mediaDevices.getUserMedia({video: true, audio: false})
        .then(function (stream) {
            video.srcObject = stream;
            video.play();
        })
        .catch(function (err) {
            console.log("An error occured! " + err);
        });

video.addEventListener('canplay', function (ev) {
    if (!streaming) {
        height = video.videoHeight / (video.videoWidth / width);
        video.setAttribute('width', width);
        video.setAttribute('height', height);
        canvas.setAttribute('width', width);
        canvas.setAttribute('height', height);

        streaming = true;
    }
}, false);

startbutton.addEventListener('click', function (ev) {
    takepicture();
    ev.preventDefault();
}, false);

clearphoto();

function clearphoto() {
    var context = canvas.getContext('2d');
    context.fillStyle = "#AAA";
    context.fillRect(0, 0, canvas.width, canvas.height);
}

function takepicture() {
    var context = canvas.getContext('2d');
    if (width && height) {
        canvas.width = width;
        canvas.height = height;
        context.drawImage(video, 0, 0, width, height);

        var dataURL = canvas.toDataURL("image/jpeg", 0.95);
        if (dataURL && dataURL != "data:,") {
            var fileName = generateImageName();
            uploadimage(dataURL, fileName);
        } else {
            alert("Image not available");
        }
    } else {
        clearphoto();
    }
}

function generateImageName() {
    ... generate image name logic here ...
    return imageName;
}

function uploadimage(dataurl, filename) {
    ... upload logic here ...
}

截图

截图

选项2,提供系统中可用相机列表,并让用户选择相机。

HTML

<select id="videoSelect"></select>
    <button id="startCameraButton">Start Camera</button>
    <br/>
    Video Tag
    <br/>
    <div class="camera">
        <video id="video">Video stream not available.</video>
        <button id="takePictureButton">Take photo</button>
    </div>
    <br/>
    Canvas
    <br/>
    <canvas id="canvas">
    </canvas>

脚本

var width = 320;
var height = 0;
var streaming = false;
var localstream = null;

startCameraButton.onclick = start;
takePictureButton.onclick = takepicture;

navigator.mediaDevices.enumerateDevices()
        .then(gotDevices)
        .catch(function (err) {
            console.log("An error occured while getting device list! " + err);
        });

function gotDevices(deviceInfos) {
    while (videoSelect.firstChild) {
        videoSelect.removeChild(videoSelect.firstChild);
    }

    for (var i = 0; i !== deviceInfos.length; ++i) {
        var deviceInfo = deviceInfos[i];
        var option = document.createElement('option');
        option.value = deviceInfo.deviceId;
        if (deviceInfo.kind === 'videoinput') {
            option.text = deviceInfo.label || 'Camera ' + (videoSelect.length + 1);
            videoSelect.appendChild(option);
        }
    }
}

function start() {
    stopVideo();
    clearphoto();
    var videoSource = videoSelect.value;
    var constraints = {
        audio: false,
        video: {deviceId: videoSource ? {exact: videoSource} : undefined}
    };
    navigator.mediaDevices.getUserMedia(constraints).
            then(gotStream).then(gotDevices).catch(handleError);
}



function gotStream(stream) {
    localstream = stream;
    video.srcObject = stream;
    video.play();
    // Refresh button list in case labels have become available
    return navigator.mediaDevices.enumerateDevices();
}

function handleError(error) {
    console.log('navigator.getUserMedia error: ', error);
}

video.addEventListener('canplay', function (ev) {
    if (!streaming) {
        height = video.videoHeight / (video.videoWidth / width);
        video.setAttribute('width', width);
        video.setAttribute('height', height);
        canvas.setAttribute('width', width);
        canvas.setAttribute('height', height);

        streaming = true;
    }
}, false);

clearphoto();

function clearphoto() {
    var context = canvas.getContext('2d');
    context.fillStyle = "#AAA";
    context.fillRect(0, 0, canvas.width, canvas.height);
}

function takepicture() {
    var context = canvas.getContext('2d');
    if (width && height) {
        canvas.width = width;
        canvas.height = height;
        context.drawImage(video, 0, 0, width, height);

        var dataURL = canvas.toDataURL("image/jpeg", 0.95);
        if (dataURL && dataURL != "data:,") {
            var fileName = generateImageName();
            fileName = fileName + ".txt"
            uploadimage(dataURL, fileName);
        } else {
            console.log("Image not available");
        }
    } else {
        clearphoto();
    }
}

    function generateImageName() {
    ... generate image name logic here ...
    return imageName;
}

function uploadimage(dataurl, filename) {
    ... upload logic here ...
}

function stopVideo() {
    if (localstream) {
        localstream.getTracks().forEach(function (track) {
            track.stop();
            localstream = null;
        });
    }
}

截图

输入图片描述

选项3:让用户选择音视频源和音频输出

在选项2中,用户可以选择任何特定的摄像头。如果用户还想选择音频源和音频输出源,只需按照以下更改修改上述代码。

HTML

            audioInputSelect
            <br/>
            <select id="audioInputSelect"></select>
            <br/>
            audioOutputSelect
            <select id="audioOutputSelect"></select>

脚本

function gotDevices(deviceInfos) {
    while (videoSelect.firstChild) {
        videoSelect.removeChild(videoSelect.firstChild);
    }

    for (var i = 0; i !== deviceInfos.length; ++i) {
        var deviceInfo = deviceInfos[i];
        var option = document.createElement('option');
        option.value = deviceInfo.deviceId;
        if (deviceInfo.kind === 'audioinput') {
            option.text = deviceInfo.label || 'Microphone ' + (audioInputSelect.length + 1);
            audioInputSelect.appendChild(option);
        } else if (deviceInfo.kind === 'audiooutput') {
            option.text = deviceInfo.label || 'Speaker ' + (audioOutputSelect.length + 1);
            audioOutputSelect.appendChild(option);
        } else if (deviceInfo.kind === 'videoinput') {
            option.text = deviceInfo.label || 'Camera ' + (videoSelect.length + 1);
            videoSelect.appendChild(option);
        }
    }
}

function start() {
    stopVideo();
    clearphoto();
    var audioSource = audioInputSelect.value;
    var videoSource = videoSelect.value;
    var constraints = {
      audio: {deviceId: audioSource ? {exact: audioSource} : undefined},
        video: {deviceId: videoSource ? {exact: videoSource} : undefined}
    };
    navigator.mediaDevices.getUserMedia(constraints).
            then(gotStream).then(gotDevices).catch(handleError);
}

5

如果这个可行,我会说这是最理想的解决方案,需要最少的工作量,干得好。 - Zoidberg
我现在没有摄像头(在办公室),只有在测试过摄像头后,我才能对其发表评论,抱歉。 - Sarin Jacob Sunny
1
我用笔记本电脑测试了那个页面。在第一个窗口中,它显示了来自我的相机的输入,但是当我点击拍照后,它没有显示任何操作。 - Sarin Jacob Sunny
1
当您点击“立即拍照”时,它应该在相机视图下方的框中显示所拍摄的照片。这里可以正常工作。 - Fabio Gomes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接