本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com
作者:爱泡澡的小萝ト
最近在学习和工作中遇到这样一个场景:如何将前端上传的图片进行压缩传递给服务端?因为此前从未了解过图片压缩的功能,所以也是带着好奇进行了一番学习,那么我的解决思路如下展示
整体思路
创建 input 框实现图片上传
将上传的文件转成 base64 格式
前端通过 base64 进行原始图片展示,并将此图片进行压缩
将压缩后的图片传给服务器
代码实现
首先我们要实现 input 上传文件并做一些细节处理,细节处理要对上传的文件类型和上传的文件大小做限制,类型和大小这里我们可以根据规则自定义。
<div class="container"> <input type="file" id="upload" /></div>const ACCEPT = ['image/jpg', 'image/png', 'image/jpeg'] // 所能接受的类型(自定义)const MAXSIZE = 3 * 1024 * 1024 // 上传图片大小限制(自定义)const MAXSIZE_STR = '3MB'const upload = document.getElementById('upload')upload.addEventListener('change', (e) => { const [file] = e.target.files if (!file) return // 上传文件为空时终止 const { type: fileType, size: fileSize } = file // 类型判断 if (!ACCEPT.includes(fileType)) { alert('不支持' + fileType + '文件类型') upload.value = '' return } // 图片大小判断 if (fileSize > MAXSIZE) { alert(`文件超出${MAXSIZE_STR}限制`) upload.value = '' return } // 压缩图片 covertImageToBase64(file, (base64Image) => compress(base64Image, uploadServer) )})当所有限制都通过之后,就要将图片转为 base64 格式,也就是进入到 covertImageToBase64 函数,我们来看看这个函数做了什么
function covertImageToBase64(file, callback) { let reader = new FileReader() reader.readAsDataURL(file) // 读取二进制数据,并将其编码为 base64 的 data url // 读取完成进行下面操作 reader.addEventListener('load', function (e) { const base64Image = reader.result callback && callback(base64Image) // 将读取到的结果传递给回调函数中 reader = null })}这里我们要将上传获取的_file_进行编码转换,通过 FileReaader[1] 构造函数中的 readAsDataURL[2] 方法进行转换,将编码后的格式文件传递给回调函数中准备进行压缩处理
到这里这里为了方便大家的理解,我做了一个动图方便观看效果,样式比较简陋😒
Kapture 2023-04-10 at 15.00.12 (1).gif
重点的压缩图片函数
上面的代码都比较好理解,这里较为复杂的逻辑就都在 covertImageToBase64 函数的的回调 compress 中,这个功能也是压缩图片中最为核心的部分。
先撸为敬
function compress(base64Image, callback) { let maxW = 800 // 图片最大宽度 let maxH = 800 // 图片最大高度 const image = new Image() image.src = base64Image document.body.appendChild(image) image.addEventListener('load', function (e) { let ratio // 图片压缩比 let needCompress = false // 是否需要压缩 // 按照比例进行图片宽高的修改 if (image.naturalWidth > maxW ) { needCompress = true ratio = image.naturalWidth / maxW maxH = image.naturalHeight / ratio } if (maxH < image.naturalHeight) { needCompress = true ratio = image.naturalHeight / maxH maxW = image.naturalWidth / ratio } if (!needCompress) { maxH = image.naturalHeight maxW = image.naturalWidth } const canvas = document.createElement('canvas') canvas.setAttribute('id', '__compress__') canvas.width = maxW canvas.height = maxH canvas.style.visibility = 'hidden' document.body.appendChild(canvas) const ctx = canvas.getContext('2d') ctx.clearRect(0, 0, maxW, maxH) ctx.drawImage(image, 0, 0, maxW, maxH) const compressImage = canvas.toDataURL('image/png', 0.9) callback && callback(compressImage) // console.log(compressImage) canvas.remove() })}function uploadServer(compressImage) { console.log(`upload to server ${compressImage}`)}代码分析
当我们接收到传来的 base64 编码的图片时,可以对其进行压缩,根据自定义的宽高与图片实际宽高对比进行比例计算,通过创建 canvas 元素画出该图片,并通过 toDataURL[3] 方法将计算宽高后也就是压缩后的 base64 返回,传入回调中就可以进行服务器上传了,那么通过检验也是能够看到图片确实进行了压缩
Kapture 2023-04-10 at 15.55.05.gif
总结
要想更好的理解图片压缩,还是要把_FileReader_和_canvas_的一些 api 弄清楚,这样才会更加容易理解代码的逻辑,希望这篇文章能够帮助到各位大佬
参考资料
[1]
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FFileReader
[2]
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsDataURL: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FFileReader%2FreadAsDataURL
[3]
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FHTMLCanvasElement%2FtoDataURL
最后
如果你觉得这篇内容对你挺有启发,我想邀请你帮我个小忙:
点个「喜欢」或「在看」,让更多的人也能看到这篇内容
我组建了个氛围非常好的前端群,里面有很多前端小伙伴,欢迎加我微信「sherlocked_93」拉你加群,一起交流和学习
关注公众号「前端下午茶」,持续为你推送精选好文,也可以加我为好友,随时聊骚。
点个喜欢支持我吧,在看就更好了