JS 压缩图片

由于用户上传的图片大小不固定,为了节约带宽,前端需要做个图片压缩再上传到服务器。

注意:本文中图片压缩方法只能将压缩后的图片固定保存为 “image/jpeg” 格式,不能设置为 “image/png” 格式(该格式压缩无效)。

具体代码如下

压缩相关的方法:

/**
 * 文件转base64
 * @param {File} file 需要转换的文件
 * @param {Function} callback 回调函数, 执行回调后返回 base64 格式图片
 */
export function imageToBase64(file, callback) {
  const reader = new FileReader()
  reader.readAsDataURL(file) // 文件转base64
  reader.addEventListener('load', e => {
    callback && callback(e.target.result)
  })
}

/**
 * base64 类型转 Blob 类型
 * @param {base64} base64
 * @returns {Blob} blob
 */
export function base64ToBlob(base64) {
  let arr = base64.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new Blob([u8arr], { type: mime })
}

/**
 * 压缩图片
 * @param {base64} originalImage 转换为 base64 的原始图片
 * @param {Number} compressRatio 压缩比例 0 - 1, 1则不压缩
 * @param {Function} callback 回调方法, 执行回调后返回 base64 格式图片
 */
export function compressImg(originalImage, compressRatio = 1, callback) {
  const image = new Image()
  image.src = originalImage

  /* 监听图片的load事件 */
  image.addEventListener('load', function() {
    let [sizeRatio, maxWidth, maxHeight] = [0, 1024, 1024] // 图片压缩宽高比例和最大宽高
    let [imageWidth, imageHeight] = [this.naturalWidth, this.naturalHeight] // 图片实际宽高
    let compressFlag = false // 图片是否需要压缩

    // 如果图片宽度大于最大宽度就等比压缩图片的高度
    if (imageWidth > maxWidth) {
      compressFlag = true
      sizeRatio = imageWidth / maxWidth
      maxHeight = imageHeight / sizeRatio
    }

    // 如果图片高度大于最大高度就等比压缩图片的宽度
    if (imageHeight > maxHeight) {
      compressFlag = true
      sizeRatio = imageHeight / maxHeight
      maxWidth = imageWidth / sizeRatio
    }

    // 如果不需要压缩
    if (!compressFlag) {
      maxWidth = imageWidth
      maxHeight = imageHeight
    }

    // 使用canvas压缩图片
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    canvas.setAttribute('id', 'canvas')
    canvas.width = maxWidth
    canvas.height = maxHeight
    ctx.clearRect(0, 0, maxWidth, maxHeight) // 清除画布内所有像素
    ctx.drawImage(image, 0, 0, maxWidth, maxHeight) // canvas绘制当前图片
    const compressImage = canvas.toDataURL('image/jpeg', compressRatio) // 设置压缩类型和压缩比例获取压缩后的文件, 为 base64

    callback && callback(compressImage)
  })
}

业务中使用,我这里用的 vue,这里只展示了部分代码(大家只需关注 isCompressImg 方法)


    beforeRead(file) {
      if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
        this.$toast('请上传 jpg 或 png 格式图片')
        return false
      }
      return true
    },
    afterRead(file) {
      file.status = 'uploading'
      file.message = '上传中...'
      this.btnDisabled = true
      const imgFile = file.file
      this.isCompressImg(imgFile, img => {
        // 此时可以自行将文件上传至服务器
        alyOSS
          .ossUploadFile({ file: img })
          .then(res => {
            this.fileList = [
              {
                url: res.url
              }
            ]
            file.status = 'done'
            file.message = ''
          })
          .catch(() => {
            file.status = 'failed'
            file.message = '上传失败'
          })
          .finally(() => {
            this.btnDisabled = false
          })
      })
    },
    // 判断是否需要压缩
    isCompressImg(file, callback) {
      const maxSize = 1 * 1024 * 1024 // 最大 1M
      // 压缩图片
      if (file.size > maxSize) {
        imageToBase64(file, originalImage => {
          compressImg(originalImage, 0.5, compressImage => {
            // base64 转 blob, blob 再转 file
            const img = new File([base64ToBlob(compressImage)], file.name, {
              type: file.type
            })
            // 递归判断, 防止压缩后的图片仍然大于 1M
            this.isCompressImg(img, f => {
              callback(f)
            })
          })
        })
      } else {
        callback(file)
      }
    },
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值