图片裁剪+base64转file对象+前端上传OSS

1,768 阅读2分钟

「今天实习的时候遇到了上传图片到阿里OSS的需求。过程波折,学习到了很多,遂有此篇。

需求背景:\color{skyblue}{需求背景:}

后台页面上传图片以及简介,前台进行展示。

出现的问题:\color{skyblue}{出现的问题:}

后台上传原图后,前台由于布局的原因进行展示的时候总会拉伸图片或者展示不全

原图:

zheng.png

拉伸后的图片:

bian.png

最初的解决办法:\color{skyblue}{最初的解决办法:}

上传图片后把图片隐藏,再进行图片的长宽获取,算出比例后,判断图片是否合规要求。

这里利用fixed隐藏图片


<img :src="hiddenImgUrl" alt="" class="hiddenImg" >

.hiddenImg {
  position: fixed;
  bottom: -99999px;
}

调用getImgWidthHeight方法算出图片的比例


   //...上传的逻辑
   
  const imgres: any = await getImgWidthHeight(hiddenImgUrl.value)
  if (imgres > 0.6 && imgres < 0.9) {
  } else {
    Common.ElMessageWarning('图片宽高比例不合要求,照片宽高比例约为3:4')
    loading.close();
    return
  }

异步的getImgWidthHeight方法

maxWaitLoad为超时时间

async function getImgWidthHeight(src, maxWaitLoad = 2500) {
  return new Promise((resolve, reject) => {
    let img = new Image();
    img.src = src;
    if (img.complete) {
      const { width, height } = img;
      resolve(width / height);
    } else {
      let timeOut = setTimeout(() => {
        reject("图片加载失败!");
      }, maxWaitLoad);
      img.onload = function () {
        const { width, height } = img;
        window.clearTimeout(timeOut);
        resolve(width / height);
      }
    }
  })
}

这样 当用户上传的图片比例不在约束范围内的时候就会提示用户图片比例不合要求。

出现的问题:\color{skyblue}{出现的问题:}

这样虽然解决了图片的展示的问题,但是上传人员的体验十分不好。于是有了像裁剪头像一样图片裁剪的需求。

最终解决办法:\color{skyblue}{最终解决办法:}

贴一个大佬的图片裁剪组件GitHub - acccccccb/vue-img-cutter

import ImgCutter from 'vue-img-cutter'

<ImgCutter rate="3:4" :cutWidth="300" :cutHeight="400" @cutDown="cutDown" ></ImgCutter>

const cutDown = (res) => {
  //res是裁剪后图片的base64的url,以及源文件名等数据
  easyUpload(res).then(res2 => {
  //调用上传oss的easyUpload方法,进行base64解码,最后进行上传oss
    data.image={
      name: res2,
      url: res.fileName
    }
    //获得上传后的url,赋值给formData.photo传给后端
    formData.photo = data.image
  })
}
//...url传给后端的逻辑

上传阿里云oss\color{skyblue}{上传阿里云oss:}

拿到token后获得自己阿里云的AccessKeyId,AccessKeySecret,region,bucket 文档里有写怎么获取,这里就不赘述了) 由于oss只能接收file对象、Blob数据或者OSS Buffer。所以这里还需要给base64转成file对象

这里贴一下阿里云的官方文档(简单上传 (aliyun.com))

function easyUpload(data) {
    return new Promise((reslove, reject) => {
      try {
        getClient().then(client => {  //获取 阿里云oss的token 拿AccessKeyId
          client.put(  //调用阿里云提供的方法
            getRandomFileName(data.file.type),  //获取一个随机的文件名
            blobToFile(base64ToBlob(data.dataURL), data.fileName),   //base64转file对象
            { 'Content-Type': 'image/jpeg' }  //设置Content-Type
          ).then(res => {
            reslove(res.url)
          })
        })
      } catch (e) {
        reject(e)
      }
    })
  }

base64file对象:\color{skyblue}{base64转file对象:}


 base64ToBlob = (base64Data) => {
    let arr = base64Data.split(","),
      fileType = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      l = bstr.length,
      u8Arr = new Uint8Array(l);
      while (l--) {
        u8Arr[l] = bstr.charCodeAt(l);
      }
    return new Blob([u8Arr], {
      type: fileType
    });
  };
  blobToFile = function (newBlob, fileName) {
    newBlob.lastModifiedDate = new Date();
    newBlob.name = fileName;
    return newBlob;
  }

通过这个需求学到了很多,继续加油