直接上代码:
<template>
<div>
<button @click="openCamera">打开摄像头</button>
<button @click="takePhoto">拍照</button>
<video ref="video" width="640" height="480"></video>
<canvas ref="canvas" width="640" height="480" style="display: none;"></canvas>
<img :src="photoDataUrl" alt="拍照的图片">
</div>
</template>
export default {
data() {
return {
//拍的照片存储的容器
photoDataUrl: '',
stream: null,
videoElement: null,
canvasElement: null,
};
},
mounted() {
//通过 ref 获取到的 video 元素赋值给组件实例的 videoElement 属性
this.videoElement = this.$refs.video;
//通过 ref 获取到的 canvas 元素赋值给组件实例的 canvasElement 属性
this.canvasElement = this.$refs.canvas;
},
methods: {
openCamera() {
/*
调用了 navigator.mediaDevices.getUserMedia 方法
该方法请求用户授权访问本地设备(例如摄像头、麦克风等) 并返回一个 Promise 对象。
调用该方法时,代码传入一个配置对象,指定要访问的设备类型
例如 { video: true } 表示要获取视频流。调用 then 方法来处理成功的情况
*/
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
//将视频流赋值给 Vue 实例的 stream 属性
this.stream = stream;
//视频流绑定到 HTML5 的 video 元素上,使用 srcObject 属性来实现,并调用 play 方法播放视频
this.videoElement.srcObject = stream;
this.videoElement.play();
//通过以上的这样的操作,即可实现摄像头视频流的捕获和展示。
})
.catch((error) => {
console.error('打开摄像头失败:', error);
});
},
takePhoto() {
//首先获取了 Canvas 元素的上下文对象 context:
const context = this.canvasElement.getContext('2d');
//通过 context.drawImage 方法将视频元素中当前帧的图像绘制到 Canvas 中:
/*
this.videoElement 表示视频元素
0 和 0 表示图像在 Canvas 中的起始坐标
this.canvasElement.width 和 this.canvasElement.height 表示图像在 Canvas 中的宽度和高度。
这一步是实现了将当前摄像头所捕获的图像绘制到 Canvas 中,以便后续可以处理图像。
*/
context.drawImage(this.videoElement, 0, 0, this.canvasElement.width, this.canvasElement.height);
// 将拍照的图片转换为base64格式
this.photoDataUrl = this.canvasElement.toDataURL('image/jpeg');
// 调用 getTracks() 方法遍历摄像头视频流的所有轨道,并逐一停止它们,这样就关闭了摄像头:
this.stream.getTracks().forEach((track) => {
track.stop();
});
// 发送照片数据给后台
this.uploadPhoto(this.photoDataUrl);
},
uploadPhoto(photoDataUrl) {
// 将照片数据上传给后台
axios.post('/upload', { photo: photoDataUrl })
.then((response) => {
console.log('照片上传成功');
})
.catch((error) => {
console.error('照片上传失败:', error);
});
},
},
};