# 背景 {#背景}
随着手机像素越来越高,使用手机拍摄的照片动辄就是几兆或十几兆,在移动端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)
}
}