近日剛做的一個(gè)功能,要在app里使用內(nèi)嵌頁(yè)面進(jìn)行圖像的上傳。
從功能上看,原生的實(shí)現(xiàn)應(yīng)該是最好的。畢竟頁(yè)面上所有的東西都隔著一個(gè)瀏覽器,所有的實(shí)現(xiàn)都要依賴(lài)瀏覽器提供的接口,不同的瀏覽器對(duì)接口的實(shí)現(xiàn)又有差異……到最后又會(huì)陷入兼容性的大坑!
吐槽歸吐槽,但是折騰的勁頭不能丟!
使用input file[camera]屬性調(diào)用相機(jī)
簡(jiǎn)直So easy!
<input type="file" accept="image/*;" capture="camera" >只需要這么一條簡(jiǎn)單的代碼,在手機(jī)瀏覽器點(diǎn)擊就可以打開(kāi)相機(jī)了。
capture是什么?其實(shí)就是對(duì)打開(kāi)方式的設(shè)置。
<!-- capture=camcorder,調(diào)用手機(jī)攝像功能 --><input type="file" accept="video/*" capture="camcorder" > <!-- capture=microphone,調(diào)用手機(jī)錄音功能 --><input type="file" accept="audio/*" capture="microphone" >魅族MX5測(cè)試結(jié)果:
谷歌瀏覽器可以打開(kāi)相機(jī)和攝像功能,其他方式均為相機(jī)、圖庫(kù)、文件管理器等混合選擇項(xiàng)。
自帶瀏覽器打開(kāi)均為文件管理器。
由此說(shuō)明此屬性兼容性還是個(gè)問(wèn)題。不過(guò)這并不能阻止我繼續(xù)折騰下去!
圖片壓縮
在如今這個(gè)手機(jī)普遍千萬(wàn)像素的時(shí)代,一張照片動(dòng)輒5M的大小。作為一個(gè)良心的開(kāi)發(fā)者,我們是要為用戶(hù)的流量負(fù)責(zé)的。
該怎么做?我也不知道。大家都在用canvas實(shí)現(xiàn),我也就用了。
document.getElementById('file').addEventListener('change', function() { var reader = new FileReader(); reader.onload = function (e) { compress(this.result); }; reader.readAsDataURL(this.files[0]);}, false);不管文件域是用何種方式打開(kāi)的,都可以在 change 事件中獲取到選擇的文件或拍攝的照片。
創(chuàng)建一個(gè)FileReader對(duì)象,我們需要調(diào)用readAsDataURL把文件轉(zhuǎn)換為base64圖像編碼,如data:image/jpeg;base64……這種格式。
onload是一個(gè)異步回調(diào),當(dāng)文件讀取完執(zhí)行該方法內(nèi)代碼。this.result記錄讀取結(jié)果,如果讀取失敗,該值為null。在這里進(jìn)行圖片壓縮的具體操作。
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;}創(chuàng)建一個(gè)Image對(duì)象,給src屬性賦值為讀取結(jié)果,同樣在onload異步回調(diào)中編寫(xiě)處理圖片的代碼。
這里就要開(kāi)始使用canvas進(jìn)行圖片壓縮了。
首先是尺寸按比例縮放,然后把圖片繪到畫(huà)布上,最后調(diào)用toDataURL方法壓縮圖像質(zhì)量。
context.toDataURL('MIME類(lèi)型', 圖像質(zhì)量0-1); // 該方法返回base64圖像編碼代碼里省略了一些校監(jiān)操作,如文件類(lèi)型約束和文件大小判斷(小于一定值可以不壓縮)。
最后就是把數(shù)據(jù)發(fā)送到后端的操作,這里就不說(shuō)了。
Html5調(diào)用攝像頭
通過(guò)以上的代碼已經(jīng)可以實(shí)現(xiàn)調(diào)用手機(jī)相機(jī)拍照、壓縮、上傳這一整套流程了。
不過(guò)在折騰的過(guò)程中也發(fā)現(xiàn)了一種調(diào)用攝像頭的方法。注意,是攝像頭!使用input調(diào)用的是相機(jī)。其中的差別就是攝像頭是只捕獲畫(huà)面,相機(jī)還包括原生的一些拍照、設(shè)置等控件。
通過(guò)對(duì)攝像頭的調(diào)用可以做很多有趣的事,比如拍照美化、濾鏡等??梢哉f(shuō)實(shí)現(xiàn)一個(gè)第三方相機(jī)是沒(méi)問(wèn)題的。
之前下載過(guò)一款安卓相機(jī)APP,不到100K的大小,可以實(shí)現(xiàn)拍照的一些風(fēng)格化,也許就是Html5實(shí)現(xiàn)的呢。
需要用到的是 getUserMedia API,具體的實(shí)現(xiàn)這里就不貼了。
【用到的HTML5標(biāo)簽】
1
<input type="file" capture="camera" accept="image/*" id="cameraInput" name="cameraInput" class="sign_file"/>
【等比縮放圖片】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function drawOnCanvas(file) {
var reader = new FileReader();
reader.onload = function(e) {
var dataURL = e.target.result,
canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d'),
img = new Image();
img.onload = function() {
var square = 320;
canvas.width = square;
canvas.height = square;
var context = canvas.getContext('2d');
context.clearRect(0, 0, square, square);
var imageWidth;
var imageHeight;
var offsetX = 0;
var offsetY = 0;
if (this.width > this.height) {
imageWidth = Math.round(square * this.width / this.height);
imageHeight = square;
offsetX = -Math.round((imageWidth - square) / 2);
} else {
imageHeight = Math.round(square * this.height / this.width);
imageWidth = square;
offsetY = -Math.round((imageHeight - square) / 2);
}
context.drawImage(this, offsetX, offsetY, imageWidth, imageHeight);
var base64 = canvas.toDataURL('image/jpeg', 0.5);
$('#j_thumb').val(base64.substr(22));
};
img.src = dataURL;
};
reader.readAsDataURL(file);
}
FileReader對(duì)象是用來(lái)解析file控件獲取的本地圖片地址的,具體介紹請(qǐng)百度一下。把解析好的地址設(shè)置給IMG標(biāo)簽的SRC屬性,然后通過(guò)canvas對(duì)象把圖片繪制; 在這過(guò)程中就有個(gè)等比縮放的算法,再用drawImage方法把圖像畫(huà)到canvas中。
【如何獲取畫(huà)好的圖片數(shù)據(jù)傳到后端處理】
通過(guò) canvas.toDataURL(‘image/jpeg’,0.5)就可以獲取到base64編碼值,然后你就可以按照傳統(tǒng)的POST或者AJAX方式處理了。
【讓圖片顯示】
1
2
3
4
document.querySelector('input[type=file]').onchange = function() {
var file = input.files[0];
drawOnCanvas(file);
};
【后臺(tái)處理方式】
1
2
3
$base64 = $_POST['formFile'];
$IMG = base64_decode( $base64 );
file_put_contents('1.png', $IMG );
根傳統(tǒng)的上傳圖片不同,這時(shí)候后臺(tái)需要用base64_decode解碼