新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
1. 项目背景
为抚远等地区用户提供了全套网页设计制作服务,及抚远网站建设行业解决方案。主营业务为成都网站设计、成都网站制作、抚远网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
网站项目基于HTML5+AngularJs开发,正在做一个由HTML5调用摄像头拍照,从而实现修改头像的功能。起初觉得HTML5拍照很简单,但是做的时候才发现HTML5获取摄像头并不是那么容易。
2. 如何调用摄像头
$scope.photoErr = false;
$scope.photoBtnDiable = true;
var mediaStream = null,track = null;
navigator.getMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
if (navigator.getMedia) {
navigator.getMedia(
{
video: true
},
// successCallback
function (stream) {
var s = window.URL.createObjectURL(stream);
var video = document.getElementById('video');
video.src = window.URL.createObjectURL(stream);
mediaStream = stream;
track = stream.getTracks()[0];
$scope.photoBtnDiable = false; $scope.$apply();
},
// errorCallback
function (err) {
$scope.errorPhoto();
console.log("The following error occured:" + err);
});
} else {
$scope.errorPhoto();
}
代码解析:
navigator为浏览器对象,包含浏览器的信息,这里就是用这个对象打开摄像头。$scope为AndularJs语法。第一步声明navigator.getMedia来调用浏览器不同的打开摄像头函数,目前仅有getUserMedia、webkitGetUserMedia、mozGetUserMedia、msGetUserMedia四种方式分别对应通用浏览器、Google浏览器、火狐浏览器和IE浏览器,浏览器会自动判断调用哪一个函数。第二步是调用打开浏览器,包含三个参数,分别为需要使用的多媒体类型、获取成功返回的流数据处理函数以及操作失败返回错误消息处理函数。其中,使用时不仅可以设置视频还能设置使用麦克风,设置方式为:
{
video: true,
audio: true
}
调用成功即打开摄像头后返回视频流数据,我们可以将流数据设置到video标签在界面上实时显示图像。mediaStream用来记录获取到的流数据,track在Chrome浏览器中用来跟踪摄像头状态,这两个变量都能用来关闭摄像头。
3. 拍照
$scope.snap = function () {
var canvas = document.createElement('canvas');
canvas.width = "400";
canvas.height = "304";
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, 400, 304);
$scope.closeCamera();
$uibModalInstance.close(canvas.toDataURL("image/png"));
};
拍照时需要使用到canvas标签,创建一个canvas标签,设置我们需要拍照的尺寸大小,通过drawImage函数将video当前的图像保存到canvas标签,最后将图像数据转换为base64数据返回并关闭摄像头,这样就完成了我们的拍照功能。这里的$uibModalInstance对象是我们项目中打开弹出层的一个对象,用来控制弹出层的显示。
4. 如何关闭摄像头
$scope.closeCamera = function () {
if (mediaStream != null) {
if (mediaStream.stop) {
mediaStream.stop();
}
$scope.videosrc = "";
}
if (track != null) {
if (track.stop) {
track.stop();
}
}
}
正如前面所说,关闭摄像头的方式是通过mediaStream和track变量,只不过,track只能关闭Chrome浏览器中的摄像头,这也是Chrome 45版本以上关闭摄像头的方式。
5. 集成到AndularJs
事实上,前面所说的都是在AndularJs中实现的,当然,这里只是实现了拍照并返回拍照数据,我们想要在其他地方也使用,就需要将这部分独立出来,这里我们用到了AngularJs中的service机制,将这部分单独做成一个service并在项目中注入,然后就可以在其他地方调用了。
service注册:
app().registerService("h5TakePhotoService", function ($q, $uibModal) {
this.photo = function () {
var deferred = $q.defer();
require([config.server + "/com/controllers/photo.js"], function () {
$uibModal.open({
templateUrl: config.server + "/com/views/modal_take_photo.html",
controller: "photoModalController",
windowClass: "modal-photo"
}).result.then(function (e) {
deferred.resolve(e);
});
});
return deferred.promise;
}
});
调用方式:
$scope.takePhoto = function () {
h5TakePhotoService.photo().then(function (res) {
if (res != null res != "") {
$scope.myImage = res;
}
});
}
h5TakePhotoService为控制器中注入的拍照service对象,最后处理返回的图像数据,设置数据显示到界面上。
6. 兼容问题
主要存在Chrome浏览器中,本地测试时,Chrome浏览器中能够正常使用,但是部署到服务器后就不能正常使用,报错消息为 [object NavigatorUserMediaError],这是因为Chrome浏览器在使用摄像头时只支持安全源访问,所以只能通过https访问才能正常使用。
最后需要说一下,测试时只能通过访问才能使用,不能通过方式访问,即我们需要将代码部署才能访问,可以在Visual Studio、 java web、php中完成。
用input type=file capture=camcorder调用摄像头,会先让你选择拍照或者从相册选取。
首先实现在浏览器中调用手机摄像头,实现拍照功能并且把拍下的照片显示在页面并上传到服务器上,然后再在服务器端进行分析。
首先实现在浏览器中调用摄像头,当然用现在火的不行的html5,html5中的video标签,并将从摄像头获得视频作为这个标签的输入来源。实现拍照功能的html5代码:
article
style scoped
video { transform: scaleX(-1); }
p { text-align: center; }
/style
h1Snapshot Kiosk/h1
section id="splash"
p id="errorMessage"Loading.../p
/section
section id="app" hidden
pvideo id="monitor" autoplay/video canvas id="photo"/canvas
pinput type=button value="????" onclick="snapshot()"
/section
script
navigator.getUserMedia({video:true}, gotStream, noStream);
var video = document.getElementById('monitor');
var canvas = document.getElementById('photo');
function gotStream(stream) {
video.src = URL.createObjectURL(stream);
video.onerror = function () {
stream.stop();
};
stream.onended = noStream;
video.onloadedmetadata = function () {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
document.getElementById('splash').hidden = true;
document.getElementById('app').hidden = false;
};
}
function noStream() {
document.getElementById('errorMessage').textContent = 'No camera available.';
}
function snapshot() {
canvas.getContext('2d').drawImage(video, 0, 0);
}
/script
/article
经本人测试在android手机的opera浏览器浏览器下可以正常实现手机拍照功能。android手机下的google chrome浏览器还不行,自带的浏览器也测试没有通过。iphone手机的safari浏览器也是不支持的。
想了解更多关于html5调用手机摄像头的内容可以点击。
图片的获取:
下面我们要从Canvas获取图片数据,其核心思路是用canvas的toDataURL将Canvas的数据转换为base64位编码的PNG图像,类似于“data:image/png;base64,xxxxx”的格式。
Html代码
var imgData =canvas.toDataURL("image/png");
因为真正图像数据是base64编码逗号之后的部分,所以我们实际服务器处理的图像数据应该是这部分,我们可以用两种办法来获取。
第一种:是在前端截取22位以后的字符串作为图像数据,例如:
Html代码
var data = imgData.substr(22);
如果要在上传前获取图片的大小,可以使用:
Html代码
var length = atob(data).length;// atob decodes a string of data which has been encoded using base-64 encoding
第二种:是在后端获取传输的数据后用后台语言截取22位以后的字符串。例如PHP里
php代码:
$image = base64_decode( str_replace('data:image/jpeg;base64,', '',$data);
图片上传:
在前端可以使用Ajax将上面获得的图片数据上传到后台脚本。例如使用jQuery时:
js代码
$.post('upload.php',{ 'data' : data } );
在后台我们用PHP脚本接收数据并存储为图片。
php代码
function convert_data($data){
$image = base64_decode( str_replace('data:image/jpeg;base64,', '',$data);
save_to_file($image);
}
function save_to_file($image){
$fp = fopen($filename, 'w');
fwrite($fp, $image); fclose($fp);
}
请注意,以上的解决方案不仅能用于Web App拍照上传,并且你可以实现把Canvas的输出转换为图片上传的功能。这样你可以使用Canvas为用户提供图片编辑,例如裁剪、上色、涂鸦的画板功能,然后把用户编辑完的图片保存到服务器上。
HTML5技术支持WebApp在手机上拍照,显示在页面上并上传到服务器。这是手机微博应用中常见的功能,当然你也可以在其它类型应用中适当使用此技术。
1、 视频流
HTML5 的 The Media Capture(媒体捕捉) API 提供了对摄像头的可编程访问,用户可以直接用 getUserMedia(请注意目前仅Chrome和Opera支持)获得摄像头提供的视频流。我们需要做的是添加一个HTML5 的 Video 标签,并将从摄像头获得的视频作为这个标签的输入来源。
video id=”video” autoplay=”"/video
script
var video_element=document.getElementById(‘video’);
if(navigator.getUserMedia){ // opera应使用opera.getUserMedianow
navigator.getUserMedia(‘video’,success,error); //success是回调函数,当然你也可以直接在此写一个匿名函数
}
function success(stream){
video_element.src=stream;
}
/script
此时,video 标签内将显示动态的摄像视频流。下面需要进行拍照了。
2、 拍照
拍照是采用HTML5的Canvas功能,实时捕获Video标签的内容,因为Video元素可以作为Canvas图像的输入,所以这一点很好实现。主要代码如下:
var canvas=document.createElement(‘canvas’); //动态创建画布对象
var ctx=canvas.getContext(’2d’);
var cw=vw,ch=vh;
ctx.fillStyle=”#ffffff”;
ctx.fillRect(0,0,cw,ch);
ctx.drawImage(video_element,0,0,cw,ch,0,0,vw,vh); //将video对象内指定的区域捕捉绘制到画布上指定的区域,可进行不等大不等位的绘制。
document.body.append(canvas);
3、 图片获取
从Canvas获取图片数据的核心思路是用canvas的toDataURL将Canvas的数据转换为base64位编码的PNG图像,类似于“data:image/png;base64,xxxxx”的格式。
var imgData=canvas.toDataURL(“image/png”);
这样,imgData变量就存储了一长串的字符数据内容,表示的就是一个PNG图像的base64编码。因为真正的图像数据是base64编码逗号之后的部分,所以要让实际服务器接收的图像数据应该是这部分,我们可以用两种办法来获取。
第一种:是在前端截取22位以后的字符串作为图像数据,例如:
var data=imgData.substr(22);
如果要在上传前获取图片的大小,可以使用:
var length=atob(data).length; //atob 可解码用base-64解码的字串
第二种:是在后端获取传输的数据后用后台语言截取22位以后的字符串(也就是在前台略过上面这步直接上传)。例如PHP里:
$image=base64_decode(str_replace(‘data:image/jpeg;base64,’,”,$data);
4、 图片上传
在前端可以使用Ajax将上面获得的图片数据上传到后台脚本。例如使用jQuery时可以用:
$.post(‘upload.php’,{‘data’:data});
在后台我们用PHP脚本接收数据并存储为图片。
function convert_data($data){
$image=base64_decode(str_replace(‘data:image/jpeg;base64,’,”,$data);
save_to_file($image);
}
function save_to_file($image){
$fp=fopen($filename,’w');
fwrite($fp,$image);
fclose($fp);
}
以上的解决方案不仅能用于Web App拍照上传,也可以通过Canvas的编辑功能函数提供图片编辑,例如裁剪、上色、涂鸦、圈点等功能,然后把用户编辑完的图片上传保存到服务器上。
在还在不断补充修正的HTML5的驱动下,Web App与Native App之间的距离将越来越小。在可预见的不远的未来,越来越多老的和新的开发项目必将会迁移到WEB应用上来。
相关规范:
The MediaCapture API:
Canvas:
html5中的video这个标签是引入视频的,通过navigator.getUserMedia去获取摄像头的视频流,所以要在事件里用关闭的代码都不能执行关闭摄像头,只有关闭网页,摄像头才关闭。
html5打开摄像头代码:
!DOCTYPE html
html lang="zh-cn"
head
meta content="text/html; charset=UTF-8" http-equiv="content-type"
titleSmart Home - Camera/title
link href="css/main.css" rel="stylesheet" type="text/css"
script src="js/jq.js"/script
script type="text/javascript"
/*
*/
function init(t){
accessLocalWebCam("camera_box");
}
// Normalizes window.URL
window.URL = window.URL || window.webkitURL || window.msURL || window.oURL;
// Normalizes navigator.getUserMedia
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia|| navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
function isChromiumVersionLower() {
var ua = navigator.userAgent;
var testChromium = ua.match(/AppleWebKit\/.* Chrome\/([\d.]+).* Safari\//);
return (testChromium (parseInt(testChromium[1].split('.')[0]) 19));
}
function successsCallback(stream) {
document.getElementById('camera_errbox').style.display = 'none';
document.getElementById('camera_box').src = (window.URL
window.URL.createObjectURL) ?
window.URL.createObjectURL(stream) : stream;
}
function errorCallback(err) {
}
function accessLocalWebCam(id) {
try {
// Tries it with spec syntax
navigator.getUserMedia({ video: true }, successsCallback, errorCallback);
} catch (err) {
// Tries it with old spec of string syntax
navigator.getUserMedia('video', successsCallback, errorCallback);
}
}
/script
style type="text/css"
#camera_errbox{
width:320px; height:auto; border:1px solid #333333; padding:10px;
color:#fff; text-align:left;margin:20px auto;
font-size:14px;
}
#camera_errbox b{
padding-bottom:15px;
}
/style
/head
body onLoad="init(this)" oncontextmenu="return false" onselectstart="return false"
div class="Screen_outer"
div id="mainbox" class="Screen_inner"
div id="bt_goback"/div
div class="logobox"/divdiv id="t_iconbox"
class="icon_12"/divdiv id="t_text"
div id="el_title" class="font_h2"Camera/div
div id="el_descr" class="font_2"/div
/div
div class="t_descri_bt"/div
div class="sp_title"span
class="sp_title_text"Camera/spandiv class="sp_oc
sp_oc_1"/div/div
dl id="el_actionbox" class="menu_btbox" style="text-align:center;"
video id="camera_box" autoplay="" src=""/video
div id="camera_errbox"
b请点击“允许”按钮,授权网页访问您的摄像头!/b
div若您并未看到任何授权提示,则表示您的浏览器不支持Media Capture或您的机器没有连接摄像头设备。/div
/div
/dl
/div
/div
/body
/html