上传图片到服务端是很常见的应用场景,由于图片尺寸不可控,在图像从前端传输给服务器之前,将图片压缩就显得很有意义,这样不仅可以节省带宽提高上传速率,还可以减轻服务器的存储压力。
这是我参与更文挑战的第10天,活动详情查看: 更文挑战
前端压缩,一般考虑两个维度:图片尺寸剪切和降低质量,本文将从这两点展开介绍。
图片剪切
关于图像剪切,我们需要借助ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
,通过原始图像、位置和尺寸信息重新生成一份新的图片数据:
- image。表示显示原始图像的
image
元素 - sx,sy。图片的剪切位置
- sWidth,sHeight。图片的剪切尺寸
- dx,dy。画布上的放置位置
- dWidth,dHeight。新图像的尺寸
再说回图片剪切:当dWidth、dHeight
小于sWidth、sHeight
时,图片的尺寸就减小了,自然也就达到了压缩的目的。
拿老婆的照片来做测试:
<img src="./wife.png" alt="">
<canvas width="254" height="419"></canvas>
<script>
var img = document.querySelector('img');
//等待图像加载完毕
img.onload = function(){
//获取图像的原始尺寸
var naturalImgSize = [img.naturalWidth,img.naturalHeight];
//设置新图像的尺寸(相对原始图像尺寸缩小一倍)
var finalImgSize = [naturalImgSize[0]/2,naturalImgSize[1]/2]
//获取画布上下文
var ctx = document.querySelector('canvas').getContext("2d");
//绘制改变尺寸后的图像到画布上
ctx.drawImage(img,0,0,naturalImgSize[0],naturalImgSize[1],0,0,finalImgSize[0],finalImgSize[1]);
}
</script>
效果图:
降低图像的质量
再说如何降低图像质量,这里我们需要借助一个方法:canvas.toBlob(callback, mimeType, qualityArgument);
- callback是转换成功后的回调函数
- mineType是将canvas转换图片的类型
- qualityArgument是图像转换的质量,是一个0-1的数字(仅当第二个参数mimeType为jpg或者webp格式时才有效)
接下来我们将之前缩小了一倍的canvas上的图像无损转换成Blob对象:
canvas.toBlob(blob=>{
console.log(blob)
},"image/jpeg",1)
可以看到最终的图像尺寸是102KB
,而原始图像是868KB
。压缩效果非常明显。
不过,如果我们需要对图片的size进行限制怎么办?比如不能超过80KB
。
这样我们就要用到第三个参数qualityArgument
了,写个工具函数:
function compressImage(canvas,maxSize,quality){
canvas.toBlob(blob=>{
if(blob.size > maxSize){
//这里将每次递减定小一些,防止图像质量过损
compressImage(canvas,maxSize,quality-0.01)
}else{
console.log(blob)
}
},"image/jpeg",quality)
}
//限制图像尺寸为80KB
compressImage(canvas,80*1024,1)
可以看到图像的最终尺寸为:
输出压缩后的内容
上面已经讨论了对图像压缩,那么如何将压缩后的内容输出呢? 这里我们考虑两种常见的输出:
- 图像文件
base64
function compressImage(canvas,maxSize,quality,cb){
canvas.toBlob(blob=>{
if(blob.size > maxSize){
compressImage(canvas,maxSize,quality-0.01,cb)
}else{
var file = new File([blob], "image.jpeg");
var base64 = canvas.toDataURL("image/jpeg",quality)
cb({
file,
base64
})
}
},"image/jpeg",quality)
}
compressImage(canvas,80*1024,1,(opt)=>{
console.log(opt);
})
效果:
最后
最好,由于作者才疏学浅,内容难免出现疏漏,不当之处还望不吝赐教。
如果本文对你有用,麻烦留个赞再走,感谢阅读!