图片压缩方法封装
# 1.应用场景
# 对图片上传的一种优化处理方法 因公司项目数据涉及到的各类封面实景等图片,原始图片有的几兆甚至几十兆大小,故给系统上传图片组件增加了可设置质量、宽度、高度三个维度的参数,来校准合适的图片大小和效果。
先封装一下压缩图片的方法compressImg(),接收一个参数对象,对象有五个属性分别为fileObj图片、quality质量、width宽度、height高度、callback回调函数, 先实例化一个image对象,然后设置src属性,监听其加载成功或失败事件。
function compressImg (res = {}) {
try {
// 定义默认输出图片类型
let type = 'image/png'
// 创建image对象
const image = new Image()
// 这里做了个判断,可以直接传入图片地址。
if (typeof(res.fileObj) === "object") {
image.src = window.URL.createObjectURL(res.fileObj)
if (res.fileObj.type) {
type = res.fileObj.type
} // 携带原类型
} else {
image.src = res.fileObj
}: res.fileObj
image.onload = function() {
// ...
}
image.onerror = function() {
res.callback(false) // 失败
}
} catch () {
res.callback(false) // 失败
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
当图片加载完成后,先保存图片的原始宽高,如果有分别指定宽和高,直接使用参数覆盖。 如果只设置了宽,那么则以指定的宽度为基准,乘原始宽高的比例,获取等比例的高度,反之亦然。
image.onload = function() {
let w = this.width // 当前图片宽
let h = this.height // 当前图片高
if (res.width && res.height) { // 如果宽高都指定
w = res.width
h = res.height
} else if (res.width || res.height) { // 如果指定其一
if (res.width > res.height) {
h = res.width * (h / w)
w = res.width
} else {
w = res.height * (w / h)
h = res.height
}
}
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
图片宽高确定后,通过document.createElement('canvas')创建一个canvas画布,getContext()获取绘图环境,setAttributeNode()设置绘图区域宽高属性,然后使用drawImage()方法将图片插入到canvas画布中,最后通过toDataURL()方法将canvas转换为base64编码,到这里拿到base64基本已经完成功能了,可根据个人需求将其转换成不同的文件流格式
image.onload = function() {
// ...
const canvas = document.createElement('canvas') // 创建一个canvas
const ctx = canvas.getContext('2d') // 获取绘图环境
// 创建属性节点
const anw = document.createAttribute('width')
anw.nodeValue = w
const anh = document.createAttribute('height')
anh.nodeValue = h
canvas.setAttributeNode(anw)
canvas.setAttributeNode(anh)
// 设置图片
ctx.drawImage(this, 0, 0, w, h)
// canvas转换字节流并设置质量
const data = canvas.toDataURL(type, parseFloat(res.quality))
// base64转换为Blob对象
const newFile = convertBase64UrlToBlob(data)
// 执行回调
res.callback(newFile)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们要将图片转换成文件对象上传到服务器,封装了convertBase64UrlToBlob()方法将base64转换为Blob对象,Blob对象可以通过new window.File()转换为file文件对象,方便以fromData格式提交。
function convertBase64UrlToBlob(dataurl) {
const bytes = window.atob(dataurl.split(',')[1]) // 去掉url的头,并转换为byte
// 处理异常,将ascii码小于0的转换为大于0
const ab = new ArrayBuffer(bytes.length)
const ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
return new Blob([ab], { type: 'image/png' })
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
方法封装完成后可以开始调用了,先准备几个要使用的HTML标签。 通过input.file标签选择图片,监听change事件在获取到图片后使用window.URL.createObjectURL()将图片对象转为浏览器临时路径,先把原图展示出来,并保存原图对象。
<html>
<div id="fileList">
</div>
</html>
<script>
// 压缩图片
compressImg({
fileObj: file, // 图片对象
width: widthNode.value, // 图片宽度
height: heightNode.value, // 图片高度
quality: qualityNode.value, // 图片质量
callback: function (val) {
if (val) {
// 裁剪成功,将Blob转换为file对象
let newfile = new window.File([val], file.name, { type: file.type })
// 插入到页面上
fileList.innerHTML = `
<div class="list-item">
<div class="list-img">
<img src="${window.URL.createObjectURL(newfile)}">
</div>
<div class="list-tips">
<div>图片名称:${newfile.name}</div>
<div>图片大小:${sizeInit(newfile.size) }</div>
</div>
</div>` + fileList.innerHTML
} else {
// 裁剪失败
alert("裁剪失败!")
}
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 非dom方法也是同理,非常好用
上次更新: 2023/07/06, 09:51:30