做H5页面,调用相册图片文件太大,怎么实现上传缩略图或者压缩图

做H5页面,调用相册图片文件太大,怎么实现上传缩略图或者压缩图

阅读 6.8k
3 个回答

趁着中午,大致代码的我写一下,供参考:

// 上传函数
function upload(e) {
    var file = e.target.files[0];
    if (!file) return; // 未上传
    var orientation; // 图片上传的角度,解决
    /**
    * 利用exif.js解决ios手机上传竖拍照片旋转90度问题
    * 详见  http://code.ciaoca.com/javascript/exif-js/
    */ 
    EXIF.getData(file, function () { // 获取照片方向角属性,用户旋转控制  
      orientation = EXIF.getTag(this, 'Orientation');
    });
    var reader = new FileReader(); // 读取文件
    reader.onload = function () {
      getImgData(this.result, orientation, function (result) {
        var img = new Image();
        img.src = result;
        // 如果图片大小小于200kb,则直接上传
        if (result.length <= that.minSize) {
          ajaxUpload(result, file.type, file.name); // 调用上传接口函数
          img = null;
          return;
        }
        // 图片加载完毕之后进行压缩,然后上传
        if (img.complete) {
          callback();
        } else {
          img.onload = callback;
        }
        function callback () {
          var data = compress(img);
          // 文件上传
          ajaxUpload(data, file.type, file.name);
          img = null;
        }
      })
    }
    reader.readAsDataURL(file);
}

/**
 * 图片上传,将base64的图片转成二进制对象,塞进formdata上传
 * @param {*} basestr
 * @param {*} type
 */
function ajaxUpload (basestr, type, name) {
  var text = window.atob(basestr.split(',')[1]);
  var buffer = new Uint8Array(text.length);
  for (var i = 0; i < text.length; i++) {
    buffer[i] = text.charCodeAt(i);
  }
  var blob = getBlob([buffer], type);
  var xhr = new XMLHttpRequest();
  var formdata = getFormData();
  formdata.append('multipartFile', blob, name)
  // append 追加还追加其他参数
  xhr.open('post', '请求的url')
  xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
          var jsonData = JSON.parse(xhr.responseText)
          // 接口返回的 json 数据 自行解析
      }

      if (xhr.status !== 200) {
        // 通信失败
     }
  }
  xhr.send(formdata)
}

/**
   * 使用canvas对大图片进行压缩
   * @param {img} 图片
   */
function compress (img) {
    // 用于压缩图片的canvas
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    // 瓦片canvas
    var tCanvas = document.createElement('canvas');
    var tctx = tCanvas.getContext('2d');
    // let initSize = img.src.length
    var width = img.width;
    var height = img.height;
    // 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
    var ratio;
    if ((ratio = width * height / 4000000) > 1) {
      ratio = Math.sqrt(ratio);
      width /= ratio;
      height /= ratio;
    } else {
      ratio = 1;
    }
    canvas.width = width;
    canvas.height = height;
    // 铺底色
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    // 如果图片像素大于100万则使用瓦片绘制
    var count;
    if ((count = width * height / 1000000) > 1) {
      count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片
      // 计算每块瓦片的宽和高
      var nw = ~~(width / count);
      var nh = ~~(height / count);
      tCanvas.width = nw;
      tCanvas.height = nh;
      for (let i = 0; i < count; i++) {
        for (let j = 0; j < count; j++) {
          tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
          ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
        }
      }
    } else {
      ctx.drawImage(img, 0, 0, width, height);
    }
    // 进行最小压缩
    var ndata = canvas.toDataURL('image/jpeg', 0.1);
    // console.log('压缩前:' + initSize)
    // console.log('压缩后:' + ndata.length)
    // console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%")
    tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
    return ndata;
}

/**
* 获取formdata
*/
function getFormData () {
    var isNeedShim = ~navigator.userAgent.indexOf('Android') && ~navigator.vendor.indexOf('Google') && !~navigator.userAgent.indexOf('Chrome') && navigator.userAgent.match(/AppleWebKit\/(\d+)/).pop() <= 534;
    return isNeedShim ? new this.FormDataShim() : new FormData();
}

/**
* formdata 补丁, 给不支持formdata上传blob的android机打补丁
* @constructor
*/
function FormDataShim () {
    var o = this;
    var parts = [];
    var boundary = Array(21).join('-') + (+new Date() * (1e16 * Math.random())).toString(36);
    var oldSend = XMLHttpRequest.prototype.send;
    this.append = function (name, value, filename) {
      parts.push('--' + boundary + '\r\nContent-Disposition: form-data; name="' + name + '"');
      if (value instanceof Blob) {
        parts.push('; filename="' + (filename || 'blob') + '"\r\nContent-Type: ' + value.type + '\r\n\r\n');
        parts.push(value);
      } else {
        parts.push('\r\n\r\n' + value);
      }
      parts.push('\r\n');
    };
    
    XMLHttpRequest.prototype.send = function (val) {
      var fr;
      var data;
      var oXHR = this;
      if (val === o) {
        parts.push('--' + boundary + '--\r\n');
        data = this.getBlob(parts);
        fr = new FileReader();
        fr.onload = function () {
          oldSend.call(oXHR, fr.result);
        }
        fr.onerror = function (err) {
          throw err;
        }
        fr.readAsArrayBuffer(data);
        this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
        XMLHttpRequest.prototype.send = oldSend;
      } else {
        oldSend.call(this, val);
      }
    }
}

/**
* 获取blob对象的兼容性写法
* @param buffer
* @param format
* @returns {*}
*/
function getBlob (buffer, format) {
    try {
      return new Blob(buffer, {type: format});
    } catch (e) {
      var bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder)();
      buffer.forEach(function (buf) {
        bb.append(buf);
      });
      return bb.getBlob(format);
    }
}

/**
* @param {string} img 图片的base64
* @param {int} dir exif获取的方向信息
* @param {function} next 回调方法,返回校正方向后的base64
*/
function getImgData (img, dir, next) {
    var image = new Image();
    image.onload = function () {
      var degree = 0;
      var drawWidth;
      var drawHeight;
      var width;
      var height;
      drawWidth = this.naturalWidth;
      drawHeight = this.naturalHeight;  // 以下改变一下图片大小
      var maxSide = Math.max(drawWidth, drawHeight);
      if (maxSide > 1024) {
        var minSide = Math.min(drawWidth, drawHeight);
        minSide = minSide / maxSide * 1024;
        maxSide = 1024;
        if (drawWidth > drawHeight) {
          drawWidth = maxSide;
          drawHeight = minSide;
        } else {
          drawWidth = minSide;
          drawHeight = maxSide;
        }
      }
      var canvas = document.createElement('canvas');
      canvas.width = width = drawWidth;
      canvas.height = height = drawHeight;
      var context = canvas.getContext('2d');  // 判断图片方向,重置canvas大小,确定旋转角度,iphone默认的是home键在右方的横屏拍摄方式
      switch (dir) {
        // iphone横屏拍摄,此时home键在左侧
        case 3:
          degree = 180
          drawWidth = -width
          drawHeight = -height
          break
        // iphone竖屏拍摄,此时home键在下方(正常拿手机的方向)
        case 6:
          canvas.width = height
          canvas.height = width
          degree = 90
          drawWidth = width
          drawHeight = -height
          break
        // iphone竖屏拍摄,此时home键在上方
        case 8:
          canvas.width = height
          canvas.height = width
          degree = 270
          drawWidth = -width
          drawHeight = height
          break
      }
      // 使用canvas旋转校正
      context.rotate(degree * Math.PI / 180)
      context.drawImage(this, 0, 0, drawWidth, drawHeight)
      // 返回校正图片
      next(canvas.toDataURL('image/jpeg', 0.8))
    }
    image.src = img
}

如果是微信端,建议调用微信的拍照上传,权限更多些!

希望对您有所帮助!

可以利用canvas对图片进行压缩之后再上传。或者你可以直接利用webuploader这个库

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题