前端图片压缩

379 阅读1分钟

背景

开发上传身份证的功能,图片太大时上传等待时间很久,在前端限制了图片的大小。但是还有一种方法就是前端做一次图片压缩,然后再上传。就可以解决这个问题。先介绍一下如下的几个概念:

FileReader

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

FileReader.readAsDataURL()

开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的Base64字符串以表示所读取文件的内容。

Canvas toDataURL

toDataURL()是canvas对象的一种方法,用于将canvas对象转换为base64位编码;

总体流程

将选取到的文件,通过Canvas toDataURL()转为base64格式,然后将base64转为blob格式,将blog格式转为File文件,传递给后端。至此完成了图片的压缩。

const convertBase64UrlToBlob = (urlData:any) => {
  const arr = urlData.split(',')
  const mime = arr[0].match(/:(.*?);/)[1]
  const bstr = atob(arr[1]) // atob方法用于解码base64
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new Blob([u8arr], {
    type: mime
  })
}

const compressImgQuality = (file, quality = 1) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => {
      const img = new Image()
      const canvas = document.createElement('canvas')
      const drawer = canvas.getContext('2d')
      img.src = reader.result as string

      // 图片压缩代码,需要注意的是,img图片渲染是异步的,所以必须在img的onlaod钩子中再进行相应操作
      img.onload = function () {
        canvas.width = img.width
        canvas.height = img.height
        drawer.drawImage(img, 0, 0, canvas.width, canvas.height)
        const blob = convertBase64UrlToBlob(canvas.toDataURL(file.type, quality))
        const resultFiles = new File([blob], file.name, { type: file.type })
        resolve(resultFiles)
      }
    }
  })
}