文章目录
- 1. 了解`navigator.mediaDevices.getUserMedia` API
- 2. 创建 HTML 结构
- 3. 编写 JavaScript 代码
- 3.1 打开摄像头
- 3.2 拍照
- 4. 完整代码
- 5. 测试
- 6. 注意事项及部署
在现代 Web 开发中,调用摄像头进行拍照是一个常见的功能,尤其是在需要用户上传头像、进行身份验证或实时交互的场景中。本文将逐步介绍如何在电脑端通过 HTML 和 JavaScript 调用摄像头进行拍照,并上传照片。我们将使用navigator.mediaDevices.getUserMedia
API 来实现这一功能。
1. 了解navigator.mediaDevices.getUserMedia
API
-
MediaDevices.getUserMedia() API
-
navigator.mediaDevices.getUserMedia
是一个现代浏览器提供的 API,用于访问用户的摄像头和麦克风。MediaDevices.getUserMedia()
会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream
,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D 转换器等等),也可能是其他轨道类型。它返回一个Promise
对象,成功后会resolve
回调一个MediaStream
对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise 会reject
回调一个PermissionDeniedError
或者NotFoundError
。 -
通过这个 API,我们可以请求设备的媒体输入,并将其流式传输到 HTML 的
<video>
元素中。
主要步骤
- 请求用户权限:在使用摄像头之前,必须请求用户的权限。
- 获取媒体流:通过
navigator.mediaDevices.getUserMedia
获取媒体流。 - 显示视频流:将媒体流绑定到
<video>
元素中。 - 拍照:使用
<canvas>
元素捕获视频帧并生成图片。
2. 创建 HTML 结构
首先,我们需要创建一个简单的 HTML 页面,包含一个视频元素、一个画布元素和两个按钮(一个用于打开摄像头,一个用于拍照)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>摄像头拍照</title>
<style>
.btn {
display: flex;
width: 40%;
height: 80px;
align-items: center;
justify-content: space-around;
}
.btn div {
background-color: purple;
color: white;
border-radius: 10px;
padding: 1rem;
}
</style>
</head>
<body>
<div></div>
<video id="video" autoplay style="width: 200px; height: 200px"></video>
<canvas
id="canvas"
width="200"
height="200"
style="border: 5px dotted yellowgreen"
></canvas>
<div class="btn">
<div id="open">打开摄像头</div>
<div id="photo">拍照</div>
</div>
</body>
</html>
3. 编写 JavaScript 代码
3.1 打开摄像头
当点击 打开摄像头 按钮时,我们需要调用navigator.mediaDevices.getUserMedia
来请求摄像头权限,并将视频流绑定到 <video>
元素中。
let open = document.querySelector("#open");
let video = document.querySelector("#video");
open.onclick = () => {
let constraints = {
video: { width: 200, height: 200 },
audio: false,
};
navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
video.srcObject = stream;
video.play();
})
.catch((error) => {
console.error("摄像头打开失败:", error);
});
};
3.2 拍照
当点击拍照 按钮时,我们需要使用 <canvas>
元素捕获当前视频帧,并将其转换为图片。
let photo = document.querySelector("#photo");
let canvas = document.querySelector("#canvas");
photo.onclick = () => {
let ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0, 200, 200);
// 将画布内容转换为 Base64 格式
let url = canvas.toDataURL("image/png");
console.log("Base64 URL: ", url);
// 将画布内容转换为 Blob 对象
canvas.toBlob((blob) => {
let blobUrl = URL.createObjectURL(blob);
let file = new window.File([blob], "封面图.png", { type: "image/png" });
console.log("Blob URL: ", blobUrl);
console.log("创建的新文件:", file);
// 使用FormData上传图片
let formData = new FormData();
formData.append("img", file);
fetch("http://localhost:8000", {
method: "post",
body: formData,
})
.then((response) => {
if (response.ok) {
console.log("文件上传成功");
} else {
console.error("文件上传失败");
}
})
.catch((error) => {
console.error("图片上传失败:", error);
});
});
};
4. 完整代码
将上述 HTML 和 JavaScript 代码组合在一起,完整的 HTML 文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>摄像头拍照</title>
<style>
.btn {
display: flex;
width: 40%;
height: 80px;
align-items: center;
justify-content: space-around;
}
.btn div {
background-color: purple;
color: white;
border-radius: 10px;
padding: 1rem;
}
</style>
</head>
<body>
<div></div>
<video id="video" autoplay style="width: 200px; height: 200px"></video>
<canvas
id="canvas"
width="200"
height="200"
style="border: 5px dotted yellowgreen"
></canvas>
<div class="btn">
<div id="open">打开摄像头</div>
<div id="photo">拍照</div>
</div>
<script>
let open = document.querySelector("#open");
let video = document.querySelector("#video");
let photo = document.querySelector("#photo");
let canvas = document.querySelector("#canvas");
open.onclick = () => {
let constraints = {
video: { width: 200, height: 200 },
audio: false,
};
navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
video.srcObject = stream;
video.play();
})
.catch((error) => {
console.error("摄像头打开失败:", error);
});
};
photo.onclick = () => {
let ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0, 200, 200);
// 将画布内容转换为Base64格式
let url = canvas.toDataURL("image/png");
console.log("Base64 URL: ", url);
// 将画布内容转换为Blob对象
canvas.toBlob((blob) => {
let blobUrl = URL.createObjectURL(blob);
let file = new window.File([blob], "封面图.png", {
type: "image/png",
});
console.log("Blob URL: ", blobUrl);
console.log("创建的新文件:", file);
// 使用FormData上传图片
let formData = new FormData();
formData.append("img", file);
fetch("http://localhost:8000", {
method: "post",
body: formData,
})
.then((response) => {
if (response.ok) {
console.log("文件上传成功");
} else {
console.error("文件上传失败");
}
})
.catch((error) => {
console.error("图片上传失败:", error);
});
});
};
</script>
</body>
</html>
5. 测试
测试:在本地运行 HTML 文件,使用 live Server
,确保摄像头可以正常打开,并且拍照功能可以正常工作。
截图:
6. 注意事项及部署
- 部署:将 HTML 文件部署到支持 HTTPS 的服务器上,因为
navigator.mediaDevices.getUserMedia
需要在 HTTPS 环境下工作。 - 浏览器支持:确保目标浏览器支持
navigator.mediaDevices.getUserMedia
API。 - 错误处理:在实际应用中,需要对可能出现的错误进行处理,例如用户拒绝权限请求。