Skip to content

图片压缩

h5

js
const compressImg = file => {
  var files
  var fileSize = parseFloat(parseInt(file["size"]) / 1024 / 1024).toFixed(2)
  var read = new FileReader()
  read.readAsDataURL(file)
  return new Promise(function (resolve, reject) {
    read.onload = function (e) {
      var img = new Image()
      img.src = e.target.result
      img.onload = function () {
        // 默认按比例压缩
        var w = img.width
        var h = img.height
        // 生成canvas
        var canvas = document.createElement("canvas")
        var ctx = canvas.getContext("2d")
        var base64
        // 创建属性节点
        canvas.setAttribute("width", w)
        canvas.setAttribute("height", h)
        ctx.drawImage(img, 0, 0, w, h)
        if (fileSize < 1) {
          // 如果图片小于一兆 那么压缩0.5
          base64 = canvas.toDataURL(file["type"], 0.5)
        } else if (fileSize > 1 && fileSize < 2) {
          // 如果图片大于1M并且小于2M 那么压缩0.5
          base64 = canvas.toDataURL(file["type"], 0.5)
        } else {
          // 如果图片超过2m 那么压缩0.2
          base64 = canvas.toDataURL(file["type"], 0.2)
        }
        // 回调函数返回file的值(将base64编码转成file)
        files = dataURLtoFile(base64, file.name) // 如果后台接收类型为base64的话这一步可以省略
        resolve(files)
      }
    }
  })
}
// base64转码(压缩完成后的图片为base64编码,这个方法可以将base64编码转回file文件)
const dataURLtoFile = (dataurl, filename) => {
  var arr = dataurl.split(",")
  var mime = arr[0].match(/:(.*?);/)[1]
  var bstr = atob(arr[1])
  var n = bstr.length
  var u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], filename, {
    type: mime,
  })
}

h5.html

ts
function compressImg(file, quality) {
  var qualitys = 0.52
  console.log(parseInt((file.size / 1024).toFixed(2)))
  if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
    qualitys = 0.85
  }
  if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
    qualitys = 0.92
  }
  if (quality) {
    qualitys = quality
  }
  if (file[0]) {
    return Promise.all(Array.from(file).map(e => this.compressImg(e, qualitys))) // 如果是 file 数组返回 Promise 数组
  } else {
    return new Promise(resolve => {
      console.log(file)
      if ((file.size / 1024).toFixed(2) < 300) {
        resolve({
          file: file,
        })
      } else {
        const reader = new FileReader() // 创建 FileReader
        reader.onload = ({target: {result: src}}) => {
          const image = new Image() // 创建 img 元素
          image.onload = async () => {
            const canvas = document.createElement("canvas") // 创建 canvas 元素
            const context = canvas.getContext("2d")
            var targetWidth = image.width
            var targetHeight = image.height
            var originWidth = image.width
            var originHeight = image.height
            if (1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024) {
              var maxWidth = 1600
              var maxHeight = 1600
              targetWidth = originWidth
              targetHeight = originHeight
              // 图片尺寸超过的限制
              if (originWidth > maxWidth || originHeight > maxHeight) {
                if (originWidth / originHeight > maxWidth / maxHeight) {
                  // 更宽,按照宽度限定尺寸
                  targetWidth = maxWidth
                  targetHeight = Math.round(maxWidth * (originHeight / originWidth))
                } else {
                  targetHeight = maxHeight
                  targetWidth = Math.round(maxHeight * (originWidth / originHeight))
                }
              }
            }
            if (10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024) {
              maxWidth = 1400
              maxHeight = 1400
              targetWidth = originWidth
              targetHeight = originHeight
              // 图片尺寸超过的限制
              if (originWidth > maxWidth || originHeight > maxHeight) {
                if (originWidth / originHeight > maxWidth / maxHeight) {
                  // 更宽,按照宽度限定尺寸
                  targetWidth = maxWidth
                  targetHeight = Math.round(maxWidth * (originHeight / originWidth))
                } else {
                  targetHeight = maxHeight
                  targetWidth = Math.round(maxHeight * (originWidth / originHeight))
                }
              }
            }
            canvas.width = targetWidth
            canvas.height = targetHeight
            context.clearRect(0, 0, targetWidth, targetHeight)
            context.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
            const canvasURL = canvas.toDataURL("image/jpeg", qualitys)
            const buffer = atob(canvasURL.split(",")[1])
            let length = buffer.length
            const bufferArray = new Uint8Array(new ArrayBuffer(length))
            while (length--) {
              bufferArray[length] = buffer.charCodeAt(length)
            }
            const miniFile = new File([bufferArray], file.name, {
              type: "image/jpeg",
            })
            console.log({
              file: miniFile,
              origin: file,
              beforeSrc: src,
              afterSrc: canvasURL,
              beforeKB: Number((file.size / 1024).toFixed(2)),
              afterKB: Number((miniFile.size / 1024).toFixed(2)),
              qualitys: qualitys,
            })
            resolve({
              file: miniFile,
              origin: file,
              beforeSrc: src,
              afterSrc: canvasURL,
              beforeKB: Number((file.size / 1024).toFixed(2)),
              afterKB: Number((miniFile.size / 1024).toFixed(2)),
            })
          }
          image.src = src
        }
        reader.readAsDataURL(file)
      }
    })
  }
}

ts

ts
const fileToDataURL = (file: Blob): Promise<any> => {
  return new Promise(resolve => {
    const reader = new FileReader()
    reader.onloadend = e => resolve((e.target as FileReader).result)
    reader.readAsDataURL(file)
  })
}
const dataURLToImage = (dataURL: string): Promise<HTMLImageElement> => {
  return new Promise(resolve => {
    const img = new Image()
    img.onload = () => resolve(img)
    img.src = dataURL
  })
}
const canvastoFile = (canvas: HTMLCanvasElement, type: string, quality: number): Promise<Blob | null> => {
  return new Promise(resolve => canvas.toBlob(blob => resolve(blob), type, quality))
}
/**
 * 图片压缩方法
 * @param {Object}  file 图片文件
 * @param {String} type 想压缩成的文件类型
 * @param {Nubmber} quality 压缩质量参数
 * @returns 压缩后的新图片
 */
export const compressionFile = async (file, type = "image/jpeg", quality = 0.5) => {
  const fileName = file.name
  const canvas = document.createElement("canvas")
  const context = canvas.getContext("2d") as CanvasRenderingContext2D
  const base64 = await fileToDataURL(file)
  const img = await dataURLToImage(base64)
  canvas.width = img.width
  canvas.height = img.height
  context.clearRect(0, 0, img.width, img.height)
  context.drawImage(img, 0, 0, img.width, img.height)
  const blob = (await canvastoFile(canvas, type, quality)) as Blob // quality:0.5可根据实际情况计算
  const newFile = await new File([blob], fileName, {
    type: type,
  })
  return newFile
}