/*
实例化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>

浏览器调起摄像头(jquery+layui)的更多相关文章

  1. 在火狐、360等浏览器中,用jquery创建表单并发送的问题

    某些浏览器无法使用js或者jquery直接创建表单并发送,这是由于这些浏览器在提交页面表单时要求页面有完整的标签项即<html><head><title></ ...

  2. input type = file 在部分安卓手机上无法调起摄像头和相册

    移动端H5web 用input type = file 在部分安卓手机上无法调起摄像头拍照,有的也无法访问相册而是直接访问了文档,解决办法是: 加上 accept = "image/*&qu ...

  3. 浏览器调起Hbuilder的APP

           最近用Hbuilder来开发APP,测试各种功能,其中,最近测试到,要用这个浏览器调起APP的功能,我看官网有教程,但是有些可能刚工作没多久,所以,有些地方看不大明白,官方也没细说,所以 ...

  4. jquery layui的巨坑

    jquery layui的巨坑 layui 模块不能写在ajax里 因为 layui只能执行一次 第二次会没效果 再执行需要刷新页面再执行

  5. 深入浏览器兼容 细数jQuery Hooks 属性篇

    关于钩子:http://www.cnblogs.com/aaronjs/p/3387906.html 本章的目的很简单,通过钩子函数更细节的了解浏览器差异与处理方案, 版本是2.0.3所以不兼容ie6 ...

  6. 浏览器下载/导出文件 及jQuery表单提交

    1 比如以下按钮, 用于导出文件,如EXCEL文件. <li> <button class="whiteBg btn2" onclick="doExp( ...

  7. 能跨域和跨浏览器的flashcookie for jquery插件

    对于写网站时需要跨域和跨浏览器的可以看看这个. 引入jquery  和 swfstore.min.js 就可以了,蛮简单好用的,会jquery基础就可以咯. mySwfStore.set('myKey ...

  8. pasteimg浏览器中粘贴图片jQuery插件

    pasteimg是一款可以在浏览器中实现图片粘贴的jQuery插件,兼容Chrome.Firefox.IE11以及其他使用这些内核的浏览器,比如,国内著名的360浏览器. pasteimg可以识别浏览 ...

  9. chrome浏览器模拟手机端:jquery click()点击无效解决方法

    $(".sku-wrap .ok").click(); chrome浏览器模拟手机端,在油猴插件中写JS代码,然后发现click()点击失效. 解决方法:jquery的click( ...

随机推荐

  1. vue项目中使用高德地图(根据坐标定位点)

    前言 项目中需要根据坐标定位,将自己的实现过程写下来,废话不多说,上代码 正文 <script> var map,marker; export default { data(){ retu ...

  2. SQLZOO 习题

    https://sqlzoo.net 8. 美國.印度和中國(USA, India, China)是人口又大,同時面積又大的國家.排除這些國家. 顯示以人口或面積為大國的國家,但不能同時兩者.顯示國家 ...

  3. linux下挂载U盘方法

    1.使用 cat /proc/partitions 查看系统现在有哪些分区:[root@localhost ~]# cat /proc/partitions major minor  #blocks  ...

  4. Archlinux笔记本安装手记

    最近看着Linux Mint里一揽子乱七八糟的应用和散布各处的配置文件愈发烦躁,便想体验下大名鼎鼎的Arch,网上的帖子们把Arch Linux的安装难度描述的非常可怕,但实际上跟着Wiki一步一步来 ...

  5. shell 搜索指定目录下所有 jar 文件生成csv文件

    虽说比较简单,但希望分享给大家.按需求改成想找的:例如txt,xls 等. 脚本名 扫描的路径 文件名 testFind.sh /  testFind.txt (如果未配置环境变量  ./testFi ...

  6. 04机器学习实战之朴素贝叶斯scikit-learn实现

    In [8]: import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from sklearn.pre ...

  7. Codeforces 1192B 全dfs序 + 线段树

    题意:给你一颗树,每次会修改一条边的边权,问修改之后的树的直径是多少? 思路:来源于:https://www.cnblogs.com/TinyWong/p/11260601.html 得到树的全序df ...

  8. ps:矢量格式图像

    假设我们写了一首新的乐曲,要把它交给唱片公司,可以通过两种方式: 把这首乐曲弹奏出来并录制在磁带上. 把这首乐曲的乐谱写下来. 这两种方式的最大区别在于记录的形式. 前者是记述性的.包含乐曲的音频信息 ...

  9. tomcat 部署指南

    下载与安装 个人建议不要使用发行版带的版本, 始终从主页来下载安装, 下载地址位于[1], 安装方法很简单, 直接解压即可, 建议解压到 /usr/local/ 目录, 再链接到 /usr/local ...

  10. dubbo、web应用 项目结构以及发布目录结构

    一.dubbo服务项目结构及发布结构 dubbo 服务项目结构 xxxxx-api 接口类和一些DTO 用于供其他项目依赖 需要提供dubbo服务的接口命名 以Facade结尾 (xxxxxFacad ...