浏览器调起摄像头
<template>
<div class="body">
这里什么都没有
<video id="videoCamera" class="video"></video>
<button @click="getCompetence" class="btn">打开摄像头</button>
<button @click="stopNavigator" class="btn">关闭摄像头</button>
<button @click="setImage" class="btn">点击截图</button>
{
{
imgSrc }}
<canvas class="canvas" id="canvasCamera"></canvas>
</div>
</template>
<script>
export default {
data() {
return {
videoWidth: 500,
videoHeight: 300,
number: 0,
hours: 0,
minutes: 0,
seconds: 0,
run: false,
imgSrc: '',
flag: true,
thisCancas: null,
thisContext: null,
thisVideo: null,
userInfo: {
imgStr: ""
},
videoState: true
}
},
methods: {
// 调用摄像头
getCompetence() {
this.videoState = false
var _this = this
this.thisCancas = document.getElementById('canvasCamera')
this.thisContext = this.thisCancas.getContext('2d')
this.thisVideo = document.getElementById('videoCamera')
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {
}
}
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先获取现存的getUserMedia(如果存在)
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
console.log('viedo', getUserMedia);
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
}
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject)
})
}
}
//使用此方式获取本地音频视频输入输出设备,找到要使用的设备id,方式见下图
var enumeratorPromise = navigator.mediaDevices.enumerateDevices()
console.log(enumeratorPromise)
//把上面获取到的设备deviceId填入下面video的deviceId中,就可以选择要调用的摄像头了
var constraints = {
audio: false, video: {
deviceId: 'becf7e45fe56e42bcb4ec3f78b1b6b0fcffd6c6ccd890d30fffc2430a92c99bb', width: this.videoWidth, height: this.videoHeight } }
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
// 旧的浏览器可能没有srcObject
if ('srcObject' in _this.thisVideo) {
_this.thisVideo.srcObject = stream
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL.createObjectURL(stream)
}
_this.thisVideo.onloadedmetadata = function (e) {
if (_this.flag == true) {
_this.thisVideo.play();
_this.flag = false;
}
else {
_this.thisVideo.pause()
_this.flag = true;
}
}
}).catch(err => {
console.log(err)
})
},
// 关闭摄像头
stopNavigator() {
this.videoState = true
this.thisVideo.srcObject.getTracks()[0].stop()
},
// 截图
setImage() {
var _this = this
_this.imgSrc = '';
// 点击,canvas画图
_this.thisContext.drawImage(_this.thisVideo, 0, 0, _this.videoWidth, _this.videoHeight)
// 获取图片base64链接
_this.imgSrc = this.thisCancas.toDataURL('image/png')//_this.imgSrc为解码得到的base64编码格式的图片
//转blob的url
// const blob = base64ToBlob(base64String);
// const imageUrl = blobToUrl(blob);
// console.log(imageUrl);
// _this.imgSrc = imageUrl
console.log('picture', _this.imgSrc)
// this.$emit('setImgSrc', _this.imgSrc)
console.log('转换', this.dataURLtoFile(_this.imgSrc, 'file'))
},
clearImgSrc() {
this.imgSrc = ''
},
//base64转文件
dataURLtoFile(urlData, fileName) {
let arr = urlData.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bytes = atob(arr[1]); // 解码base64
let n = bytes.length
let ia = new Uint8Array(n);
while (n--) {
ia[n] = bytes.charCodeAt(n);
}
console.log('转换成功');
return new File([ia], fileName, {
type: mime });
},
base64ToBlob(base64) {
const byteCharacters = atob(base64);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
const slice = byteCharacters.slice(offset, offset + 512);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {
type: 'image/jpeg' }); // 根据实际的 Base64 字符串类型设置对应的 MIME 类型
return blob;
},
blobToUrl(blob) {
const url = URL.createObjectURL(blob);
return url;
}
}
}
</script>
<style lang="less">
.body {
display: flex;
flex-direction: column;
justify-content: center;
// align-items: center;
width: 100%;
height: 100%;
}
.video {
width: 500px;
height: 300px;
}
.canvas {
width: 500px;
height: 100%;
}
.btn {
width: 100px;
height: 20px;
}
</style>
参考:
[【前端vue——系列6】vue连接摄像头并实现摄像头暂停,计时,截图到本地等功能](https://blog.csdn.net/yangyaning123/article/details/118071503)