移動端 H5 圖片壓縮上傳

nkslixin 7年前發布 | 30K 次閱讀 HTML5 前端技術 canvas

移動端H5圖片壓縮上傳

大體的思路是,部分API的兼容性請參照 caniuse :

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

步驟1當中,在進行圖片壓縮前,還是對圖片大小做了判斷的,如果圖片大小大于200KB時,是直接進行圖片上傳,不進行圖片的壓縮,如果圖片的大小是大于200KB,則是先進行圖片的壓縮再上傳:

<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);
}</pre> 

步驟2,3:

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圖片上傳過程中,存在著這樣的問題:

  1. 當你豎著拿手機的時候,拍完照,上傳圖片時,會出現照片自動旋轉的情況,而橫著拍照并上傳圖片時不會出現這個問題。這個時候如果想糾正圖片自動旋轉的情況,將圖片轉化為二進制的數據 (使用了binaryajax.js) ,方便獲取圖片的 exif信息 ,通過獲取 exif的信息 來確定圖片旋轉的角度 (使用了exif.js) ,然后再進行圖片相應的旋轉處理。
  2. 在 IOS 中,當圖片的大小大于 2MB時,會出現圖片壓扁的情況,這個時候需要重置圖片的比例。 
  3. 利用FileReader,讀取圖片的過程需要花費一定時間,將圖片數據注入到canvas畫布中需要一定時間,圖片壓縮的過程中,圖片越大,CPU計算消耗的時間也越長,可能會出現頓卡的情況。總之,就是這個過程當中需要花費一定時間。
  4. IOS8.1的版本中有個 FileReader 的bug: FileReader 讀取的圖片轉化為Base64時,字符串為空,, 遇到這個情況的話- - 還是老老實實把圖片不做壓縮處理扔給服務端吧.

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

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

方式1可以通過 xhr ajax 或者 xhr2 FormData 進行提交。

方法2這里就有個大坑了。 

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

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

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日更新

在安卓機器中, 部分機型不支持 JPEG 格式的圖片導出, 在 fex-team 提供的 webuploader 插件當中有個 jpegencoder.js 和 androidpatch.js 插件主要是解決這個問題, 不過在部分 4.x 的機型, 在 webview 里面對 file 對象進行了閹割,比如你拿不到 file.type 的值。 唉- -。

2月22日更新

Android4.4 下 <input type="file"> 由于系統 WebView 的 openFileChooser 接口更改,導致無法選擇文件,從而導致無法上傳文件. 

使用

npm install
  npm run build
  • 支持AMD, CMD模塊化的引入方式
  • 也可通過外鏈
canvasResize(this.files[0], {
      crop: false,    // 是否裁剪
      quality: 0.9,   // 壓縮質量  0 - 1
      rotate: 0,      // 旋轉角度 
      callback(baseStr) {
        console.log(baseStr.length)
      }
    })

Some Tips

  • 在使用 FormData 進行文件上傳的時候,沒有將圖片文件轉化為 blob ,而是轉為了 base64 ,主要是考慮到部分機型的兼容性的問題。
  • 在遇到一些是由于 native 端上導致的問題的時候,比如在安卓 4.4.x 的部分機型(主要集中在原生的系統,部門國產機,對 openFileChooser 做過兼容)當中無法喚起選擇圖片或拍照的接口, 這個時候還是讓 native 的同學給你提供 bridge 去完成圖片的壓縮和轉碼吧, 然后你再拿著端上給壓縮好的圖片去上傳吧。
  • 封裝好的庫中沒有提供裁剪的選項,如果需要有這方面的需求,請在 src/canvasResize.js 里面做相應的修改(讀讀源碼也挺好- -)。

使用到的庫

 

來自:https://github.com/CommanderXL/imgResize/blob/master/README.md

 

 本文由用戶 nkslixin 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!