zoukankan      html  css  js  c++  java
  • 使用FormData数据做图片上传: new FormData() canvas实现图片压缩

    使用FormData数据做图片上传: new FormData()       canvas实现图片压缩

    ps: 千万要使用append不要用set   苹果ios有兼容问题导致数据获取不到,需要后台接口支持formData数据 Content-Type: multipart/form-data

     正确的打开方式:formdata.append('file', file)

    错误的打开方式:formData.set(name,value) 

    //html代码
    <div class="sendImage" slot="label">
                  <input type="file" name="file" accept="image/*" ref="ndImgUpload"
                         class="upload_input" @change="imgSelectChange">
                </div>
    
    
    
    //**************javascript代码 Begin**********************
    
    //************* tool.js文件   canvas实现图片压缩***********
    
    //    用于压缩图片的canvas
    let canvas = document.createElement("canvas");
    let ctx = canvas.getContext('2d');
    //    瓦片canvas
    let tCanvas = document.createElement("canvas");
    let tctx = tCanvas.getContext("2d");
    
    
     // /**
     //  *  ************ js图片压缩类*****************
     // */
    export function compress (img) {
      let initSize = img.src.length;
      let width = img.width;
      let height = img.height;
    
    //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
      let 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 = "#fff";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    //如果图片像素大于100万则使用瓦片绘制
      let count;
      if ((count = width * height / 1000000) > 1) {
        count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片
    
    //            计算每块瓦片的宽和高
        let nw = ~~(width / count);
        let 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);
      }
    
      //进行压缩toDataURL:值越小,压缩力度越大
      let ndata = canvas.toDataURL('image/jpeg', 0.7);
    
      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;
    }
    
    /**
     * 将以base64的图片url数据转换为Blob
     * @param urlData
     * 用url方式表示的base64图片数据
     */
    export function convertBase64UrlToBlob (urlData) {
      let arr = urlData.split(','), mime = arr[0].match(/:(.*?);/)[1],
        bstr = window.atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], {type: mime});
    }
    
    
    
    
      /**
       *  ***********业务代码开始************
       */
    
      import {compress, convertBase64UrlToBlob} from 'utils/tool'
      const UPLOAD_IMG_SIZE = 10          //图片上传大小不能大于10M
      const IMG_NEED_COMPRESS_SIZE = 0.5  //图片大小<=0.5M,则不压缩,直接上传
      const SELECT_IMG_QUANTITY = 9       //发送消息图片最多选9张
    
    
    //  *************vue代码  ***************
    
    methods:{
     imgSelectChange (e) {
            this.$vux.loading.show({
              text: 'Loading'
            })
    
            let file = e.target
    
            setTimeout(() => { //加500ms定时器是为了防止大质量图片上传会造成卡顿loading会延迟执行
              this.sendImgIndex = 0
    
              if (file.files.length > SELECT_IMG_QUANTITY) {
                this.$vux.loading.hide()
                return this.$vux.alert.show({
                  title: '提示',
                  content: '最多选9张图片',
                  onHide () {
                    file.value = ''
                  }
                })
              }
    
              for (let obj of Array.from(file.files)) {
    
                if (!//(?:jpeg|png|gif|jpg)/i.test(obj.type)) {
                  this.$vux.loading.hide()
                  return this.$vux.alert.show({
                    title: '提示',
                    content: `${obj.name}不是图片文件类型`,
                    onHide () {
                      file.value = ''
                    }
                  })
                }
    
                let calcSize = obj.size / 1024 / 1024
                if (calcSize > UPLOAD_IMG_SIZE) {
                  this.$vux.loading.hide()
                  return this.$vux.alert.show({
                    title: '提示',
                    content: `图片大小不能大于${UPLOAD_IMG_SIZE}M`,
                    onHide () {
                      file.value = ''
                    }
                  })
                }
    
              }
    
              const imgLen = file.files.length
              this.eachSendImg(file.files, file, (data) => {
    
                //msgType 0系统 1文字 2图片 3音频 4视频 5回撤
                this.sendMsgHandle(2, data, () => {
                  this.sendImgIndex === imgLen && this.$vux.loading.hide()
                }, () => {
                  this.sendImgIndex === imgLen && this.$vux.loading.hide()
                  this.$vux.alert.show({
                    title: '提示',
                    content: `图片${file.files[this.sendImgIndex - 1].name}发送消息失败`
                  });
                })
    
              }, (err) => {
    
              })
            }, 500)
          },
     eachSendImg (files, input, success, error) {
            if (!files.length) return
            let that = this
            let args = arguments
    
            that.sendImg(files[that.sendImgIndex]).then(data => {
              success(data)
              that.sendImgIndex++
              files[that.sendImgIndex] ? that.eachSendImg.apply(that, args) : input.value = ''
    
            }).catch(err => {
              that.$vux.loading.hide()
    
              let txt_tip = err.msg === 'FILE_WRONG_SIZE' ? `图片${files[that.sendImgIndex].name}文件过大,上传失败`
                : `图片${files[that.sendImgIndex].name}上传失败`;
    
              that.$vux.alert.show({
                title: '提示',
                content: txt_tip,
                onHide () {
                  error(err)
                  that.sendImgIndex++
    
                  if (files[that.sendImgIndex]) {
                    that.$vux.loading.show({
                      text: 'Loading'
                    })
                    that.eachSendImg.apply(that, args)
                  } else {
                    input.value = ''
                  }
    
                }
              })
    
            })
    
          },
     sendImg (file) {
    
            let formdata = new FormData(); // FormData 对象
            let that = this
    
            return new Promise((resolve, reject) => {
    
              if (file.size / 1024 / 1024 <= IMG_NEED_COMPRESS_SIZE) {
    
                formdata.append('file', file)
                that.sendImgAjax(formdata).then((res) => {
                  resolve(res)
                }).catch((err) => {
                  reject(err)
                })
                return;
              }
    
              let reader = new FileReader();
              reader.onload = function () {
                let result = this.result;
                let img = new Image();
                img.src = result;
    
                //   图片加载完毕之后进行压缩,然后上传
                if (img.complete) {
                  let data = compress(img);
    
                  let blob = convertBase64UrlToBlob(data);
                  formdata.append("file", blob, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
                  that.sendImgAjax(formdata).then((res) => {
                    resolve(res)
                  }).catch((err) => {
                    reject(err)
                  })
    
                  img = null;
                } else {
                  img.onload = () => {
                    let data = compress(img);
    
                    let blob = convertBase64UrlToBlob(data);
                    formdata.append("file", blob, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
                    that.sendImgAjax(formdata).then((res) => {
                      resolve(res)
                    }).catch((err) => {
                      reject(err)
                    })
    
                    img = null;
                  };
                }
    
              }
              reader.readAsDataURL(file);
            })
          },
     sendImgAjax (formData) {
            return new Promise((resolve, reject) => {
              getData.common.form_uploadImg({
                data: formData,
                sucCb (data) {
                  resolve(data)
                },
                failCb (err) {
                  reject(err)
                }
              })
            })
          },
     sendMsgHandle (type, msg, success, error) {//发送消息
            if (!this.inputVal.trim() && !msg) return this.$vux.toast.text('消息内容不能为空');
            this.disabled = true
    
            this.$vux.loading.show({
              text: 'Loading'
            })
    
            if (this.query.groupId) {
              let that = this
              getData.doctor.group_chat_send_msg({
                params: {
                  gid: that.query.groupId,
                  //msg{1 || 0} :如果是图片上传,数据转为字符串,包含宽高url,msgType
                  msg: msg ? JSON.stringify(msg) : that.inputVal,
                  type //msgType 0系统 1文字 2图片 3音频 4视频 5回撤
                },
                sucCb (data) {
                  msg && (data.msg = JSON.parse(data.msg)) //如果是图片上传,msg消息数据为对象转的字符串
                  that.data.push({
                    chatid: data.uid,
                    from: data.uid,
                    content: msg ? data.msg.url : data.msg,
                     msg ? data.msg.width : 0,
                    height: msg ? data.msg.height : 0,
                    create_time: data.date,
                    avatar: data.pic,
                    name: data.nick,
                    group_id: data.gid,
                    msg_id: data.id,
                    msg_type: data.type
                  })
    
                  that.addPrevTimeData()
                  that.setLocalData(that.query.groupId, that.data.slice(-1))
    
                  type !== 2 && that.$vux.loading.hide()
                  that.disabled = false
                  that.inputVal = ''
    
                  success && success()
                },
                failCb (err) {
                  type !== 2 && that.$vux.loading.hide()
                  that.disabled = false
                  let overtime = err.code * 1 === 0
    
                  if (that.inGoBackError(err.code) || overtime) {
                    type === 2 && that.$vux.loading.hide()
    
                    that.$vux.alert.show({
                      title: '提示',
                      content: overtime ? '发送失败,请检查网络' : err.code === 'USER_NOT_IN_GROUP' ? '您已被移出群聊' : err.msg,
                      onHide () {
                        !overtime && that.$router.replace({
                          path: '/spa/msgGroup'
                        })
                      }
                    });
                  } else if (type === 2) {
                    error && error()
                  } else {
                    that.$vux.loading.hide()
                    that.$vux.alert.show({
                      title: '提示',
                      content: '消息发送失败'
                    });
                  }
    
                }
              })
            }
          }
        
    }
    

      

  • 相关阅读:
    第二部分 设计类型:第8章 方法
    centos7 网卡重命名
    centos7修改主机名
    修改umask值
    mysql表字段属性
    mysql基础操作
    mysql错误代码ERROR 1045 (转载)
    sed高级用法
    shell拷贝原文件到目标对应文件夹
    函数(位置传参)
  • 原文地址:https://www.cnblogs.com/MrZouJian/p/9099238.html
Copyright © 2011-2022 走看看