背景:移動端H5項目,須要實現調用手機拍照,並將圖片壓縮上傳功能。javascript
<input type="file" accept="image/*" capture="camera" >
//使用cursor進行事件穿透,來阻止元素成爲鼠標事件的目標 button{ cursor:pointer; pointer-events:none; }
----此時圖片上傳的樣式已經處理好了----css
代碼片斷:<style > *{ padding: 0; margin: 0; } .wrapper{ width: 320px; height: 50px; margin: 20px auto; position: relative; border: 1px solid #f0f0f0; } input{ width: 100px; height: 30px; } button{ position: absolute; cursor: pointer; pointer-events: none; width: 100px; height: 30px; left: 0; top: 0; } a{ pointer-events: none; } .img{ border: 1px solid #ccc; padding: 10px; } </style > <div class = "wrapper"> <input type = "file" accept= "image/*" capture= "camera" id= "img" /> <button >上傳照片 </button > </div >
經過change事件,監聽圖片上傳,經過readerAsDataURL獲取上傳的圖片。html
document.getElementById( 'img').addEventListener( 'change', function () { var reader = new FileReader(); reader.onload = function (e) { //調用圖片壓縮方法:compress(); }; reader.readAsDataURL(this.files[0]); console.log(this.files[0]); var fileSize = Math.round( this.files[0].size/1024/1024) ; //以M爲單位 //this.files[0] 該信息包含:圖片的大小,以byte計算 獲取size的方法以下:this.files[0].size; }, false);
對上傳的圖片進行壓縮,須要藉助於canvas API,調用其中的canvas.toDataURL(type, encoderOptions); 將圖片按照必定的壓縮比進行壓縮,獲得base64編碼。重點來了:壓縮策略:先設置圖片的最大寬度 or 最大高度,通常設置其中一個就能夠了,由於全部的手機寬高比差異不是很大。而後設置圖片的最大size,allowMaxSize,根據圖片的實際大小和最大容許大小,設置相應的壓縮比率。前端
//最終實現思路: 一、設置壓縮後的最大寬度 or 高度; 二、設置壓縮比例,根據圖片的不一樣size大小,設置不一樣的壓縮比。 function compress(res,fileSize) { //res表明上傳的圖片,fileSize大小圖片的大小 var img = new Image(), maxW = 640; //設置最大寬度 img.onload = function () { var cvs = document.createElement( 'canvas'), ctx = cvs.getContext( '2d'); if(img.width > maxW) { img.height *= maxW / img.width; img.width = maxW; } 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 compressRate = getCompressRate(1,fileSize); var dataUrl = cvs.toDataURL( 'image/jpeg', compressRate); document.body.appendChild(cvs); console.log(dataUrl); } img.src = res; } function getCompressRate(allowMaxSize,fileSize){ //計算壓縮比率,size單位爲MB var compressRate = 1; if(fileSize/allowMaxSize > 4){ compressRate = 0.5; } else if(fileSize/allowMaxSize >3){ compressRate = 0.6; } else if(fileSize/allowMaxSize >2){ compressRate = 0.7; } else if(fileSize > allowMaxSize){ compressRate = 0.8; } else{ compressRate = 0.9; } return compressRate; }
緣由:html5 canvas屬於客戶端API,沒有權限去保存圖片到硬盤,只有canvas.toDataURL()這一接口可導出畫布的base64編碼,以提供給服務器進行處理保存。因此若是要將base64編碼轉成圖片須要藉助於nodeJs。由於nodeJS有相關文件處理的API。html5
//使用nodeJS將base64轉化成圖片 var express = require('express'); var fs = require("fs"); var app = module.exports = express(); function dataToImage(dataUrl){ var base64Data = dataUrl.replace(/^data:image\/\w+;base64,/,''); var dataBuffer = new Buffer(base64Data,'base64'); fs.writeFile('out.jpg',dataBuffer,function(err){ if(err){ console.log(err); }else{ console.log('Success...'); } }); } dataToImage('data:image/jpeg;base64,/9...'); //圖片完整base64過長,因此省略... if(!module.parent){ app.listen(8000); console.log('Express started on port 8000'); }
Summary:若是使用nodeJS,須要單獨部署nodeJS代碼到服務器,整個邏輯會比較麻煩。綜合比較兩種方法,推薦使用第一種方法,直接傳base64給服務器,後臺處理相應的轉化!java
demo: http://www.zhangyixia.com/image-upload/ node
可直接掃描二維碼:
css3
相關知識科普:web
canvas.toDataURL(type, encoderOptions);
參考資料:express
http://www.imys.net/20150916/webapp-input-use-camera.html
http://www.oxxostudio.tw/articles/201409/pointer-events.html