MDN Web API 教程:使用 getUserMedia() 拍摄静态照片
2025-07-07 01:21:10作者:卓艾滢Kingsley
本文将详细介绍如何利用 WebRTC 技术中的 navigator.mediaDevices.getUserMedia()
API 访问用户设备的图像采集设备,并实现拍照功能。这是一个非常实用的功能,可以应用于各种需要用户上传照片的 Web 应用中。
功能概述
我们将创建一个简单的拍照应用,主要功能包括:
- 访问用户设备的图像采集设备
- 实时显示采集的画面
- 点击按钮拍摄静态照片
- 显示拍摄的照片
准备工作
HTML 结构
首先,我们需要设置基本的 HTML 结构:
<div class="content-area">
<h1>拍照功能演示</h1>
<div class="camera">
<video id="video">视频流不可用</video>
<button id="start-button">拍照</button>
</div>
<canvas id="canvas"></canvas>
<div class="output">
<img id="photo" alt="拍摄的照片将显示在这里">
</div>
</div>
这个结构包含三个主要部分:
- 视频显示区域 (
<video>
) - 拍照按钮
- 照片显示区域 (
<img>
)
注意我们还包含了一个隐藏的 <canvas>
元素,它将在拍照过程中作为中间处理环节使用。
JavaScript 实现
初始化变量
首先定义一些全局变量:
const width = 320; // 照片宽度
let height = 0; // 高度将根据视频流计算
let streaming = false; // 标记视频流状态
// 获取DOM元素
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const photo = document.getElementById('photo');
const startButton = document.getElementById('start-button');
获取图像采集设备访问权限
核心是调用 getUserMedia()
方法请求访问图像采集设备:
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then((stream) => {
video.srcObject = stream;
video.play();
})
.catch((err) => {
console.error(`发生错误: ${err}`);
});
这个方法返回一个 Promise:
- 成功时:将视频流赋给
<video>
元素并开始播放 - 失败时:打印错误信息(可能是用户拒绝授权或没有设备)
视频准备就绪处理
我们需要监听视频的 canplay
事件,当视频可以播放时进行初始化:
video.addEventListener('canplay', (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', (ev) => {
takePicture();
ev.preventDefault();
}, false);
拍照的核心函数 takePicture()
:
function takePicture() {
const context = canvas.getContext('2d');
if (width && height) {
// 设置画布尺寸
canvas.width = width;
canvas.height = height;
// 将视频帧绘制到画布上
context.drawImage(video, 0, 0, width, height);
// 将画布内容转为图片数据
const data = canvas.toDataURL('image/png');
// 显示拍摄的照片
photo.setAttribute('src', data);
} else {
clearPhoto();
}
}
清除照片
我们还需要一个清除照片的函数:
function clearPhoto() {
const context = canvas.getContext('2d');
// 用灰色填充画布
context.fillStyle = '#AAA';
context.fillRect(0, 0, canvas.width, canvas.height);
// 将空白画布转为图片并显示
const data = canvas.toDataURL('image/png');
photo.setAttribute('src', data);
}
添加滤镜效果
我们可以扩展功能,为拍摄的照片添加滤镜效果:
function takePicture() {
const context = canvas.getContext('2d');
if (width && height) {
canvas.width = width;
canvas.height = height;
// 获取视频元素应用的CSS滤镜
const videoStyles = window.getComputedStyle(video);
const filterValue = videoStyles.getPropertyValue('filter');
// 将同样的滤镜应用到画布
context.filter = filterValue !== 'none' ? filterValue : 'none';
context.drawImage(video, 0, 0, width, height);
const dataUrl = canvas.toDataURL('image/png');
photo.setAttribute('src', dataUrl);
} else {
clearPhoto();
}
}
这样,如果视频元素应用了CSS滤镜(如灰度、模糊等),拍摄的照片也会应用相同的效果。
选择特定设备
如果需要指定使用某个特定的图像采集设备:
// 首先枚举所有可用设备
navigator.mediaDevices.enumerateDevices()
.then((devices) => {
// 筛选出视频输入设备
const videoDevices = devices.filter(device => device.kind === 'videoinput');
// 使用第一个视频设备
if (videoDevices.length > 0) {
return navigator.mediaDevices.getUserMedia({
video: {
deviceId: videoDevices[0].deviceId
},
audio: false
});
}
})
.then((stream) => {
// 处理视频流
video.srcObject = stream;
video.play();
})
.catch((err) => {
console.error(`发生错误: ${err}`);
});
注意事项
- 用户权限:浏览器会要求用户授权访问图像采集设备,用户必须同意才能继续
- HTTPS:在生产环境中,此API只能在安全上下文(HTTPS)中工作
- 错误处理:需要妥善处理用户拒绝授权或没有设备的情况
- 性能考虑:高分辨率视频流可能会影响性能,特别是移动设备
总结
通过本文,我们学习了如何使用WebRTC API实现浏览器中的拍照功能。这个功能可以广泛应用于各种Web应用,如:
- 用户头像上传
- 证件照拍摄
- 产品展示
- 在线考试监考系统等
关键点在于理解视频流、画布和图像数据之间的转换过程。通过扩展这个基础功能,你可以实现更复杂的效果,如实时滤镜、人脸识别等高级特性。