移動端H5圖片上傳的那些坑

上週作一個關於移動端圖片壓縮上傳的功能。期間踩了幾個坑,在此總結下。javascript

大致的思路是,部分API的兼容性請參照caniusehtml

  1. 利用FileReader,讀取blob對象,或者是file對象,將圖片轉化爲data uri的形式。
  2. 使用canvas,在頁面上新建一個畫布,利用canvas提供的API,將圖片畫入這個畫布當中。
  3. 利用canvas.toDataURL(),進行圖片的壓縮,獲得圖片的data uri的值
  4. 上傳文件。

步驟1當中,在進行圖片壓縮前,仍是對圖片大小作了判斷的,若是圖片大小大於200KB時,是直接進行圖片上傳,不進行圖片的壓縮,若是圖片的大小是大於200KB,則是先進行圖片的壓縮再上傳:html5

<input type="file" id="choose" accept="image/*">
var fileChooser = document.getElementById("choose"),
        maxSize = 200 * 1024;   //200KB
    fileChoose.change = function() {
        var file = this.files[0],   //讀取文件
            reader = new FileReader();
            
            reader.onload = function() {
                var result = this.result,   //result爲data url的形式
                    img = new Image(),
                    img.src = result;
                    
                    
                if(result.length < maxSize) {  
                    imgUpload(result);      //圖片直接上傳
                } else {
                    var data = compress(img);    //圖片首先進行壓縮
                    imgUpload(data);                //圖片上傳
                }
            }
            
            reader.readAsDataURL(file);
    }

步驟2,3:java

var canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');
        
    function compress(img) {
        canvas.width = img.width;
        canvas.height = img.height;
        
        //利用canvas進行繪圖
        
        //將原來圖片的質量壓縮到原先的0.2倍。
        var data = canvas.toDataURL('image/jpeg', 0.2); //data url的形式
        
        return data;
    }

在利用canvas進行繪圖的過程當中,IOS圖片上傳過程當中,存在着這樣的問題:android

  1. 當你豎着拿手機的時候,拍完照,上傳圖片時,會出現照片自動旋轉的狀況,而橫着拍照並上傳圖片時不會出現這個問題。這個時候若是想糾正圖片自動旋轉的狀況,將圖片轉化爲二進制的數據(使用了binaryajax.js),方便獲取圖片的exif信息,經過獲取exif的信息來肯定圖片旋轉的角度(使用了exif.js),而後再進行圖片相應的旋轉處理。解決方法請戳我
  2. IOS中,當圖片的大小大於 2MB時,會出現圖片壓扁的狀況,這個時候須要重置圖片的比例。解決方法請戳我
  3. 利用FileReader,讀取圖片的過程須要花費必定時間,將圖片數據注入到canvas畫布中須要必定時間,圖片壓縮的過程當中,圖片越大,CPU計算消耗的時間也越長,可能會出現頓卡的狀況。總之,就是這個過程中須要花費必定時間。
  4. IOS8.1的版本中有個FileReader的bug: FileReader讀取的圖片轉化爲Base64時,字符串爲空,具體的問題描述請戳我

步驟4,文件上傳有2種方式:ios

  1. 將圖片轉化爲base64
  2. 將圖片數據轉爲Blob對象,使用FormData上傳文件

方式1能夠經過xhr ajax或者xhr2 FormData進行提交。git

方法2這裏就有個大坑了。具體描述請戳我github

簡單點說就是:Blob對象是沒法注入到FormData對象當中的。web

當你拿到了圖片的data uri數據後,將其轉化爲Blob數據類型ajax

var ndata = compress(img);
    ndata = window.atob(ndata); //將base64格式的數據進行解碼
    
    //新建一個buffer對象,用以存儲圖片數據
    var buffer = new Uint8Array(ndata.length);
    for(var i = 0; i < text.length; i++) {
        buffer[i] = ndata.charCodeAt(i);
    }
    
    //將buffer對象轉化爲Blob數據類型
    var blob = getBlob([buffer]);
    
    var fd = new FormData(),
        xhr = new XMLHttpRequest();
    fd.append('file', blob);
    
    xhr.open('post', url);
    xhr.onreadystatechange = function() {
        //do something
    }
    xhr.send(fd);

在新建Blob對象中有須要進行兼容性的處理,特別是對於不支持FormData上傳blob的andriod機的兼容性處理。具體的方法請戳我
主要實現的細節是經過重寫HTTP請求。


2月19日更新

在安卓機器中,部分4.x的機型, 在webview裏面對file對象進行了閹割,好比你拿不到file.type的值。

2月22日更新

Android4.4<input type="file">因爲系統WebViewopenFileChooser接口更改,致使沒法選擇文件,從而致使沒法上傳文件. bug描述請戳我

封裝好的github庫,請戳我,若是以爲文章不錯,請不要吝嗇你的star~~

相關文章
相關標籤/搜索