h5 利用getUserMedia 实现 只调用摄像头
h5开发中调用摄像头,通常会根据不同的手机显示不同的状态,往往会可以选择相册中的图片,常规用法:-input type=file capture为了让用户必须拍照上传 利用 getUserMedia实现调用摄像头以 vue 为例<template><div><videoid="videoCamera"height="500"style="height: 500px"p
·
h5开发中调用摄像头,通常会根据不同的手机显示不同的状态,往往会可以选择相册中的图片,
常规用法:
-input type=file capture
为了让用户必须拍照上传 利用 getUserMedia 实现调用摄像头
以 vue 为例
<template>
<div class="camera_box" v-if="show">
<div>
<div class="video_box">
<video
id="videoCamera"
style="width: 100%; height: 500px"
playsinline
autoPlay
></video>
</div>
<!-- <van-image :src="imgSrc" /> -->
<canvas id="canvasCamera" v-show="imgShow" />
<div class="option-btn">
<Button type="info" @click="cancle">取消</Button>
<Button type="info" @click="drawImage">拍照</Button>
<Button type="info" @click="changeCamera">切换摄像头</Button>
</div>
</div>
</div>
</template>
<script>
import { Image, Button, Popup } from "vant";
import Compressor from "compressorjs";
import { lrzUploadImage } from "../../services/upload";
import { IMAGE_LIMIT } from "../../utils/config";
export default {
props: {
showCamera: {
type: Boolean,
default: false,
},
ImgFile: {
type: Function,
default: null
}
},
components: {
Button,
[Image.name]: Image,
[Popup.name]: Popup,
},
watch: {
showCamera(newVal) {
this.show = newVal
if (newVal) {
this.getCompetence();
} else {
this.stopNavigator();
}
},
show(newVal) {
this.$emit("update:showCamera", newVal);
}
},
data() {
return {
url: "", // 上传的图片的地址
// visible: false, //弹窗
videoWidth: 0, // 绘画布的宽高
videoHeight: 0,
os: false, //控制摄像头开关
thisCancas: null,
thisContext: null,
thisVideo: null,
imgSrc: undefined,
imgFile: null,
imgShow: false,
facingMode: "environment", // environment user
show: false
};
},
methods: {
changeCamera() {
this.stopNavigator();
this.facingMode =
this.facingMode === "environment" ? "user" : "environment";
this.getCompetence();
},
cancle() {
this.show = false
this.$emit("ImgFile", true,'')
},
// 调用摄像头权限
getCompetence() {
//必须在model中render后才可获取到dom节点,直接获取无法获取到model中的dom节点
this.$nextTick(() => {
const _this = this;
this.os = false; //切换成关闭摄像头
// 获取画布节点
this.thisCancas = document.getElementById("canvasCamera");
// 为画布指定绘画为2d类型
this.thisContext = this.thisCancas.getContext("2d");
//获取video节点
this.thisVideo = document.getElementById("videoCamera");
// 获取img节点
this.thisImg = document.getElementById("imgCamera");
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
// navigator.menavigatordiaDevices = {};
navigator.mediaDevices = {};
}
console.log("9999", navigator.mediaDevices.getUserMedia);
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
console.log(
"navigator",
navigator.webkitGetUserMedia,
navigator.mozGetUserMedia,
navigator.getUserMedia
);
// 首先获取现存的getUserMedia(如果存在)
let getUserMedia =
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.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);
});
};
}
const constraints = {
audio: false,
video: {
width: window.screen.width,
height: 500,
// transform: "scaleX(-1)",
facingMode: this.facingMode,
},
};
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.videoWidth = 500;
_this.videoHeight = window.screen.width;
_this.thisCancas.width = 500;
_this.thisCancas.height = window.screen.width;
_this.thisVideo.onloadedmetadata = function (e) {
console.log("e", e);
// 动态获取视频流宽、高
//_this.videoWidth = _this.thisVideo.videoWidth;
//_this.videoHeight = _this.thisVideo.videoHeight;
//_this.thisCancas.width = _this.thisVideo.videoWidth;
//_this.thisCancas.height =_this.thisVideo.videoHeight
_this.thisVideo.play();
};
})
.catch((err) => {
console.log("err", err);
});
});
},
//进行绘制图片
drawImage() {
// 点击,canvas画图
this.thisContext.drawImage(
this.thisVideo,
0,
0,
this.videoWidth,
this.videoHeight
);
// 获取图片base64链接
this.imgSrc = this.thisCancas.toDataURL("image/png");
console.log(this.imgSrc, 8888)
this.onSubmit()
},
//清空画布
clearCanvas(id) {
let c = document.getElementById(id);
let cxt = c.getContext("2d");
cxt.clearRect(0, 0, c.width, c.height);
},
//重置画布
resetCanvas() {
this.imgSrc = "";
this.clearCanvas("canvasCamera");
},
//关闭摄像头
stopNavigator() {
if (this.thisVideo && this.thisVideo !== null) {
this.thisVideo.srcObject.getTracks()?.map((item) => {
item.stop();
});
}
},
/*调用摄像头拍照结束*/
/*完成拍照并对其照片进行上传*/
onSubmit() {
this.imgFile = this.dataURLtoFile(this.imgSrc, new Date() + ".png");
this.stopNavigator();
this.show = false
this.beforeRead(this.imgFile).then(res => {
console.log('压缩结果', res)
lrzUploadImage(res, (results, url) => {
console.log('上传结果', results, url)
this.$emit("ImgFile", results, url)
});
})
},
dataURLtoFile(dataurl, filename) {
let arr = dataurl.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
},
// 图片修正
beforeRead(file, detail, i = 1) {
console.log("beforeRead", file);
// loading
// this.$emit("beforeRead", this.echoField);
return new Promise((resolve) => {
// compressorjs 默认开启 checkOrientation 选项
let quality = 1;
let len = IMAGE_LIMIT * (1024 * 1024);
if (file.size > len) {
quality = 0.5 ** i;
}
// 会将图片修正为正确方向
new Compressor(file, {
checkOrientation: true,
quality: quality,
success: async (result) => {
let nowFile = new File([result], result.name, {
type: file.type,
});
if (i >= 2) {
console.log("2次压缩结束");
resolve(result);
} else if (result.size > len) {
resolve(this.beforeRead(nowFile, detail, Number(i) + 1));
} else {
resolve(result);
}
},
error(err) {
console.log("beforeRead", err);
},
});
});
},
},
mounted() {},
};
</script>
<style lang="less" scoped>
.camera_box {
width: 100%;
background: black;
height: 100vh;
z-index: 999;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.canvas {
display: none;
}
.option-btn {
display: flex;
flex-direction: row;
justify-content: space-around;
}
.video_box {
width: 100%;
height: 500px;
#videoCamera {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
}
</style>
动态获取vedio宽高 只能在 onloadedmetadata函数内
getUserMedia 只能在https环境下正确应用, ios只有safari浏览器支持
本地开发可以在本地搭建https环境进行调试
更多推荐
已为社区贡献2条内容
所有评论(0)