标题为最近遇到的一个实际要求,题目很简单,做起来挺费心费力。因为兼容性及潜在问题,目前单纯做到desktop chrome only。参考资料多见于 http://www.html5rocks.com/zh/tutorials/,可自行搜索相关内容。
若排版乱掉,查阅https://www.zybuluo.com/bornkiller/note/7064即可。
HTML主要部分如下
<div class="container">
<div class="row">
<div class="col-md-6 col-lg-6">
<video id="source" width="100%" height="480" autoplay></video>
<button id="snapTrigger">Snap Photo</button>
<button id="uploadTrigger">Upload Photo</button>
</div>
<div class="col-md-6 col-lg-6">
<canvas id="snapshot" width="600" height="460"></canvas>
</div>
</div>
</div>
浏览器调用摄像头拍照
浏览器调用摄像头需要全新的BOM对象,navigat.webkitGetUserMedia
,通过此接口,可以调用摄像头和麦克风,调用时需要用户授权方可开启。
- 摄像头画面实时显示
var video = document.querySelector('#source');
var sourceConfig = { "video" : true };
if(navigator.webkitGetUserMedia) {
navigator.webkitGetUserMedia(sourceConfig, function(stream) {
video.src = window.webkitURL.createObjectURL(stream);
video.play();
}, defaultErrHandle);
}
调用很简单,将摄像头捕获的二进制流转换为DomString
,再用video
节点引用即可,具体接口可自行查询。
- 截图
var canvas = document.querySelector('#snapshot');
var context = canvas.getContext('2d');
var snapTrigger = document.querySelector('#snapTrigger');
snapTrigger.addEventListener('click',function(e){
context.drawImage(video, 0, 0 ,600,480);
})
用canvas
画布绘制当前帧的像素信息。
二进制文件转换
前两步顺分顺水,到这一步的时候出现第一次近乎绝望的心情,当JAVASCRIPT一脚踩入二进制的世界,FE的世界观被震撼到。
- Canvas ----> Blob
Canvas有一个保存当前画布的方法canvas.toDataURL('image/jpeg')
,返回值是一个data-url shema
,通用格式为data:mimeType,base64,encodeString
,但实际需要的是二进制对象,所以需要转换,从data-url到blob对象,我最终也没有搞明白Base64 及相关的编码/解码问题,只是得到了转换的函数。函数内部涉及到两个很少用到的对象和一个全局方法,uInt8Array,Blob和window.atob()方法,有兴趣的自行google。。
function canvasToBlob(dataURL){
var BASE64_MARKER = ';base64,';
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: 'imgag/jpeg'});
}
该方法参数为data-url shema,返回值为一个标准 blob 对象。
方法参考了Github.com上封装html5 Filesystem
接口开源项目,地址:https://github.com/ebidel/filer.js。
Dropbox用户授权
拍照获取二进制对象之后,就需要上传到dropbox,感觉上并不难,dropbox支持HTTP
调用,但自己尝试以失败告终,只能通过官方推荐SDK来实现,该SDK功能很强大,但我用到的功能有限。dropbox.js
地址:https://github.com/dropbox/dropbox-js。
- 获取授权。
var client = new Dropbox.Client({ key: "2oj96m9cxc6psdf" });
client.authenticate(function(error, client) {
if (error) {
defaultErrHandle(error);
}
});
- 上传图片
function uploadFile(){
var tmp = canvasToBlob(canvas.toDataURL('image/jpeg'));
if(client.isAuthenticated()){
client.writeFile("profile.jpg", tmp , function(error, stat) {
if (error) {
defaultErrHandle(error); // Something went wrong.
}
});
}
}
通过SDK,可以很便捷的上传任何内容,client.writeFile()
方法支持string
,File
,Blob
,ArrayBuffer
.
- 个人原生代码尝试
dropbox的授权有implict grant
方式,所以一个重定向基本上就可以拿到access_token
,谈谈文件上传部分,代码如下:
function uploadFile(){
var tmp = canvasToBlob(canvas.toDataURL('image/jpeg'));
var xhr = new XMLHttpRequest();
var data = new FormData();
data.append('profile',tmp,'profile');
xhr.open('POST',
'https://api-content.dropbox.com/1/files/dropbox/',
true);
xhr.setRequestHeader('Authorization','Bearer ' + window.localStorage.getItem('access_token'));
xhr.send(data);
}
理论上没有问题,但实际上一直在给我返回400 Bad request
,多方查阅无法解决,遂只能放弃。
编码有感
- 最后编码以失败告终,心情比较沉闷,努力有时候并不能得到回报。
- 全新的HTML5跟现代浏览器的支持,已经能做到几年前FE根本不敢想象的事情,
FileSystem
,FileReader
,Websocket
,Worker
,UserMedia
,localstorage
,Canvas
,WebGL
,XHR Level2
,但是这么多特性实际应用的并不是很多,应用场景确实是个产品经理角度出发的考量,浏览器标准支持的滞后性也需要付出更多的学习成本和部署成本。 - 前端框架层出不穷,正在使用的
Angularjs
个人给32个赞,历久弥坚的backbone
用户基数不小,新晋的Ember.js
等一众正在吸引众人目光。我只用过Angularjs
,个人感觉这是个快速崛起的框架,难度是我唯一想吐槽的点,编码习惯的转换速度决定了学习使用这个框架的难度,越早放弃直接操作DOM的编码方式,越快能接受这个框架。如果用了Angularjs
,意味着后台是个纯粹的Restful API,在已经选用了这套框架之后,我是坚决反对再引入后台模板引擎,比如说Jade
。 - 后端Nodejs强势回归,前后端语言统一意味着前端工程师需要承担更多的开发职责。前端工程师可能做做页面,处理交互,后台工程师用模板引擎规则重写,然后服务器端渲染输出最终页。而现在的职责可能需要划到数据库查询这一层。
- 对前端工程师来说,最坏的时代,也是最好的时代。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。