原文 https://github.com/tmallfe/tmallfe.github.io/issues/4javascript
體驗完產品,具體講下技術實現方案,總體的實現過程能夠分爲:html
拍照->得到圖片數據->將商品與圖片合成->生成效果圖->用戶保存圖片html5
跨終端調取攝像頭java
這是試戴的關鍵一步,考慮到須要支持到各個終端,因此優先想到使用標準的web方案來實現:WebRTC - getUserMedia
jquery
基於 getUserMedia,面向 mobile 快速嘗試,基本完成了主要的功能android
但 getUserMedia 的支持狀況並不理想,尤爲是 sarfari 的不支持讓廣大 ios/mac 用戶沒法體驗,這裏就須要 PC、mobile 的兼容處理,以跨終端 mobile first 及優雅退化的思路設計兼容API:ios
控制先後攝像頭(web)git
對於戒指的試戴,手機上咱們指望優先調用後置攝像頭,在 web 中啓動時就須要設置優前後置攝像頭,W3C 文檔還處於 Draft 階段,相對還不是特別完善,能夠經過以下設置:github
{ video:{ optional: [ { sourceId: $sourceId } ] } }
經過 MediaStreamTrack.getSources
可得到設備的全部 sourceId,注意:考慮設備可能沒有外設如臺式機或外設設備不可用(在虛擬機或遠程),這種狀況下會報錯,因此須要 try&catach 容錯。web
控制拍照時圖片尺寸(web)
不一樣的終端,攝像頭拍攝的圖片照片尺寸是不一樣的,若是咱們只須要得到某一部分圖像,就須要對圖像作剪裁,在 WEB 中爲了避免引發用戶疑惑,展示給用戶拍照界面時,所見最好就是所須要的部分
舉個栗子:咱們指望得到一個正方形的圖片,可是 rmbp 中攝像原始是 16:9 的圖像,考慮方案有:
須要注意的是:video API 中有 videoHeight 及 videoWidth 兩個屬性,當 video play 時理論這兩個屬性就是當前圖像的寬高,但實際狀況 Mozilla 存在一個 bug#926753,play 時仍沒法準確獲取,兼容的方案輪訓監聽:
Event.on(video,"play",function(){ if(this.videoHeight===0){ return S.later(arguments.callee,100,false,this); } // now width/height ok }
在拍照完成 native 中須要把圖片數據傳遞給 web,另外用戶保存圖片到本地時,web 又須要把合成好的圖片數據傳遞給 native 讓其保存,這邊涉及 native 與 web 的傳遞大數據通信:
WebView#addJavascriptInterface()
向 web 注入 js 方法UIWebView#stringByEvaluatingJavaScriptFromString()
執行 js 函數,兩種方式向 web 傳遞大數據都沒有問題
比較簡單,用圖片說明: picWidth/maskWidth = x1/x = w1/w
知道了具體位置,生成圖片即可以簡單的調用 canvas.toDataURL
得到圖片數據,但這裏涉及一個圖片跨域問題:
Canvas 獲取圖片數據會有跨域的限制,以前有:imageProxy flash來作代理的方案,可是這個方案仍然不夠高效和簡潔,尤爲是對於 mobile 更無能爲力
最好的方案是 web 標準的 CORS,經過讓服務器返回 allow-origin 的 header,讓 canvas 能夠正常處理:
// http response header: Access-Control-Allow-Origin: * img.crossOrigin = "Anonymous"; img.onload = function() { ctx.drawImage( img, 0, 0 ); canvas.toDataURL("image/png"); }
在整個開發的過程當中是以組件化的思路分層處理,並封裝成了具體的組件,經過封裝的組件,後續拍照、試戴能夠快速搭建完成,除了天貓自身業務特點的組件外,比較通用的有:
再設計跨終端有組件時,經驗是優先面向 mobile 設計,這樣邏輯及交互流程更加簡潔,可讓 API 涉及更加清晰,後續正對 PC 適當兼容。
最後簡單聊下這個業務:這是一個技術驅動業務的項目,從初期的業務重點在頻道,中間經歷幾回業務調整,到目前把試戴做爲業務後續的重點,能夠說這個產品在其中起到了不少的做用,其中幾點經驗:
後續試戴還有不少地方能夠發力,比較重要的一些方向: