移動端原生JS上傳圖片(含圖片壓縮和方向處理、ajax上傳)

基本思路

  • 監聽 input file 的 change 事件,獲取到上傳的文件信息
  • 使用 FileReader 對象讀取文件的 base64 格式,賦值給 img 顯示
  • 將圖片繪製在 canvas 上,控制圖片繪製的寬度,超過寬度,等比縮放。
  • 利用 exif.js 獲取圖片的方向信息,解決 ios 上豎直照片翻轉

基礎代碼

你只須要一個簡簡單單的 input 便可,固然,要顯示預覽圖片,確定還須要一個 img 標籤。此外,原生的 input 標籤比較醜,爲了美觀起見,通常都會把 input 透明度設置成 0,而後自定義個按鈕的樣式蓋在上面,樣式這裏就不詳細講了,easy。node

<input type="file" name="image" accept=「image/*」 onchange='handleInputChange' id="upload-img">
<img src="" class="prev-img">

兼容性

  • 安卓上不支持 multiple 屬性,即不能一次多選
  • 由於調用的是系統原生的文件讀取,每一個機型顯示的頁面不同,難以測試

完整的封裝 Class 以下,若是不須要壓縮或者方向處理,直接註釋便可。ios

export default class Uploader {
  constructor() {

  }

  /**
   * 把base64格式轉化成Blob格式
   * @param  {[type]} urlData [description]
   * @return {[type]}         [description]
   */
  convertBase64UrlToBlob(urlData) {
    var arr = urlData.split(','),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {
      type: mime
    });
  }

  /**
   * 外部調用的方法 完成圖片的壓縮
   * @param  {[type]}   file     須要處理的file對象
   * @param  {[type]}   obj      傳入的配置 quality 壓縮的質量
   * @param  {Function} callback 完成壓縮以後的回調函數
   * @return {[type]}            [description]
   */
  photoCompress(file, obj, callback) {
    // 使用HTML5的FileReader開始讀取File對象中的內容
    let setting = obj;
    var ready = new FileReader();
    ready.readAsDataURL(file);
    var that = this;
    // 判斷圖片需不須要壓縮
    if (file.size / 1024 < 500) {
      setting.quality = .9;
    } else {
      setting.quality = .5;
    }
    
    // 獲取圖片源信息 判斷照片方向
    ready.onload = function () {
      var _this2 = this;
      that.getOrientation(file).then(function(o){
      // setting.orientation = EXIF.getTag(file, "Orientation");
      setting.orientation = o;
      var re = _this2.result;
      that.canvasDataURL(re, setting, callback, file)
      })
    }
    


  }

  /**
   * canvas繪製
   * @param  {[type]}   result     [description]
   * @param  {[type]}   obj      [description]
   * @param  {Function} callback [description]
   * @return {[type]}            [description]
   */
  canvasDataURL(result, obj, callback, file) {
    var img = new Image();
    img.src = result;
    var _this = this;
    img.onload = function() {
      var that = this;
      var w, h, scale, quality;
      scale = that.width / that.height;
      if (that.width > 1200) {
        w = 1200;
        h = w / scale;
      } else {
        w = that.width;
        h = that.height;
      }
      //生成canvas
      var canvas = document.createElement('canvas');
      var ctx = canvas.getContext('2d');
      // 建立屬性節點
      var anw = document.createAttribute("width");
      anw.nodeValue = w;
      var anh = document.createAttribute("height");
      anh.nodeValue = h;
      canvas.setAttributeNode(anw);
      canvas.setAttributeNode(anh);
      // 調整圖片方向
      // console.log(obj.orientation)
      if (obj.orientation && obj.orientation != "" && obj.orientation != 1) {
        switch (obj.orientation) {
          case 6: //須要順時針(向左)90度旋轉
            _this.rotateImg(that, w, h, 'left', canvas, ctx);
            break;
          case 8: //須要逆時針(向右)90度旋轉
            _this.rotateImg(that, w, h, 'right', canvas, ctx);
            break;
          case 3: //須要180度旋轉
            _this.rotateImg(that, w, h, 'right', canvas, ctx); //轉兩次
            _this.rotateImg(that, w, h, 'right', canvas, ctx);
            break;
        }
      } else {
        ctx.drawImage(that, 0, 0, w, h);
      }
      // 壓縮圖像質量
      var base64 = canvas.toDataURL('image/jpeg', obj.quality);
      // 回調函數返回base64的值
      callback(base64);
    }

  }

  getObjectURL(file) {
    var url = null;
    if (window.createObjectURL != undefined) {
      url = window.createObjectURL(file);
    } else if (window.URL != undefined) { // mozilla(firefox)
      url = window.URL.createObjectURL(file);
    } else if (window.webkitURL != undefined) { // webkit or chrome
      url = window.webkitURL.createObjectURL(file);
    }
    return url;
  }


  rotateImg(img, w, h, direction, canvas, ctx) {
    //最小與最大旋轉方向,圖片旋轉4次後回到原方向
    var min_step = 0;
    var max_step = 3;
    //var img = document.getElementById(pid);
    if (img == null) return;
    //img的高度和寬度不能在img元素隱藏後獲取,不然會出錯
    var height = h;
    var width = w;
    //var step = img.getAttribute('step');
    var step = 2;
    if (step == null) {
      step = min_step;
    }
    if (direction == 'right') {
      step++;
      //旋轉到原位置,即超過最大值
      step > max_step && (step = min_step);
    } else {
      step--;
      step < min_step && (step = max_step);
    }
    //旋轉角度以弧度值爲參數
    var degree = step * 90 * Math.PI / 180;
    // var ctx = canvas.getContext('2d');
    // alert(h)
    switch (step) {
      case 0:
        canvas.width = width;
        canvas.height = height;
        ctx.drawImage(img, 0, 0);
        break;
      case 1:
        canvas.width = height;
        canvas.height = width;
        ctx.rotate(degree);
        ctx.drawImage(img, 0, -height,w,h);
        break;
      case 2:
        canvas.width = width;
        canvas.height = height;
        ctx.rotate(degree);
        ctx.drawImage(img, -width, -height,w,h);
        break;
      case 3:
        canvas.width = height;
        canvas.height = width;
        ctx.rotate(degree);
        ctx.drawImage(img, -width, 0,w,h);
        break;
    }
  }

  ajaxThen(data) {
    return new Promise((resolve, reject) => {
      var form = new FormData();
      form.append('image', data);
      // console.log(data,form)
      $.ajax({
        url: '/home/image',
        data: form,
        method: 'post',
        dataType: 'json',
        contentType: false,
        processData: false,
        mimeType: "multipart/form-data",
        success: function(res) {
          resolve(res)
        }
      })
    })

  }

  getOrientation(file) {
    return new Promise((resolve, reject) => {
      EXIF.getData(file, () => {
        let o = EXIF.getTag(file, "Orientation");
        resolve(o);
        reject(o);
      })
    })
  }
}
相關文章
相關標籤/搜索