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 相关文章推荐
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
Sep 04 Javascript
JQuery从头学起第一讲
Jul 04 Javascript
js如何调用qq互联api实现第三方登录
Mar 28 Javascript
jQuery中:animated选择器用法实例
Dec 29 Javascript
Jquery使用css方法改变样式实例
May 18 Javascript
jQuery实现右侧显示可向左滑动展示的深色QQ客服效果代码
Oct 23 Javascript
第一次接触神奇的Bootstrap表单
Jul 27 Javascript
JS实现根据文件字节数返回文件大小的方法
Aug 02 Javascript
完美解决手机浏览器顶部下拉出现网页源或刷新的问题
Nov 30 Javascript
改进 JavaScript 和 Rust 的互操作性并深入认识 wasm-bindgen 组件
Jul 13 Javascript
如何在vue项目中嵌入jsp页面的方法(2种)
Feb 06 Javascript
vue 中 get / delete 传递数组参数方法
Mar 23 Vue.js
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
discuz目录文件资料汇总
2014/12/30 PHP
PHP使用ffmpeg给视频增加字幕显示的方法
2015/03/12 PHP
PHP共享内存用法实例分析
2016/02/12 PHP
Jquery工作常用实例 使用AJAX使网页进行异步更新
2011/07/26 Javascript
jQuery表格排序组件-tablesorter使用示例
2014/05/26 Javascript
extjs 时间范围选择自动判断的实现代码
2014/06/24 Javascript
用简洁的jQuery方法toggleClass实现隔行换色
2014/10/22 Javascript
JavaScript限定图片显示大小的方法
2015/03/11 Javascript
JS实现超简单的鼠标拖动效果
2015/11/02 Javascript
Vue.js实现一个漂亮、灵活、可复用的提示组件示例
2017/03/17 Javascript
原生JS控制多个滚动条同步跟随滚动效果
2017/12/22 Javascript
详解JavaScript中的强制类型转换
2019/04/15 Javascript
webpack HappyPack实战详解
2019/10/08 Javascript
使用React-Router实现前端路由鉴权的示例代码
2020/07/26 Javascript
小程序实现可拖动的悬浮按钮
2020/09/07 Javascript
解决ant-design-vue中menu菜单无法默认展开的问题
2020/10/31 Javascript
javascript实现下拉菜单效果
2021/02/09 Javascript
python读取Android permission文件
2013/11/01 Python
Python3.遍历某文件夹提取特定文件名的实例
2018/04/26 Python
Tensorflow卷积神经网络实例
2018/05/24 Python
python中如何使用分步式进程计算详解
2019/03/22 Python
Python高级特性之闭包与装饰器实例详解
2019/11/19 Python
利用matplotlib为图片上添加触发事件进行交互
2020/04/23 Python
Django 解决阿里云部署同步数据库报错的问题
2020/05/14 Python
Python如何执行精确的浮点数运算
2020/07/31 Python
Python爬虫之App爬虫视频下载的实现
2020/12/08 Python
物流管理专业职业生涯规划书
2014/01/06 职场文书
总会计师岗位职责
2014/02/19 职场文书
教育系统干部作风整顿心得体会
2014/09/09 职场文书
毕业实习自我鉴定范文2014
2014/09/26 职场文书
2014年公司工作总结
2014/11/22 职场文书
践行三严三实心得体会(2016推荐篇)
2016/01/06 职场文书
创业计划书之香辣虾火锅
2019/09/23 职场文书
详解Html5项目适配系统深色模式方案总结
2021/04/14 HTML / CSS
详细介绍Next.js脚手架完整搭建封装
2022/04/26 Javascript
使用JS前端技术实现静态图片局部流动效果
2022/08/05 Javascript