canvas图片压缩

用canvas实现图片压缩, 主要原理是获取图片真实宽高, 然后进行等比缩放, 最后用canvas进行绘制

代码

<input type="file" id="upload" />
const upload = document.getElementById('upload')
const ACCEPT = ['image/png', 'image/jpg', 'image/jpeg']
const MAXSIZE = 1024 * 1024 * 3
const MAXSIZE_STR = '3MB'

/* 转换为base64 */
function coverImageToBase64(file, cb) {
  let reader = new FileReader()
  reader.addEventListener('load', (e) => {
      const base64Image = e.target.result
      cb && cb(base64Image)
      reader = null
  })
  reader.readAsDataURL(file)
}

/* 压缩核心方法 */
function compress(base64Image, cb) {
  const image = new Image()
  let max_width = 1024
  let max_height = 1024
  image.addEventListener('load', (e) => {
    // 压缩比
    let ratio
    // 是否压缩
    let needCompress = false

    if (image.naturalWidth > max_width) {
      needCompress = true
      ratio = image.naturalWidth / max_width
      // 同步压缩高度
      max_height = image.naturalHeight / ratio
    }

    if (image.naturalHeight > max_height) {
      needCompress = true
      ratio = image.naturalHeight / max_height
      max_width = image.naturalWidth / ratio
    }

    // 不需要压缩获取图片实际宽高
    if (!needCompress) {
      max_width = image.naturalWidth
      max_height = image.naturalHeight
    }

    const canvas = document.createElement('canvas')
    canvas.setAttribute('id', '_compress_')
    canvas.width = max_width
    canvas.height = max_height
    canvas.style.visibility = 'hidden'
    document.body.appendChild(canvas)

    const ctx = canvas.getContext('2d')
    // 清除空间内的像素
    ctx.clearRect(0, 0, max_width, max_height)
    ctx.drawImage(image, 0, 0, max_width, max_height)
    // 输出压缩的base64格式
    const compressImage = canvas.toDataURL('image/jpeg', 0.9)
    cb && cb(compressImage)

    const _image = new Image()
    _image.src = compressImage
    document.body.appendChild(_image)

    canvas.remove()
    // console.log('压缩比: ', image.src.length / _image.src.length)
  })
  image.src = base64Image
  document.body.appendChild(image)
}

/* 上传 */
function uploadToServer(compressImg) {
  return 'success'
}

/* 检查上传文件 */
upload.addEventListener('change', () => {
  const [file] = e.target.files
  if (!file) return
  const {
    type: fileType,
    size: fileSize
  } = file
  if (!ACCEPT.includes(fileType) < 0) {
    alert(`不支持${fileType}类型的图片`)
    return
  }
  if (fileSize > MAXSIZE) {
    alert(`文件超出${MAXSIZE_STR}`)
    upload.value = ''
    return
  }
  coverImageToBase64(file, (base64Img) => compress(base64Img, uploadToServer))
})