51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

JS图片压缩

# 背景 {#背景}

随着手机像素越来越高,使用手机拍摄的照片动辄就是几兆或十几兆,在移动端H5上传图片的场景,会造成流量的浪费。特别是在网络不好的情况下,更容易出现上传时间超长甚至是上传失败的问题。

为了提示图片上传体验,故需要在上传前对图片进行压缩。

# 图片压缩 {#图片压缩}

/**
 * 图片压缩
 * @param {File} file 文件
 * @param {Function} success 成功回调,返回压缩后文件
 * @param {File} error 失败回调,返回错误信息
 */
function compressImage(file, success, error) {
  // 图片小于1M不压缩
  if (file.size < Math.pow(1024, 2)) {
    return success(file)
  }

  const name = file.name // 文件名
  const reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onload = (e) => {
    const src = e.target.result

    const img = new Image()
    img.src = src
    img.onload = (e) => {
      const rate = img.width / 1000 > 1 ? img.width / 1000 : 1
      const w = img.width / rate
      const h = img.height / rate
      const quality = 0.9 // 默认图片质量为0.92
      // 生成canvas
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      canvas.width = w
      canvas.height = h
      console.log(w, h)
      // 铺底色 PNG转JPEG时透明区域会变黑色
      ctx.fillStyle = '#fff'
      ctx.fillRect(0, 0, w, h)
      ctx.drawImage(img, 0, 0, w, h)
      // quality值越小,所绘制出的图像越模糊
      const base64 = canvas.toDataURL('image/jpeg', quality) // 图片格式jpeg或webp可以选0-1质量区间
      // 去掉url的头,并转换为byte
      const bytes = window.atob(base64.split(',')[1])
      // 返回base64转blob的值
      console.log(`原图${(src.length / 1024).toFixed(2)}kb`, `新图${(bytes.length / 1024).toFixed(2)}kb`)
      // 处理异常,将ascii码小于0的转换为大于0
      const ia = new Uint8Array(bytes.length)
      for (let i = 0, len = bytes.length; i < len; i++) {
        ia[i] = bytes.charCodeAt(i)
      }
      file = new File([ ia ], name, { type: 'image/jpeg', lastModified: Date.now() })
      success(file)
    }
    img.onerror = (e) => {
      error(e)
    }
  }
  reader.onerror = (e) => {
    error(e)
  }
}
赞(2)
未经允许不得转载:工具盒子 » JS图片压缩