JS打开摄像头并截图上传
直入正题,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打开摄像头并截图上传的更多相关文章
- 头像截图上传三种方式之一(一个简单易用的flash插件)(asp.net版本)
flash中有版权声明,不适合商业开发.这是官网地址:http://www.hdfu.net/ 本文参考了http://blog.csdn.net/yafei450225664/article/det ...
- 使用Vlc.DotNet打开摄像头并截图 C#
参考上一篇 使用vlc打开usb摄像头 理论上输入下面地址 "dshow:// :dshow-size=1600*1200:dshow-vdev=USB CAM2"C#就能打 ...
- Node + js实现大文件分片上传基本原理及实践(一)
_ 阅读目录 一:什么是分片上传? 二:理解Blob对象中的slice方法对文件进行分割及其他知识点 三. 使用 spark-md5 生成 md5文件 四. 使用koa+js实现大文件分片上传实践 回 ...
- 通过修改ajaxFileUpload.js实现多图片动态上传并实现预览
参考:http://smotive.iteye.com/blog/1903606 大部分我也是根据他的方法修改的,我也要根据name实现动态的多文件上传功能,但是有个问题使我一直无法实现多文件上传. ...
- Selenium常用API用法示例集----下拉框、文本域及富文本框、弹窗、JS、frame、文件上传和下载
元素识别方法.一组元素定位.鼠标操作.多窗口处理.下拉框.文本域及富文本框.弹窗.JS.frame.文件上传和下载 元素识别方法: driver.find_element_by_id() driver ...
- 用js实现预览待上传的本地图片
js实现预览待上传的本地图片,代码如下: <form name="form5" id="form5" method="post" ac ...
- php和js实现文件拖拽上传
Dropzone.js实现文件拖拽上传 http://www.sucaihuo.com/php/1399.html demo http://www.sucaihuo.com/jquery/13/139 ...
- 在Asp.Net Core中配置使用MarkDown富文本编辑器实现图片上传和截图上传(开源代码.net core3.0)
我们的富文本编辑器不能没有图片上传尤其是截图上传,下面我来教大家怎么实现MarkDown富文本编辑器截图上传和图片上传. 1.配置编辑器到html页 <div id="test-edi ...
- Js 之移动端图片上传插件mbUploadify
一.下载 https://pan.baidu.com/s/1NEL4tkHoK4ydqdMi_hgWcw 提取码:vx7e 二.Demo示例 <div class="weui_uplo ...
随机推荐
- C#基础之操作字符串的方法
C#基础之操作字符串的方法 C#中封装的对字符串操作的方法很多,下面将常见的几种方法进行总结: 首先定义一个字符串str 1.str.ToCharArray(),将字符串转换成字符数组 2.str.S ...
- S3C2440的RTC解析
位二-十进制交换码(BCD)值数据给CPU.这些数据包括年.月.日.星期.时.分和秒的时间信息.RTC单元工作在外部32.768kHz晶振并且可以执行闹钟功能 实时时钟模块保存的数据是DCD码形式. ...
- DateFormat 竟然是非线程安全的?!!!!!
今天撸代码忽然发现一个奇怪的一场抛出,经过一番排查发现有可能DateFormat 的多线程问题造成的,网上一查DateFormat竟然非线程安全.那我原先的代码...(细思极恐)
- java--反射和注解
一.java.lang.reflect类 Class类 1.反射机制(Reflection):通过类创建对象, 2.反射机制提供了如下功能: 在运行时,判断任意一个对象所属的类 构造任意一个类的对 ...
- IM 融云 之 安装cocoapods 安装 SDK
1. podfile 内容如下: platform :ios, '7.0' pod 'RongCloudIMKitWithVoip', '2.4.3' 现在最新是2.4.3 导入之后,就直接可以用了. ...
- R语言中的if-else语句写法
结构 1 : if() xx else yy 一行: 结构 2: if() {xx} else {yy} 或者 if(){ xx }else #此处不能两行写 ...
- APPcache
<!DOCTYPE html> <html manifest="example.appcache"> <head> <title>& ...
- ceentos5.5 配置samba服务&用户&组
准备 Change Root Password passwd root 在提示下建立新密码 静态IP vi /etc/sysconfig/network-scripts/ifcfg-eth0 #网络 ...
- mark笔记
1.[cocos2dx]ccnode跟ccui节点混用时注意touch层级问题,基本不可控
- c 语言冒泡排序
重要的不是代码 而是思想思路 #include<stdio.h> void Print(int *num, int n) { int i; for(i = 0; i < ...