浏览器调起摄像头
<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 = falsevar _this = thisthis.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.getUserMediareturn 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) {// 旧的浏览器可能没有srcObjectif ('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 = truethis.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 = imageUrlconsole.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]); // 解码base64let n = bytes.lengthlet 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)