1

标题为最近遇到的一个实际要求,题目很简单,做起来挺费心费力。因为兼容性及潜在问题,目前单纯做到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强势回归,前后端语言统一意味着前端工程师需要承担更多的开发职责。前端工程师可能做做页面,处理交互,后台工程师用模板引擎规则重写,然后服务器端渲染输出最终页。而现在的职责可能需要划到数据库查询这一层。
  • 对前端工程师来说,最坏的时代,也是最好的时代。

怀疑真爱的流浪者jason
923 声望62 粉丝

For every single second in life, I want to fight with the monster deep within my heart , and I want to win.........