浏览器调起摄像头
<template>
<div class="body">
这里什么都没有
<video ref="videoRef" id="videoCamera" class="video"></video>
<button @click="getCompetence" class="btn" :disabled="!videoState">
打开摄像头
</button>
<button @click="stopNavigator" class="btn" :disabled="videoState">
关闭摄像头
</button>
<button @click="captureScreenshot" class="btn">点击截图</button>
{{ imgSrc }}
<canvas ref="canvasRef" class="canvas"></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.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);
let videoDeviceId = "";
enumeratorPromise.then((results) => {
results.forEach((result) => {
if (result.kind == "videoinput") {
videoDeviceId = result.deviceId;
console.log(result.deviceId);
}
});
});
//把上面获取到的设备deviceId填入下面video的deviceId中,就可以选择要调用的摄像头了
var constraints = {
audio: false,
video: {
deviceId: videoDeviceId,
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();
this.flag = true;
},
// 截图
// captureScreenshot() {
// this.imgSrc = ""
// const video = this.$refs.videoRef;
// const canvas = this.$refs.canvasRef;
// const context = canvas.getContext('2d');
// // 将canvas的尺寸设置为视频的尺寸
// canvas.width = video.videoWidth;
// canvas.height = video.videoHeight;
// // 在canvas上绘制视频画面
// context.drawImage(video, 0, 0, canvas.width, canvas.height);
// // 将canvas内容转换为图片
// this.imgSrc = canvas.toDataURL();
// // 打印图片的DataURL
// console.log(this.imgSrc); //base64
// console.log("转换", this.dataURLtoFile(this.imgSrc, "file")); //二进制文件
// // 可以将这个image上传到服务器,保存为图片文件等等
// },
//处理一下canvas的scale和dpi,截图有点模糊,让图片变清晰些,但好像也一般
captureScreenshot() {
const video = this.$refs.videoRef;
const canvas = this.$refs.canvasRef;
const context = canvas.getContext('2d');
const scale = window.devicePixelRatio || 1;
// 将canvas的尺寸设置为视频的尺寸,并考虑DPI缩放
canvas.width = video.videoWidth * scale;
canvas.height = video.videoHeight * scale;
// 缩放canvas
context.scale(scale, scale);
// 绘制视频画面
context.drawImage(video, 0, 0, canvas.width, canvas.height);
// 将canvas内容转换为图片,指定输出的图像质量
this.imgSrc = canvas.toDataURL('image/jpeg', 1.0);
// 将canvas内容转换为图片
this.imgSrc = canvas.toDataURL();
// 打印图片的DataURL
console.log(this.imgSrc); //base64
console.log("转换", this.dataURLtoFile(this.imgSrc, "file")); //二进制文件
// 可以将这个image上传到服务器,保存为图片文件等等
},
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>