开始总要说点啥
为了帮后端服务器分担一点压力啦!毕竟前端搞一些事情是在客户端搞,不行只能说客户电脑垃圾!
![img]
目标
- 1.按比例压缩
- 2.可配置化参数(压缩的宽高比,和质量)
- 3.异步的方式
思路
- 1.将前端通过表单拿到
File
对象 - 2.将
File
对象转为Img
可以渲染的Base64
- 3.我们去加载
Image
,拿到当前文件的原始宽高,去对比配置项的宽高,如果大于配置项的宽高则进行压缩,否则原图返回 - 4.如果需要压缩的话,我们就去计算当前需要被压缩的比率,得到一个压缩后的等比例宽高,然后根据这个宽高生成canvas画布
- 5.将我们的图片渲染到canvas上面,然后将canvas导出为一个
DataURL
,这个导出的图片就是按照我们宽高比压缩后的图片,也可以配置导出的质量参数
编码
;(function name(doc) {
const compressUtil = {}
function fileToBase64(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.addEventListener('load', (e) => {
resolve(e.target.result)
})
reader.readAsDataURL(file)
})
}
//拿到base64渲染的iMG,用来获取原图的宽高
function getNaturalDomForCalc(base64FileContext) {
return new Promise((resolve, reject) => {
const img = new Image()
img.src = base64FileContext
img.onload = function () {
resolve(img)
}
})
}
//计算压缩比率
function calcForCompressRate(img, compressConfig) {
for (key in compressConfig) {
this[key] = compressConfig[key]
}
return new Promise((resolve, reject) => {
let rate,
needToCompress = false,
originHeight = img.naturalHeight,
originWidth = img.naturalWidth
if (originWidth > this.width) {
needToCompress = true
rate = originWidth / this.width
originWidth = this.width
//如果它的宽度被压缩了,那么高度肯定要按比例进行压缩
originHeight = originHeight / rate
}
if (originHeight > this.height) {
needToCompress = true
rate = originHeight / this.height
originHeight = this.height
//如果它的宽度被压缩了,那么高度肯定要按比例进行压缩
originWidth = originWidth / rate
}
const canvas = doc.createElement('canvas')
canvas.width = originWidth
canvas.height = originHeight
canvas.style.display = 'none'
doc.body.appendChild(canvas)
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, originWidth, originHeight)
ctx.drawImage(img, 0, 0, originWidth, originHeight)
const compressedImg = canvas.toDataURL(this.fileType, this.quality)
doc.body.removeChild(canvas)
resolve(compressedImg)
})
}
function dataURLtoBlob(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 })
}
function compressImgToBase64(
file,
compressConfig = {
width: 100,
height: 100,
quality: 0.5, //0-1
fileType: 'image/jpeg',
}
) {
let isRightConfig = true
const RequiredConfigurationKeys = ['width', 'height', 'quality', 'fileType']
for (let key in compressConfig) {
RequiredConfigurationKeys.find((item) => item == key) ? '' : (isRightConfig = false)
}
if (!isRightConfig) {
throw new Error(
`Incorrect configuration. Please use a configuration in a format similar to this {width: 100,height: 100,quality: 0.5,fileType: 'image/jpeg',},Or, instead of passing the configuration, we'll use the default configuration\n 不正确的配置。请使用类似于{width: 100,height: 100,quality: 0.5,fileType: 'image/jpeg',}的格式配置,或者,我们将使用默认配置而不是传递的配置`
)
}
return new Promise(async (resolve, reject) => {
const base64Context = await fileToBase64(file)
const img = await getNaturalDomForCalc(base64Context)
const compressedImg = await calcForCompressRate(img, compressConfig)
resolve(compressedImg)
})
}
//向全局暴露唯一的工具
compressUtil.compressImgToBase64 = compressImgToBase64
compressUtil.base64toBlob = dataURLtoBlob
window.compressUtil = compressUtil
})(document)
怎么用
<body>
<input type="file" id='uploader' multiple></input>
</body>
通过form表单 input file 去上传文件 ,监听表单的change事件,然后触发我们的工具函数,传入file对象和配置对象(可以不传,内部有默认值)
uploader.addEventListener('change',handleToUpload)
function handleToUpload(e){
const files = e.target.files;
for(let file of files){
compressUtil.compressImgToBase64(file,{
width: 100,
height: 100,
quality: 1, //0-1
fileType: 'image/jpeg',
}).then(res=>{
console.log(res);
console.log(compressUtil.base64toBlob(res));
})
}
}
测试 搞一张2m
的图片来试一下
Good!
评论区