前端js壓縮圖片並上傳

公司最近有須要壓縮上傳圖片功能,查找了些資料並實現了一把。node

主要用到的原生組件:FileReader、Canvas、Blob、FormDataios

邏輯步驟:web

  1. FileReader.readAsDataURL將上傳的圖片文件轉爲Base64格式
  2. 將img繪製到canvas上,canvas.toDataURL壓縮圖片
  3. new Blob將壓縮後的Base64轉爲Blob格式
  4. FormData.append將圖片文件數據存入formdata

Code:ajax

this.compressImage(files[0], (file)=>{
    console.log(file);
    const formData = new FormData();
    formData.append('file', file, file.name || '上傳圖片.jpeg');
}, $.noop);
//壓縮圖片
compressImage = (file, success, error) => {
    // 圖片小於1M不壓縮
    if (file.size < Math.pow(1024, 2)) {
        return success(file);
    }

    const name = file.name; //文件名
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) => {
        const src = e.target.result;
        
        const img = new Image();
        img.src = src;
        img.onload = (e) => {
            const w = img.width;
            const h = img.height;
            const quality = 0.8;  // 默認圖片質量爲0.92
            //生成canvas
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            // 建立屬性節點
            const anw = document.createAttribute("width");
            anw.nodeValue = w;
            const anh = document.createAttribute("height");
            anh.nodeValue = h;
            canvas.setAttributeNode(anw);
            canvas.setAttributeNode(anh);

            //鋪底色 PNG轉JPEG時透明區域會變黑色
            ctx.fillStyle = "#fff";
            ctx.fillRect(0, 0, w, h);

            ctx.drawImage(img, 0, 0, w, h);
            // quality值越小,所繪製出的圖像越模糊
            const base64 = canvas.toDataURL('image/jpeg', quality); //圖片格式jpeg或webp能夠選0-1質量區間

            // 返回base64轉blob的值
            console.log(`原圖${(src.length/1024).toFixed(2)}kb`, `新圖${(base64.length/1024).toFixed(2)}kb`);
            //去掉url的頭,並轉換爲byte
            const bytes = window.atob(base64.split(',')[1]);
            //處理異常,將ascii碼小於0的轉換爲大於0
            const ab = new ArrayBuffer(bytes.length);
            const ia = new Uint8Array(ab);
            for (let i = 0; i < bytes.length; i++) {
                ia[i] = bytes.charCodeAt(i);
            }
            file = new Blob( [ab] , {type : 'image/jpeg'});
            file.name = name;

            success(file);
        }
        img.onerror = (e) => {
            error(e);
        }
    }
    reader.onerror = (e) => {
        error(e);
    }
}

遇到的一些坑:canvas

  1. PNG轉JPEG時PNG格式的透明區域會變黑色,須要先手動鋪底色
  2. toDataURL參數爲PNG時不支持傳圖片質量,因此須要寫死image/jpeg或image/webp,具體能夠參考toDataURL的api
  3. formData.append第三個參數filename是有瀏覽器兼容性問題的,若是不傳就是filename=blob,後端校驗文件名可能過不去
  4. ajax的contentType和processData須要傳false,這和本文關係不大直接帶過
  5. 網上說的ios中canvas繪製圖片大小限制我在iphone6上測試沒遇到,可能和機型或系統有關係,若是有能夠在下面留言

結語,壓縮功能比較適合移動端,畢竟PC端帶寬比較好並且不能兼容IE老版本。後端

相關文章
相關標籤/搜索