浏览器调起摄像头(jquery+layui)

/*
实例化camvas配置参数
config = {
                video:{width:Number(scale*4),height:Number(scale*3)},//视频比例4:3
                canvasId:'canvas',//画布canvas节点ID
                videoId:'v',//video节点ID
                imgType:'png',//图片类型,/png|jpeg|bmp|gif/
                quality:'1' //图片质量0-1之间
            }
*/

window.URL = window.URL || window.webkitURL||window.mozURL || window.msURL;

navigator.getUserMedia  = navigator.getUserMedia || 
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia || 
                          navigator.msGetUserMedia
                          
window.requestAnimationFrame = window.requestAnimationFrame ||
                               window.webkitRequestAnimationFrame ||
                               window.mozRequestAnimationFrame ||
                               window.msRequestAnimationFrame ||
                               window.oRequestAnimationFrame

// Integrate navigator.getUserMedia & navigator.mediaDevices.getUserMedia
function getUserMedia (constraints, successCallback, errorCallback) {
  if (!constraints || !successCallback || !errorCallback) {return}
  
  if (navigator.mediaDevices) {
    navigator.mediaDevices.getUserMedia(constraints).then(successCallback, errorCallback)
  } else {
    navigator.getUserMedia(constraints, successCallback, errorCallback)
  }
}

//获取摄像头设备源
function getMediaStream() {
  var exArray = []; //存储设备源ID
  MediaStreamTrack.getSources(function (sourceInfos) {
    for (var i = 0; i != sourceInfos.length; ++i) {
      var sourceInfo = sourceInfos[i];
      //这里会遍历audio,video,所以要加以区分
      if (sourceInfo.kind === 'video') {
        exArray.push(sourceInfo.id);
      }
    }
  });
  return exArray;
}

//用户手机端使用后置摄像头
function getMediaConfig() {
  if (navigator.getUserMedia) {
    if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)){
      //手机端
      return {
        'video':
            {'optional': [
                {'sourceId': getMediaStream()[1] //0为前置摄像头,1为后置
                }]
            },
        'audio':false
      }
    }else{
      return {'video':true,'audio':false}
    }
  }
  else {
    alert('Native device media streaming (getUserMedia) not supported in this browser.');
  }
}
                               
// The function takes a canvas context and a `drawFunc` function.
// `drawFunc` receives two parameters, the video and the time since
// the last time it was called.
function camvas(config) {
  var self = this
  self.convas = document.getElementById(config.canvasId)
  self.ctx = self.convas.getContext('2d');
  self.config = config
  self.isStop = false;

  //video节点ID
  self.video = document.getElementById(self.config.videoId)

  //video 显示尺寸
  self.video.setAttribute('width', this.config.video.width)
  self.video.setAttribute('height', this.config.video.height)

  //视频流控制句柄
  var mediaStreamTrack;
  //对外开启视频方法
  this.startCamera = function () {
    // The callback happens when we are starting to stream the video.
    getUserMedia(getMediaConfig(), function(stream) {
      // Yay, now our webcam input is treated as a normal video and
      // we can start having fun
      try {
        mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks().length==1 ?
            stream.getTracks()[0]:stream.getTracks()[1];
        if(self.video.mozSrcObject !== undefined){
          //Firefox中,video.mozSrcObject最初为null,而不是未定义的,我们可以靠这个来检测Firefox的支持
          self.video.mozSrcObject = stream;
        }else{
          self.video.srcObject = stream;
        }
      } catch (error) {
        self.video.src = window.URL && window.URL.createObjectURL(stream) || stream;
      }
      self.isStop = false;
      self.video.play();
      // Let's start drawing the canvas!
      // self.recordVideo()
    }, function(err){
      alert(err);
    })
  }

  //录像方法
  this.recordVideo = function() {
    var self = this
    var last = Date.now()
    var loop = function() {
      // For some effects, you might want to know how much time is passed
      // since the last frame; that's why we pass along a Delta time `dt`
      // variable (expressed in milliseconds)
      var dt = Date.now() - last
      self.draw(self.video, dt)
      last = Date.now()
      requestAnimationFrame(loop) 
    }
    requestAnimationFrame(loop) 
  }
  //停止视频
  this.stop = function () {
    self.ctx.clearRect(0, 0, self.config.video.width,self.config.video.height);
    mediaStreamTrack && mediaStreamTrack.stop();
    self.isStop = true;
  }
  //拍照,base64/image/png
  this.drawImage=function (callback) {
    if(!self.isStop){
      self.ctx.drawImage(self.video,0,0,self.config.video.width,self.config.video.height);
      var base64URL = self.convas.toDataURL('image/'+self.config.imgType,self.config.quality);
      callback&&callback(base64URL);
    }
  }

  //录像数据帧
  this.draw = function(video, dt) {
    self.ctx.drawImage(video, 0, 0)
  }
}
<style>
    .camera-control {
        position: absolute;
        z-index: 10;
        left: 0;
        right: 0;
        bottom: 0;
        text-align: center;
        padding: 10px;
        min-height: 40px;
    }
    .camera-btn {
        cursor: pointer;
        border: none;
        color: #fff;
        padding: 8px 12px;
        font-size: 14px;
        outline: none;
        background-color: rgba(255, 255, 255, 0.3);
        transition: all 0.3s;
        box-shadow: 0 2px 0 0 rgba(45, 140, 240, 0.8);
        margin: 0 5px;
    }
    .camera-canvas-group {
        display: flex;
        left: 0;
        right: 0;
        height: 80px;
    }
    .camera-canvas-item {
        opacity: 0.8;
        flex: 1;
        max-width: 100px;
        height: 100%;
        overflow: hidden;
        clear: both;
        margin-bottom: -1px;
        transition: all 0.2s;
        position: relative;
    }
    .camera-canvas-item img {
        float: left;
        width: 100%;
        background-color: #000;
        border: 1px solid #fff;
    }

    .camera-canvas-item:hover {
        position: relative;
        opacity: 1;
        box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.8);
    }

    .camera-canvas-item:hover {}
    .camera-btn:hover {
        background-color: rgba(45, 140, 240, 0.6);
        box-shadow: 0 2px 0 0 rgba(45, 140, 240, 1);
    }

    .camera-btn:active {
        background-color: rgba(45, 140, 240, 0.2);
    }
    .canvas-item-del{
        position: absolute;
        right: 0px;
        font-size: 22px;
        color: #ef475d;
        cursor: pointer;
    }
    .camera-show-pc{
        background-color:#FFFFFF;margin:0px auto;
    }
</style>
<div class="layui-fluid layui-anim" id="camera" lay-title="摄像头测试">
    <div class="layui-row">
        <div class="layui-card" style="background-color:#1E8AE8;margin: auto auto;">
            <div class="layui-card-body">
                <div class="layui-row camera-show-pc">
                    <h1 style="padding: 23px 0px;;font-size: 2.4rem;color: #1E8AE8;font-weight: bold;text-align: center">camera</h1>
                    <div class="bag_display_flex" style="justify-content: center;">
                        <div style="position: relative;">
                            <video id="v" style="background-color: #000000"></video>
                            <div class="camera-control">
                                <button type="button" id="stop" class="layui-icon layui-icon-stop camera-btn">关闭</button>
                                <button type="button" id="start" class="layui-icon layui-icon-triangle-r camera-btn">开始</button>
                                <button type="button" id="snap" class="layui-icon layui-icon-camera-fill camera-btn">拍照</button>
                                <button type="button" id="save" class="layui-icon layui-icon-save camera-btn">保存</button>
                                <button type="button" id="clear" class="layui-icon layui-icon-fonts-clear camera-btn">清空</button>
                            </div>
                        </div>
                        <div>
                            <canvas id="canvas" style="margin-left: 2px;background-color: #000000"></canvas>
                        </div>
                    </div>
                    <div class="layui-row" style="position: relative">
                        <div class="camera-canvas-group"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript" src="js/camera/camvas.js"></script>
<script data-th-inline="javascript" type="text/javascript">
    layui.use(['jquery'], function () {
        var $ = layui.jquery,
            $view = $('#camera'),
            config={},
            myCamvas;
        init();
        onClick();


        function init() {
            let scale = 120;//宽高比例倍数
            config = {
                video:{width:Number(scale*4),height:Number(scale*3)},//4:3
                canvasId:'canvas',
                videoId:'v',
                imgType:'png',
                quality:'1' //图片质量0-1之间
            };
            $('.camera-show-pc').css('width',config.video.width*2+20);
            $view.find('#canvas').attr('width',config.video.width);
            $view.find('#canvas').attr('height',config.video.height);
            //拍照实例化
            myCamvas = new camvas(config);
            myCamvas.startCamera();
            $view.find('#start').hide();
        }
        function onClick() {
            //停止拍照
            $view.find('#stop').click(function () {
                myCamvas.stop()
                $view.find('#stop').hide()
                $view.find('#start').show()
            })
            //启动摄像头
            $view.find('#start').click(function () {
                myCamvas.startCamera();
                $view.find('#stop').show()
                $view.find('#start').hide()
            })
            //拍照
            $view.find('#snap').click(function () {
                myCamvas.drawImage(function drawImage(base64URL) {
                    let xsCamera = $('<div></div>').addClass('camera-canvas-item');
                    xsCamera.append($('<img>').attr('src',base64URL)).append($('<span></span>').addClass('layui-icon layui-icon-close-circle-fill canvas-item-del'));
                    $('.camera-canvas-group').prepend(xsCamera);
                });
            })
            //清空
            $view.find('#clear').click(function () {
                $view.find('.camera-canvas-group').empty()
            })

            //append方式添加节点直接click无效,点击显示大图
            $view.find('.camera-canvas-group').on('click','.camera-canvas-item img',function () {
                myCamvas.ctx.drawImage(this,0,0,config.video.width,config.video.height)
            })
            //删除图片
            $view.find('.camera-canvas-group').on('click','.camera-canvas-item .canvas-item-del',function () {
                //删除父节点元素
                $(this).closest('.camera-canvas-item').remove()
            })
            //保存所有图片到本地
            $view.find('#save').click(function () {
                let fileName = getFileName();
                let el_a = $('<a>');
                layui.each($view.find('.camera-canvas-group .camera-canvas-item'),function (k,item) {
                    let t_filename = fileName+'_'+k+'.'+config.imgType;
                    downLoad($(this).find('img').attr('src'),t_filename,config.imgType);
                })
            })
            //空格按下拍照
            $(document).keypress(function (e) {
                e.keyCode===32&&$('#snap').trigger('click');
            })
        };
        //tode
        function getFileName() {
            let date = new Date();
            let fileName = ''+date.getFullYear()+(date.getMonth()<9?+'0':'')
                +(date.getMonth()+1) +(date.getDate()<10?+'0':'')+date.getDate()
                +date.getHours() +date.getMinutes()+(date.getSeconds()<10?'0':'')+date.getSeconds();
            return fileName;
        }
        function downLoad(dataURL,fileName,fileType) {
            var reader = new FileReader();
            reader.readAsDataURL(createFile(dataURL));
            reader.onload = function (e) {
                if ('msSaveOrOpenBlob' in navigator) { // IE,Edge
                    var base64file = e.target.result + '';
                    window.navigator.msSaveOrOpenBlob(createFile(base64file.replace('data:' + fileType + ';base64,', ''), fileType), fileName);
                } else { // chrome,firefox
                    var link = document.createElement('a');
                    link.style.display = 'none';
                    link.href = e.target.result;
                    link.setAttribute('download', fileName);
                    // document.body.appendChild(link);
                    link.click();
                    $(link).remove();
                }
            }

            /*dataURL = dataURL.replace('image/'+fileType,'image/octet-stream');
            var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
            save_link.href = dataURL;
            save_link.download = fileName;
            $(save_link).click()
            var event = document.createEvent('MouseEvents');
            event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            save_link.dispatchEvent(event);*/
        };

        // 解析 BASE64文件内容 for IE,Edge
        function createFile(urlData) {
            var arr = urlData.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = window.atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while (n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            return new Blob([u8arr], { type: mime });
        }

    });
</script>

 

posted @ 2019-09-01 17:35  fosonR  阅读(3713)  评论(0编辑  收藏  举报