最近的几个需求都涉及到了扫码和拍照之类的功能,扫码用的是插件 html5-qrcode,拍照就自己写了一下,没多少行代码。
用的是 WEBRTC 的 api 然后把视频流画到 canvas 里面,再保存成图片,直接上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
</style>
</head>
<body>
<div>
<video id="cameraVideo" autoplay="true"></video>
</div>
<button onclick="takePhoto()">开始</button>
<button onclick="snapPhoto()">拍照</button>
<button onclick="closePhoto()">关闭</button>
<script>
let mediaStream = null;
var track = null;
function takePhoto () {
navigator.mediaDevices
.getUserMedia({
video: true,
})
.then(function (stream) {
let video = document.getElementById('cameraVideo');
video.srcObject = stream;
mediaStream = stream;
track = stream.getTracks()[0];
})
.catch(function (err) {
console.log(err);
});
}
function snapPhoto () {
var canvas = document.createElement('canvas');
let videoEl = document.getElementById('cameraVideo');
let videoH = videoEl.videoHeight;
let videoW = videoEl.videoWidth;
canvas.width = videoW;
canvas.height = videoH;
var video = document.getElementById('cameraVideo');
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, videoW, videoH);
canvas.toBlob(function(blob){
var file = new File([blob], Date.now().toString() + '.png', {
type: "image/png",
lastModified: Date.now()
});
download(Date.now().toString() + '.png', file);
});
}
function closePhoto () {
if (mediaStream !== null) {
if (mediaStream.stop) {
mediaStream.stop();
}
};
if (track !== null) {
if (track.stop) {
track.stop();
}
};
var video = document.getElementById('cameraVideo');
video.src = "";
}
const download = (fileName, blob) => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = fileName;
link.click();
link.remove();
URL.revokeObjectURL(link.href);
};
</script>
</body>
</html>
一开始用的是简写 navigator.getUserMedia,结果 ios 居然不行,后面 navigator.mediaDevices.getUserMedia 就可以了,也是神奇。
还有要注意,如果不想视频拍照的时候全屏(移动端),给 video 加上属性 webkit-playsinline playsinline x5-video-player-type="h5-page"
另外视频可以设置前置和后置摄像头,分辨率,video 是对象,user 是前置,environment 是后置,width/height 是分辨率,移动端可能还反着来,就是这个分辨率一直不知道是怎么可以设置全,因为拍照的框是固定的,所以很难设置的刚好,如果只是播放视频还好,通过判断分辨率然后用 css 控制 object-fit,是 cover 还是 contain,如果是 fill 就有肯能变形。
{
facingMode: 'environment',
width: { ideal: 720 },
height: { ideal: 1280 },
}
要是有人对这个分辨率有很好的理解,求指教,毕竟现在的项目有可能要解决满框。
也可以到 GitHub 下载对应的代码:https://github.com/wade3po/demoCode