前言
上传图片对图片大小有要求,故需要前端压缩图片后再上传。简单的实现效果如下:
您可以点击这里:图片压缩
步骤
- 上传一张图片,进行校验,获取图片文件。
- 使用
FileReader
的readAsDataURL
方法将文件转成base64
字符串,即图片的url
- 使用
canvas
的drawImage
方法绘制图片,toDataURL
方法获取Data Url
,即可以实现压缩图片
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片压缩</title>
</head>
<body>
<input type="file" name="" id="file">
<input type="button" value="下载" id="download">
<div>图片压缩比:<span id="ratio"></span></div>
<script>
const fileEl = document.querySelector('#file')
const ratioEl = document.querySelector('#ratio')
const downloadEl = document.querySelector('#download')
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const body = document.body
// 压缩后的图片url
let compressUrl = ''
// 最大上传文件大小
const MAX_SIZE = 3 * 1024 * 1024
// 上传文件类型
const FILE_TYPES = ['image/jpeg', 'image/png']
// 上传文件最大宽度
const MAX_WIDTH = 1024
// 上传文件最大高度
const MAX_HEIGHT = 1024
// 上传文件最大宽高比
const MAX_WH_RATIO = MAX_WIDTH / MAX_HEIGHT
// 重置
function resetEl () {
const imgArr = body.querySelectorAll('img')
imgArr.forEach(v => {
body.removeChild(v)
})
ratioEl.innerHTML = ''
}
// 将文件转成base64
function convertFile2base64 (file) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.addEventListener('load', e => {
resolve(e.target.result)
reader = null
})
reader.readAsDataURL(file)
})
}
// 压缩图片
function compress (url, fileType) {
const img = new Image()
img.src = url
body.appendChild(img)
img.addEventListener('load', e => {
const {width: originWidth, height: originHeight} = e.target
// 原始宽高比
const originWHRatio = originWidth / originHeight
let targetWidth = originWidth
let targetHeight = originHeight
// 1、计算上传图片压缩后的宽高
// 2、绘制压缩后的图片
// 3、上传
if (originWidth > MAX_WIDTH || originHeight > MAX_HEIGHT) {
if (originWHRatio > MAX_WH_RATIO) {
// 图片更宽
targetWidth = MAX_WIDTH
targetHeight = Math.round(targetWidth / originWHRatio)
} else {
// 图片更高
targetHeight = MAX_HEIGHT
targetWidth = Math.round(targetHeight * originWHRatio)
}
}
// 图片压缩比
const ratio = originWidth / targetWidth
const newImg = document.createElement('img')
ratioEl.innerHTML = ratio
canvas.width = targetWidth
canvas.height = targetHeight
ctx.clearRect(0, 0, targetWidth, targetHeight)
// 绘制压缩的图片
ctx.drawImage(img, 0, 0, targetWidth, targetHeight)
// 获取 Data Url
compressUrl = canvas.toDataURL(fileType);
newImg.src = compressUrl
newImg.addEventListener('load', () => {
body.appendChild(newImg)
})
// body.appendChild(canvas)
})
}
fileEl.addEventListener('change', e => {
resetEl()
const [file] = e.target.files
if (!file) return
const {size: fileSize, type: fileType} = file
console.warn('file', file, fileSize, MAX_SIZE, fileType);
if (!FILE_TYPES.includes(fileType)) {
alert('只能上传图片')
fileEl.value = ''
return
}
if (fileSize > MAX_SIZE) {
alert('图片不能超过3M')
fileEl.value = ''
return
}
convertFile2base64(file).then(res => {
compress(res, fileType)
})
})
downloadEl.addEventListener('click', e => {
const a = document.createElement('a')
a.href = compressUrl
a.style.display = 'none'
a.download = '图片'
body.appendChild(a)
a.click()
a.remove()
})
</script>
</body>
</html>
参考
https://www.cnblogs.com/goloving/p/8260206.html
https://www.jianshu.com/p/f46195810c3b