JavaScript前端实现压缩图⽚功能
为什么要前端来压缩图⽚
最近在做⼀个移动端h5上传图⽚的功能,本来这个功能并不复杂,只需要将图⽚⽂件通过axios传到服务端即可,但是考虑到现在⼿机设配的拍照功能⼗分强⼤,随便⼀张照⽚都能动辄五六兆,⽽服务端的要求是上传图⽚必须⼩于两兆,⽽且直接传这么⼤图⽚,带宽它也受不了,所以前端进⾏压缩图⽚就成了⼀个必要的环节。
压缩效果
⾸先介绍下压缩的⼤概流程
通过原⽣的input标签拿到要上传的图⽚⽂件
将图⽚⽂件转化成img元素标签
在canvas上压缩绘制该HTMLImageElement
将canvas绘制的图像转成blob⽂件
最后将该blob⽂件传到服务端
完成!
接下来看下详细步骤
考虑到⽂章和步骤的完整性,所以我会把每个细节都写出来,即使有些东西很基础。
1.  使⽤Input标签来获取图⽚⽂件资源
这⼀步⼤家应该最熟悉不过了吧,原⽣input标签,通过设置type属性为file来让⽤户可以选择⽂件,设置accept限制选择的⽂件类型,绑定onchange事件,来获取确认选择后的⽂件
<input type="file" accept="image/*" />
点击控件,触发焦点,打开⽂件资源管理器,选中⽂件并确认后,会触发change事件,所以可以在change事件的回调中获取选中⽂件,它长这个样
2. 读取⽂件转成img标签元素
拿到图⽚⽂件后,先将其转成HTMLImageElement,也就是普通的img标签,具体要使⽤ FileReader构造函数。
先new出来⼀个img和fileReader的实例,通过fileReader的 readAsDataURL这个api,来读取图⽚⽂件,其返回值是⼀个编码后的base64的字符串,然后将这个字符串赋值给img的src属性上,这样就完成了图⽚⽂件到 HTMLImageElement的转化。
// 先new⼀个img和fileReader的实例
const img = new Image()
const reader = new FileReader()// 读取⽂件资源
img.src = sult
}
转化的HTMLImageElement
3. canvas压缩,核⼼步骤
拿到转化后的img元素后,先取出该元素的宽⾼度,这个宽⾼度就是实际图⽚⽂件的宽⾼度。
const { width: originWidth, height: originHeight } = img
然后定义⼀个最⼤限度的宽⾼度,如果超过这个限制宽⾼度,则进⾏等⽐例的缩放
// 最⼤尺⼨限制
const maxWidth = 1000,maxHeihgt = 1000
// 需要压缩的⽬标尺⼨
let targetWidth = originWidth, targetHeight = originHeight
// 等⽐例计算超过最⼤限制时缩放后的图⽚尺⼨
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > 1) {
// 宽图⽚
targetWidth = maxWidth
targetHeight = und(maxWidth * (originHeight / originWidth))
inputtypefile不上传文件} else {
// ⾼图⽚
targetHeight = maxHeight
targetWidth = und(maxHeight * (originWidth / originHeight))
}
}
计算好将要压缩的尺⼨后,创建canvas实例,设置canvas的宽⾼度为压缩计算后的尺⼨,并将img绘制到上⾯
// 创建画布
const canvas = ateElement('canvas')
const context = Context('2d')
// 设置宽⾼度为等同于要压缩图⽚的尺⼨
canvas.width = targetWidth
canvas.height = targetHeight
context.clearRect(0, 0, targetWidth, targetHeight)
//将img绘制到画布上
context.drawImage(img, 0, 0, targetWidth, targetHeight)
4. 转成blob⽂件
canvas绘制完成后,就可以使⽤ toBlob来将图像转成blob⽂件了,这个api接受三个⼊参
回调函数中可以得到转化后的blob⽂件,type为要转成的图⽚类型,默认png。
encoderOptions为当设置的图⽚格式为image/jpeg或者image/webp时⽤来指定图⽚展⽰质量。
所以如果我们只是要压缩jpg或者webp格式的图⽚的话,不需要进⾏第3部的操作,直接使⽤这个api,
然后填⼊想要的质量参数就可以了。但实际上,我们还是要考虑多种的图⽚格式,因此很有必要使⽤第三部的过程。
转成的blob长这个样⼦
5. 将blob上传,⼤功告成。
完整的代码实现
因为整个过程中都存在着异步回调操作,所以我使⽤了async,实现异步代码的同步执⾏
// 压缩前将file转换成img对象
function readImg(file) {
return new Promise((resolve, reject) => {
const img = new Image()
const reader = new FileReader()
img.src = sult
}
reject(e)
}
resolve(img)
}
reject(e)
}
})
}
/**
* 压缩图⽚
*@param img 被压缩的img对象
* @param type 压缩后转换的⽂件类型
* @param mx 触发压缩的图⽚最⼤宽度限制
* @param mh 触发压缩的图⽚最⼤⾼度限制
*/
function compressImg(img, type, mx, mh) {
return new Promise((resolve, reject) => {
const canvas = ateElement('canvas')
const context = Context('2d')
const { width: originWidth, height: originHeight } = img
// 最⼤尺⼨限制
const maxWidth = mx
const maxHeight = mh
/
/ ⽬标尺⼨
let targetWidth = originWidth
let targetHeight = originHeight
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > 1) {
// 宽图⽚
targetWidth = maxWidth
targetHeight = und(maxWidth * (originHeight / originWidth))
} else {
// ⾼图⽚
targetHeight = maxHeight
targetWidth = und(maxHeight * (originWidth / originHeight))
}
}
canvas.width = targetWidth
canvas.height = targetHeight
context.clearRect(0, 0, targetWidth, targetHeight)
// 图⽚绘制
context.drawImage(img, 0, 0, targetWidth, targetHeight)
resolve(blob)
}, type || 'image/png') })
}
⼤致执⾏过程,具体可根据需求,⾃⾏改动
async function upload(file){
const img = await readImg(file)
const blob = await compressImg(img, pe, 1000, 1000)
const formData = new FormData()
formData.append('file', blob, 'xxx.jpg')
axios.post('xxx/api',formData)
}
upload(file).catch(e => console.log(e))
到此这篇关于JavaScript前端实现压缩图⽚功能的⽂章就介绍到这了,更多相关JavaScript 压缩图⽚内容请搜索以前的⽂章或继
续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!