JS打开摄像头并截图上传示例


Posted in Javascript onFebruary 18, 2017

直入正题,JS打开摄像头并截图上传至后端的一个完整步骤

1. 打开摄像头主要用到getUserMedia方法,然后将获取到的媒体流置入video标签

2. 截取图片主要用到canvas绘图,使用drawImage方法将video的内容绘至canvas中

3. 将截取的内容上传至服务器,将canvas中的内容转为base64格式上传,后端(PHP)通过file_put_contents将其转为图片

JS打开摄像头并截图上传示例

要注意的是,在chrome以外的浏览器中,使用摄像头或多或少会出现一些问题,可能也是老问题了,所以以下代码主要基于chrome使用

比如在最新版FireFox中的报错,不知为啥

JS打开摄像头并截图上传示例

JS打开摄像头并截图上传示例

1. 打开摄像头

getUserMedia 有新版本和旧版本两种,建议使用新版本

旧版本位于navigator 对象下,根据浏览器不同有所不同

// 获取媒体方法(旧方法)
  navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMeddia || navigator.msGetUserMedia;
if (navigator.getMedia) {
    navigator.getMedia({
      video: true
    }, function(stream) {
      mediaStreamTrack = stream.getTracks()[0];

      video.src = (window.URL || window.webkitURL).createObjectURL(stream);
      video.play();
    }, function(err) {
      console.log(err);
    });
  }

第一个参数中指示需要使用视频(video)或音频(audio)。

第二个参数中指示调用成功后的回调,其中带一个参数(MediaStream),在旧版本中可以直接通过调用MediaStream.stop() 来关闭摄像头,不过在新版之中已废弃。需要使用MediaStream.getTracks()[index].stop() 来关闭相应的Track

第三个参数指示调用失败后的回调

新版本位于navigator.mediaDevices 对象下

if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    }).then(function(stream) {
      console.log(stream);

      mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[1];

      video.src = (window.URL || window.webkitURL).createObjectURL(stream);
      video.play();
    }).catch(function(err) {
      console.log(err);
    })
  }

与旧版类似,不过该方法返回了一个Promise对象,可以使用then和catch表示成功与失败的回调

需要注意的是,MediaStream.getTracks() 返回的Tracks数组是按第一个参数倒序排列的

比如现在定义了

{
  video: true,
  audio: true
}

想关闭摄像头,就需要调用MediaStream.getTracks()[1].stop();

同理,0对应于audio的track

使用createObjectURL 将MediaStream写入video标签,就能够存储实时的媒体流数据(也可以方便的实时查看画面)

旧版本中webkitURL 对象以不被支持,需要使用URL对象

<video width="200" height="150"></video>
  <canvas width="200" height="150"></canvas>

  <p>
    <button id="snap">截取图像</button>
    <button id="close">关闭摄像头</button>
    <button id="upload">上传图像</button>
  </p>

  <img id="uploaded" width="200" height="150" />

2. 截取图像

将内容写入即可

// 截取图像
  snap.addEventListener('click', function() {
    context.drawImage(video, 0, 0, 200, 150);
  }, false);

3. 关闭摄像头

// 关闭摄像头
  close.addEventListener('click', function() {
    mediaStreamTrack && mediaStreamTrack.stop();
  }, false);

4. 上传截取的图像

canvas.toDataURL('image/png')

// 上传截取的图像
  upload.addEventListener('click', function() {
    jQuery.post('/uploadSnap.php', {
      snapData: canvas.toDataURL('image/png')
    }).done(function(rs) {
      rs = JSON.parse(rs);

      console.log(rs);

      uploaded.src = rs.path;
    }).fail(function(err) {
      console.log(err);
    });
  }, false);

而这里的后端(PHP)则将获取的内容转换成图像文件保存

需要注意的是,要将base64的头部信息字段去掉再保存,否则似乎图像是损坏无法打开滴

<?php

  $snapData = $_POST['snapData'];
  $snapData = str_replace('data:image/png;base64,', '', $snapData);
  // $snapData = str_replace(' ', '+', $snapData);

  $img = base64_decode($snapData);

  $uploadDir = 'upload/';
  $fileName = date('YmdHis', time()) . uniqid();

  if (!(file_put_contents($uploadDir . $fileName, $img))) {
    echo json_encode(array('code' => 500, 'msg' => '文件上传失败'));
  } else {
    echo json_encode(array('code' => 200, 'msg' => '文件上传成功', 'path' => $uploadDir . $fileName));
  }

?>

完整JS代码

<script type="text/javascript" src="jquery.js"></script>
  <script type="text/javascript">
  function $(elem) {
    return document.querySelector(elem);
  }

  // 获取媒体方法(旧方法)
  navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMeddia || navigator.msGetUserMedia;

  var canvas = $('canvas'),
    context = canvas.getContext('2d'),
    video = $('video'),
    snap = $('#snap'),
    close = $('#close'),
    upload = $('#upload'),
    uploaded = $('#uploaded'),
    mediaStreamTrack;

  // 获取媒体方法(新方法)
  // 使用新方法打开摄像头
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    }).then(function(stream) {
      console.log(stream);

      mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[1];

      video.src = (window.URL || window.webkitURL).createObjectURL(stream);
      video.play();
    }).catch(function(err) {
      console.log(err);
    })
  }
  // 使用旧方法打开摄像头
  else if (navigator.getMedia) {
    navigator.getMedia({
      video: true
    }, function(stream) {
      mediaStreamTrack = stream.getTracks()[0];

      video.src = (window.URL || window.webkitURL).createObjectURL(stream);
      video.play();
    }, function(err) {
      console.log(err);
    });
  }

  // 截取图像
  snap.addEventListener('click', function() {
    context.drawImage(video, 0, 0, 200, 150);
  }, false);

  // 关闭摄像头
  close.addEventListener('click', function() {
    mediaStreamTrack && mediaStreamTrack.stop();
  }, false);

  // 上传截取的图像
  upload.addEventListener('click', function() {
    jQuery.post('/uploadSnap.php', {
      snapData: canvas.toDataURL('image/png')
    }).done(function(rs) {
      rs = JSON.parse(rs);

      console.log(rs);

      uploaded.src = rs.path;
    }).fail(function(err) {
      console.log(err);
    });
  }, false);

  </script>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js捕获鼠标右键菜单中的粘帖事件实现代码
Apr 01 Javascript
JavaScript初学者建议:不要去管浏览器兼容
Feb 04 Javascript
jquery ajax,ashx,json的用法总结
Feb 12 Javascript
JavaScript中点击事件的写法
Jun 28 Javascript
AngularJS表单验证中级篇(3)
Sep 28 Javascript
jQuery Ajax传值到Servlet出现乱码问题的解决方法
Oct 09 Javascript
JavaScript中清空数组的三种方式
Mar 22 Javascript
Bootstrap datepicker日期选择器插件使用详解
Jul 26 Javascript
使用vue与jquery实时监听用户输入状态的操作代码
Sep 19 jQuery
分享vue.js devtools遇到一系列问题
Oct 24 Javascript
jQuery EasyUI 选项卡面板tabs的使用实例讲解
Dec 25 jQuery
vue.js,ajax渲染页面的实例
Feb 11 Javascript
Android中Okhttp3实现上传多张图片同时传递参数
Feb 18 #Javascript
AngularJS表单提交实例详解
Feb 18 #Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
Feb 18 #Javascript
JS实现数组去重复值的方法示例
Feb 18 #Javascript
bootstarp modal框居中显示的实现代码
Feb 18 #Javascript
JS实现本地存储信息的方法(基于localStorage与userData)
Feb 18 #Javascript
JS表单数据验证的正则表达式(常用)
Feb 18 #Javascript
You might like
社区(php&amp;&amp;mysql)六
2006/10/09 PHP
常见的PHP五种设计模式小结
2011/03/23 PHP
PHP中使用CURL获取页面title例子
2015/01/07 PHP
PHP使用内置dir类实现目录遍历删除
2015/03/31 PHP
PHP实现针对日期,月数,天数,周数,小时,分,秒等的加减运算示例【基于strtotime】
2017/04/19 PHP
PHP简单验证码功能机制实例详解
2019/03/27 PHP
javascript各浏览器中option元素的表现差异
2011/04/07 Javascript
基于jquery实现的表格分页实现代码
2011/06/21 Javascript
了解一点js的Eval函数
2012/07/26 Javascript
js获取当前时间显示在页面上并每秒刷新
2014/12/24 Javascript
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
如何用js 实现依赖注入的思想,后端框架思想搬到前端来
2015/08/03 Javascript
JavaScript 动态三角函数实例详解
2017/01/08 Javascript
简单实现js菜单栏切换效果
2017/03/04 Javascript
vue的Virtual Dom实现snabbdom解密
2017/05/03 Javascript
Bootstrap modal只加载一次数据的解决办法(推荐)
2017/11/24 Javascript
webpack-dev-server自动更新页面方法
2018/02/22 Javascript
微信小程序支付功能 php后台对接完整代码分享
2018/06/12 Javascript
Python Socket传输文件示例
2017/01/16 Python
windows下python之mysqldb模块安装方法
2017/09/07 Python
Python实现图片添加文字
2019/11/26 Python
Python内置函数locals和globals对比
2020/04/28 Python
python中元组的用法整理
2020/06/15 Python
keras实现VGG16方式(预测一张图片)
2020/07/07 Python
python 合并多个excel中同名的sheet
2021/01/22 Python
基于HTML5 Canvas的3D动态Chart图表的示例
2017/11/02 HTML / CSS
web字体加载方案优化小结
2019/11/29 HTML / CSS
台湾乐天市场:日本No.1的网路购物网站
2017/03/22 全球购物
体育学院毕业生自荐信
2013/11/03 职场文书
4s店总经理岗位职责
2013/12/31 职场文书
民族学专业求职信
2014/07/28 职场文书
员工趣味活动方案
2014/08/27 职场文书
2014年小学数学教师工作总结
2014/12/03 职场文书
2016年大学光棍节活动总结
2016/04/05 职场文书
助学金申请书该怎么写?
2019/07/16 职场文书
asyncio异步编程之Task对象详解
2022/03/13 Python