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

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

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

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

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

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

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>

JS打开摄像头并截图上传的更多相关文章

  1. 头像截图上传三种方式之一(一个简单易用的flash插件)(asp.net版本)

    flash中有版权声明,不适合商业开发.这是官网地址:http://www.hdfu.net/ 本文参考了http://blog.csdn.net/yafei450225664/article/det ...

  2. 使用Vlc.DotNet打开摄像头并截图 C#

      参考上一篇  使用vlc打开usb摄像头 理论上输入下面地址 "dshow:// :dshow-size=1600*1200:dshow-vdev=USB CAM2"C#就能打 ...

  3. Node + js实现大文件分片上传基本原理及实践(一)

    _ 阅读目录 一:什么是分片上传? 二:理解Blob对象中的slice方法对文件进行分割及其他知识点 三. 使用 spark-md5 生成 md5文件 四. 使用koa+js实现大文件分片上传实践 回 ...

  4. 通过修改ajaxFileUpload.js实现多图片动态上传并实现预览

    参考:http://smotive.iteye.com/blog/1903606 大部分我也是根据他的方法修改的,我也要根据name实现动态的多文件上传功能,但是有个问题使我一直无法实现多文件上传. ...

  5. Selenium常用API用法示例集----下拉框、文本域及富文本框、弹窗、JS、frame、文件上传和下载

    元素识别方法.一组元素定位.鼠标操作.多窗口处理.下拉框.文本域及富文本框.弹窗.JS.frame.文件上传和下载 元素识别方法: driver.find_element_by_id() driver ...

  6. 用js实现预览待上传的本地图片

    js实现预览待上传的本地图片,代码如下: <form name="form5" id="form5" method="post" ac ...

  7. php和js实现文件拖拽上传

    Dropzone.js实现文件拖拽上传 http://www.sucaihuo.com/php/1399.html demo http://www.sucaihuo.com/jquery/13/139 ...

  8. 在Asp.Net Core中配置使用MarkDown富文本编辑器实现图片上传和截图上传(开源代码.net core3.0)

    我们的富文本编辑器不能没有图片上传尤其是截图上传,下面我来教大家怎么实现MarkDown富文本编辑器截图上传和图片上传. 1.配置编辑器到html页 <div id="test-edi ...

  9. Js 之移动端图片上传插件mbUploadify

    一.下载 https://pan.baidu.com/s/1NEL4tkHoK4ydqdMi_hgWcw 提取码:vx7e 二.Demo示例 <div class="weui_uplo ...

随机推荐

  1. 内层div的margin-top影响外层div——引出外边距合并Collapsing margins

    内层div的margin-top影响外层div——引出外边距合并Collapsing margins 作者:zccst 今天才算是了解边距合并.正如一位前辈所言,每一个CSS的坑,都让你学到不少知识. ...

  2. STM32单片机在Keil5下仿真的问题解决及GPIO口初始化、使用

    STM32单片机在Keil5下仿真的问题解决及GPIO口初始化.使用 最近看了视频,里面有仿真,可以清楚看到GPIO口的数据变化,也想尝试下,DUG时却出现*** error 65: access v ...

  3. iOS 开发之动画篇 - 从 UIView 动画说起

    毋庸置疑的:在iOS开发中,制作动画效果是最让开发者享受的环节之一.一个设计严谨.精细的动画效果能给用户耳目一新的效果,吸引他们的眼光 —— 这对于app而言是非常重要的. 本文作为动画文集的第一篇, ...

  4. UVa 757 - Gone Fishing

    题目大意:John有h的时间可以去钓鱼,有n湖可钓鱼,以5分钟为时间单位,每个湖初始每个单位时间可钓f条鱼,每下一个时间单位数量减少d条.同时,John只能从1号湖往后走进行钓鱼,湖之间的距离需要t个 ...

  5. Android组件生命周期(三)

    Android系统试图尽可能长地保持一个应用程序进程,但是当内存低时它最终还是需要移除旧的进程.为了决定保持哪个进程及杀死哪个进程,Android将每个进程放入一个基于运行于其中的组件的重要性等级和这 ...

  6. Zepto 使用中的一些注意点(转)

    http://www.zeptojs.cn/     zepto英文站在线文档 http://www.css88.com/doc/zeptojs_api/       zepto中文站在线文档 htt ...

  7. delphi 字符串查找替换函数 转

    1.       提取字符串中指定子字符串前的字符串 Function Before( Src:string ; S:string ): string ; Var   F: Word ; begin ...

  8. Struts2 属性驱动、模型驱动、异常机制

    模型驱动使用单独的VO(值对象)来封装请求参数和处理结果,属性驱动则使用Action实例来封装请求参数和处理结果. 一.使用模型驱动 1.login.action采用模型驱动模式实现,采用模型驱动时必 ...

  9. MySQL ibdata多路径扩容

    vi /etc/my.cnf innodb_data_home_dir = innodb_data_file_path= /data/mysql/ibdata1:10M:autoextend(为目前i ...

  10. javascript 简单工厂

    function detail() { this.imgArr = []; this.codeArr = []; } detail.prototype.addimg = function(img) { ...