js 如何调用摄像头拍照
问题:
//web rtc 调用摄像头(兼容性写法(谷歌、火狐、ie))
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
//调用成功会回调返回一个stream流 video:true 表示采集视频,audio:true 表示采集声音,反之就都不采集。
navigator.getUserMedia({video:true,audio:false},function(stream){
//将采集到的视频信息显示在video标签中
video.srcObject = stream;
},console.log)
原文链接:https://blog.csdn.net/xiehuanbin/article/details/131512316
navigator.mediaDevices is undefined 会报错,得知因为加密的安全性问题:
目前查到的解决办法如下:
1. 使用https协议,需要域名
2. 手动修改本机浏览器配置【chrome://flags/ 】,多个地址用【,】隔开,修改后底部会提示重启浏览器
3.localhost 域
本地文件以file 形式打开时
其他情况下你在浏览器里log这个API都是返回undefined.
如果想要 HTTP 环境下也能使用和调试 MediaDevices.getUserMedia(),通过开启 Chrome 的相应参数,也是可以实现的。
传递相应参数来启动 Chrome,-unsafely-treat-insecure-origin-as-secure="http://example.com"
1.第一种
业务逻辑需要人脸验证,需要通过调用摄像头获取人脸来调用接口做对比,所以学习了一下js关于调用摄像头拍照。主要通过video调用摄像头和canvas截取画面。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <video width="500" height="500" autoplay class="video"></video> <canvas width="500" height="500"></canvas> <button onclick="openx()">调用摄像头</button> <button onclick="pho()">拍照</button> <button onclick="exit()">关闭摄像头</button> </body> </html> <script> let video = document.querySelector('.video'); let canvas = document.querySelector('canvas'); function openx() { let constraints = { video: { //这里是摄像头的信息 height: 500, width: 500 }, // audio: true, //是否开启麦克风 } let isok = navigator.mediaDevices.getUserMedia(constraints); //这里主要是用于请求用户打开摄像头的权限 isok.then(res => { //可以看出是使用promise封装的 那么我们就可以使用then和catch video.srcObject = res; //用户允许时 将摄像头对象的画面转移到video上面 video.play(); //打开video的画面 }).catch((err) => { console.log(err) //拒绝时打印错误信息 }) } function pho() { canvas.getContext("2d").drawImage(video, 0, 0, 300, 300); //第一个参数为要截取的dom对象,第二个和第三个为xy轴的偏移值 3-4为截取图像的大小 } function exit() { video.srcObject.getTracks()[0].stop(); //这里如果打开了麦克风、getTracks是一个数组,我们同样需要获取下标[1]来关闭摄像头 打开麦克风[0]就是麦克风 } </script>
上述代码看起来并不多,包含了打开-截取图像-关闭 摄像头的功能,足以满足功能需求。
https://blog.csdn.net/m0_72436362/article/details/128321359
外接摄像头没错,笔记本的摄像头报错,放form标签里有问题,不显示
$("img").css("src", canvas.toDataURL("image/png"));
2.第二种,笔记本的摄像头打开没报错
<!DOCTYPE html> <html lang="ZH-CN"> <head> <meta charset="utf-8"> <title>web RTC 测试</title> <style> .booth { width:400px; background:#ccc; border: 10px solid #ddd; margin: 0 auto; } </style> </head> <body> <article> <section> <video id="video"></video> </section> <section> <audio id="audio"></audio> </section> <button id="btn">拍照</button> <section> <canvas id="canvas"></canvas> </section> <section><img src="" alt="" id="img"></section> </article> <article> <header>相关知识</header> <h2>获取用户媒体:</h2> <p> <code>navigator.mediaDevices.getUserMedia({video: true, audio: true}) // 异步操作</code> </p> <h2>枚举媒体数:video,audio输入输出设备</h2> <p><code>navigator.mediaDevices.enumerateDevices() // 异步操作</code></p> </article> <script> let convas = document.querySelector("#canvas"); // let video = document.querySelector("#video"); let audio = document.querySelector("audio"); let img = document.querySelector("#img"); let btn = document.querySelector("button"); let context = canvas.getContext('2d'); let width = 320; //视频和canvas的宽度 let height = 0; // let streaming = false; // 是否开始捕获媒体 // 获取用户媒体,包含视频和音频 navigator.mediaDevices.getUserMedia({video: true, audio: true}) .then(stream => { video.srcObject = stream; // 将捕获的视频流传递给video 放弃window.URL.createObjectURL(stream)的使用 video.play(); // 播放视频 audio.srcObject = stream; audio.play(); }); function tackcapture() { // 需要判断媒体流是否就绪 if(streaming){ context.drawImage(video, 0, 0, 350, 200);// 将视频画面捕捉后绘制到canvas里面 img.src = canvas.toDataURL('image/png');// 将canvas的数据传送到img里 } } btn.addEventListener('click',tackcapture,false); // 按钮点击事件 // 监听视频流就位事件,即视频可以播放了 video.addEventListener('canplay', function(ev){ if (!streaming) { height = video.videoHeight / (video.videoWidth/width); video.setAttribute('width', width); video.setAttribute('height', height); canvas.setAttribute('width', width); canvas.setAttribute('height', height); streaming = true; } }, false); </script> </body> </html>
- 有些浏览器可能不支持此功能
- 必须通过服务器打开页面,通过files://打开无效
- 如果通过远程服务器打开则必须是https协议, http协议也无法使用
转:https://www.cnblogs.com/scarecrowlxb/p/6804747.html
3.第三种
<script src="https://cdn.bootcss.com/zepto/1.2.0/zepto.min.js"></script>
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>使用js调用设备摄像头并实现拍照</title> <script src="https://cdn.bootcss.com/zepto/1.2.0/zepto.min.js"></script> <style type="text/css"> * { margin: 0; padding: 0; } video { width: 200px; } button { width: 100px; height: 60px; } </style> </head> <body> <div class="box"> <video src=""></video> <button class="shot">拍照</button> <canvas id="canvas"></canvas> <img src="" /> </div> <a href="https://codesandbox.io/s/811w1z2xwj">点击编辑</a> <script type="text/javascript"> // 视频大小 var constraints = { audio: true, video: { width: 200, height: 250 } }; // 开启视频 navigator.mediaDevices .getUserMedia(constraints) .then(function(mediaStream) { console.log("getUserMedia:", mediaStream); var video = document.querySelector("video"); video.srcObject = mediaStream; video.onloadedmetadata = function(e) { video.play(); }; // 使用canvas进行拍照 var canvas = document.getElementById("canvas"); $("button").on("click", function() { canvas.getContext("2d").drawImage(video, 0, 0, 200, 250); $("img").css("src", canvas.toDataURL("image/png")); }); }) .catch(function(err) { console.log(err.name + ": " + err.message); }); </script> </body> </html>
转:http://www.taodudu.cc/news/show-6195164.html?action=onClick
https://811w1z2xwj.codesandbox.io/
4.第四种
<!doctype html> <html lang="en"> <head> <title>js调用摄像头拍照上传图片</title> <meta charset="utf-8"> </head> <body> <button onclick="openMedia()">开启摄像头</button> <video id="video" width="500px" height="500px" autoplay="autoplay"></video> <canvas id="canvas" width="500px" height="500px"></canvas> <button onclick="takePhoto()">拍照</button> <img id="imgTag" src="" alt="imgTag"> <button onclick="closeMedia()">关闭摄像头</button> <script> let mediaStreamTrack = null; // 视频对象(全局) function openMedia() { let constraints = { video: { width: 500, height: 500 }, audio: true }; //获得video摄像头 let video = document.getElementById('video'); let promise = navigator.mediaDevices.getUserMedia(constraints); promise.then((mediaStream) => { mediaStreamTrack = typeof mediaStream.stop === 'function' ? mediaStream : mediaStream.getTracks()[1]; video.srcObject = mediaStream; video.play(); }); } // 拍照 function takePhoto() { //获得Canvas对象 let video = document.getElementById('video'); let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, 500, 500); // toDataURL --- 可传入'image/png'---默认, 'image/jpeg' let img = document.getElementById('canvas').toDataURL(); // 这里的img就是得到的图片 console.log('img-----', img); document.getElementById('imgTag').src = img; } // 关闭摄像头 function closeMedia() { mediaStreamTrack.stop(); } </script> </body>
5. 调用用户的摄像头
调用电脑摄像头功能,经过在网上查找资料有以下三种方案实现。
- 通过浏览器API来getUserMedia来实现调用用户的摄像头,但有两点限制:部署到生产服务的时候要使用htts协议访问该项目,第二点限制就是第一次获取摄像头时要点击允许弹窗。
- 通过web端发送websocket请求给客户端,然后客户端调用摄像头应用程序,但每次初始打开摄像头应用时都有个初始化2~3秒左右,用户体验不免友好。
- 通过客户端获取摄像头的每一帧数据,并通过websocket返回给web端,具体步骤下面有代码讲解。
getUserMedia方式实现代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>调用摄像头录像</title> </head> <body> <video id="video" width="640" height="480" autoplay></video> <button id="startRecord">开始录制</button> <button id="stopRecord">停止录制</button> <script> var video = document.querySelector('#video'); var startRecord = document.querySelector('#startRecord'); var stopRecord = document.querySelector('#stopRecord'); var mediaRecorder; var chunks = []; navigator.mediaDevices.getUserMedia({ audio: false, video: true }).then(function (stream) { video.srcObject = stream; mediaRecorder = new MediaRecorder(stream); mediaRecorder.ondataavailable = function (e) { chunks.push(e.data); }; mediaRecorder.onstop = function (e) { var blob = new Blob(chunks, { type: 'video/mp4' }); chunks = []; var videoURL = window.URL.createObjectURL(blob); video.src = videoURL; }; }); startRecord.onclick = function () { mediaRecorder.start(); }; stopRecord.onclick = function () { mediaRecorder.stop(); }; </script> </body> </html>
客户端返回视频流方式实现代码
vue前端代码
前端接收到H264视频流,需要用JMuxer来转码才能在video标签里播放,需要执行npm install JMuxer来安装这个库。详细代码如下:
<template> <video id="player" :controls="false" :muted="false" :autoplay="true"></video> </template> <script setup> import JMuxer from 'jmuxer'; import { onMounted, onBeforeUnmount} from 'vue'; var ws = null; var jmuxer = null; const list = reactive([]); const isDisable = ref(false); onMounted(() => { jmuxer = new JMuxer({ node: 'player', // 可用值是:video、audio mode: 'video', // 最大延迟时间(毫秒), 默认为值是500毫秒 maxDelay: 100, // 缓冲区刷新时间,默认为值是500毫秒 flushingTime: 0, // 是否会自动清除播放的媒体缓冲区。默认为true clearBuffer: true, // 可选值。视频的帧率,如果它是已知的或固定值。如果所提供的媒体数据中没有块持续时间,它将用于查找帧持续时间。 fps: 30, // 将从MP4轨道数据读取FPS,而不是使用(以上)FPS值。默认为false。 readFpsFromTrack: false, // 将在浏览器控制台打印调试日志。默认为false debug: false, // 遇到任何丢失的视频帧将会被触发 onMissingVideoFrames: function (data) { console.log('丢失的视频帧'); }, onError: function (data) { if (/Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor)) { jmuxer.reset(); } } }); ws = new WebSocket('ws://127.0.0.1:12797'); ws.binaryType = 'arraybuffer'; ws.onmessage = function (event) { jmuxer.feed({ video: new Uint8Array(event.data) }); }; ws.onopen = function () { console.log('已连接'); ws.send('{"interfaceId":"100002","command":"1"}'); }; ws.onerror = function (err) { console.log('出错--Socket Error', err); }; ws.onclose = function () { console.log('断开'); }; }); // 实现拍照功能 const toScan = () => { const videoEl = document.getElementById('player'); const canvas = document.createElement('canvas'); canvas.width = videoEl.videoWidth; canvas.height = videoEl.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(videoEl, 0, 0, videoEl.videoWidth, videoEl.videoHeight); console.log(canvas.toDataURL('image/png')); }; onBeforeUnmount(() => { console.info('离开页面,关闭高拍仪'); ws.close(); jmuxer.destroy(); }); </script>
链接:https://www.jianshu.com/p/e929fe5f8c35
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>html5拍照</title> <style type="text/css"> body{overflow-y:auto;overflow-x:auto;margin:0;} #cameraBtn,#cameraDiv{padding:5px;} .big-btn-blue{ display:inline-block; min-width:80px; height:30px; margin:0 5px; padding:0 15px; vertical-align:top; line-height:30px; text-align:center; font-size:14px; font-family: "微软雅黑"; color:#fff; border-radius:2px; box-sizing:border-box; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; cursor:pointer; } .big-btn-blue{ -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; transition: all 0.3s ease;}/*动画*/ .big-btn-blue{ border:1px solid #3194dd; background-color:#3194dd;}/*纯蓝色*/ </style> <script type="text/javascript"> //访问用户媒体设备的兼容方法 function getUserMedia(constrains,success,error){ if(navigator.mediaDevices.getUserMedia){ //最新标准API navigator.mediaDevices.getUserMedia(constrains).then(success).catch(error); } else if (navigator.webkitGetUserMedia){ //webkit内核浏览器 navigator.webkitGetUserMedia(constrains).then(success).catch(error); } else if (navigator.mozGetUserMedia){ //Firefox浏览器 navagator.mozGetUserMedia(constrains).then(success).catch(error); } else if (navigator.getUserMedia){ //旧版API navigator.getUserMedia(constrains).then(success).catch(error); }else{ alert("不支持的浏览器"); } } //成功的回调函数 function success(stream){ //兼容webkit内核浏览器 var CompatibleURL = window.URL || window.webkitURL; //将视频流设置为video元素的源 try { video.srcObject = stream; } catch (e) { video.src = CompatibleURL.createObjectURL(stream); } //播放视频 video.play(); } //异常的回调函数 function error(error){ alert("访问用户媒体设备失败,"+error.name+""+error.message); } /** * 获取当前静态页面的参数 * 返回值和使用方法类似java request的getparamater * 不同: 当取得的为数组(length>1)时调用toString()返回(逗号分隔每个元素) * @param {Object} name * @return {TypeName} */ function getPara(name,search){ var p = getParas(name,search); if(p.length==0){ return null; }else if(p.length==1){ return p[0]; }else{ return p.toString(); } } /**获取当前静态页面的参数 * 返回值和使用方法类似java request的getparamaterValues * @param {Object} name 要取出的参数名,可以在参数字符串中重复出现 * @param {Object} search 手工指定要解析的参数字符串,默认为当前页面后跟的参数 * @return {TypeName} */ function getParas(name,search){ if(!search){ search = window.location.search.substr(1);//1.html?a=1&b=2 } var para = []; var pairs = search.split("&");//a=1&b=2&b=2&c=2&b=2 for(var i=0;i<pairs.length;i=i+1){ var sign = pairs[i].indexOf("="); if(sign == -1){//如果没有找到=号,那么就跳过,跳到下一个字符串(下一个循环)。 continue; } var aKey = pairs[i].substring(0,sign); if(aKey==name){ para.push(unescape(pairs[i].substring(sign+1))); } } return para; } //开启摄像头 function captureInit(){ if ((navigator.mediaDevices!=undefined && navigator.mediaDevices.getUserMedia!=undefined) || navigator.getUserMedia!=undefined || navigator.webkitGetUserMedia!=undefined || navigator.mozGetUserMedia!=undefined){ document.getElementById("help").style.display="none"; //调用用户媒体设备,访问摄像头,改为触发事件 getUserMedia({video:{width:imgWidth,height:imgHeight}},success,error); if(captureState==0){ captureState=1;//标记此按钮已点击 } } else { captureState=0;//异常标识按钮没点 alert("你的浏览器不支持访问用户媒体设备或访问地址不是https开头,您可以点击右侧下载解决方案"); document.getElementById("help").style.display="inline-block"; } } //注册拍照按钮的单击事件 function capture(){ //绘制画面 if(captureState==0){ alert("请先开启摄像头"); return; } context.drawImage(video,0,0,imgWidth,imgHeight);//后面两个长宽 //canvas.toDataURL("image/png");//即可得到base64编码 captureState=2; } //确认按钮返回给父页面的函数 function queren(){ if(captureState!=2){ alert("请先开启摄像头并拍照"); return; } var base64=canvas.toDataURL("image/jpeg"); var pics={}; pics.filetypeid=filetypeid;//返回给前端 pics.base64=base64; if(window.opener){ window.opener[cb](pics);// /FileUploadTmp/为项目临时文件夹相对路径 window.close(); }else if(window.parent){ window.parent[cb](pics); window.parent.$("#dialog_ifr_html").dialog("close");//close会导致flash未执行完就销毁,页面JS报错 }else{ window.close(); } } </script> </head> <body> <div id="cameraBtn"> <input type="button" id="init" onclick="captureInit()" value="开启摄像头"/> <input type="button" id="capture" onclick="capture()" value="拍照"/> <input type="button" id="queren" onclick="queren()" value="确定"/> <span id="help" style="display:none;"><a href="/static/ad/down/camera.doc">点此下载无法拍照的解决方案</a></span> </div> <div id="cameraDiv"> <!-- 视频流 --> <video id="video" autoplay style="width: 300px;height: 200px"></video> <!--描绘video截图--> <canvas id="canvas" width="300" height="200"></canvas> </div> <script type="text/javascript"> var cb=getPara("cb")||"setImg"; var filetypeid=getPara("filetypeid")||"filetypeid";//附件类型id var video=document.getElementById("video"); var canvas=document.getElementById("canvas"); var context=canvas.getContext("2d"); var imgWidth=getPara("width")||"300";//这个值div的宽一致 var imgHeight=getPara("height")||"200";//这个值div的高一致 var captureState=0;//未开启,1已开启,2已拍照,为2才可点击确认按钮 var style = getPara("style")||"big-btn-blue"; video.style.width=imgWidth; video.style.height=imgHeight; var st = style.split(","); document.getElementById("init").className=st[0]; document.getElementById("capture").className=st[1]||st[0]; document.getElementById("queren").className=st[2]||st[0]; document.getElementById("help").className=st[3]||st[0]; </script> </body> </html>