近日剛做的一個功能,要在app裡使用內嵌頁面進行影像的上傳。
從功能上看,原生的實現應該是最好的。畢竟頁面上所有的東西都隔著一個瀏覽器,所有的實現都要依賴瀏覽器提供的介面,不同的瀏覽器對介面的實現又有差異……到最後又會陷入相容性的大坑!
吐槽歸吐槽,但是折騰的勁頭不能丟!
使用input
file[camera]屬性呼叫相機
簡直So easy!
<input type=“file” accept=“image/*;” capture=“camera” >
|
只需要這麼一條簡單的程式碼,在手機瀏覽器點選就可以開啟相機了。
capture
是什麼?其實就是對開啟方式的設定。
<!– capture=camcorder,呼叫手機攝像功能 –>
<input type=“file” accept=“video/*” capture=“camcorder” >
<!– capture=microphone,呼叫手機錄音功能 –>
<input type=“file” accept=“audio/*” capture=“microphone” >
|
魅族MX5測試結果:
- 谷歌瀏覽器可以開啟相機和攝像功能,其他方式均為相機、相簿、檔案管理器等混合選擇項。
- 自帶瀏覽器開啟均為檔案管理器。
由此說明此屬性相容性還是個問題。不過這並不能阻止我繼續折騰下去!
圖片壓縮
在如今這個手機普遍千萬畫素的時代,一張照片動輒5M的大小。作為一個良心的開發者,我們是要為使用者的流量負責的。
該怎麼做?我也不知道。大家都在用canvas
實現,我也就用了。
document.getElementById(`file`).addEventListener(`change`, function() {
var reader = new FileReader();
reader.onload = function (e) {
compress(this.result);
};
reader.readAsDataURL(this.files[0]);
}, false);
|
不管檔案域是用何種方式開啟的,都可以在 change
事件中獲取到選擇的檔案或拍攝的照片。
建立一個FileReader
物件,我們需要呼叫readAsDataURL
把檔案轉換為base64
影像編碼,如data:image/jpeg;base64……
這種格式。onload
是一個非同步回撥,當檔案讀取完執行該方法內程式碼。this.result
記錄讀取結果,如果讀取失敗,該值為null
。在這裡進行圖片壓縮的具體操作。
var compress = function (res) {
var img = new Image(),
maxH = 160;
img.onload = function () {
var cvs = document.createElement(`canvas`),
ctx = cvs.getContext(`2d`);
if(img.height > maxH) {
img.width *= maxH / img.height;
img.height = maxH;
}
cvs.width = img.width;
cvs.height = img.height;
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.drawImage(img, 0, 0, img.width, img.height);
var dataUrl = cvs.toDataURL(`image/jpeg`, 0.6);
// 上傳略
}
img.src = res;
}
|
建立一個Image
物件,給src
屬性賦值為讀取結果,同樣在onload
非同步回撥中編寫處理圖片的程式碼。
這裡就要開始使用canvas
進行圖片壓縮了。
首先是尺寸按比例縮放,然後把圖片繪到畫布上,最後呼叫toDataURL
方法壓縮影像質量。
context.toDataURL(`MIME型別`, 影像質量0-1); // 該方法返回base64影像編碼
|
程式碼裡省略了一些校監操作,如檔案型別約束和檔案大小判斷(小於一定值可以不壓縮)。
最後就是把資料傳送到後端的操作,這裡就不說了。
Html5呼叫攝像頭
通過以上的程式碼已經可以實現呼叫手機相機拍照、壓縮、上傳這一整套流程了。
不過在折騰的過程中也發現了一種呼叫攝像頭的方法。注意,是攝像頭
!使用input呼叫的是相機。其中的差別就是攝像頭是隻捕獲畫面,相機還包括原生的一些拍照、設定等控制元件。
通過對攝像頭的呼叫可以做很多有趣的事,比如拍照美化、濾鏡等。可以說實現一個第三方相機是沒問題的。
之前下載過一款安卓相機APP,不到100K的大小,可以實現拍照的一些風格化,也許就是Html5實現的呢。
需要用到的是 getUserMedia API,具體的實現這裡就不貼了。