前言
因公司项目数据涉及到的各类封面实景等图片,原始图片有的几兆甚至几十兆大小,故给后台管理系统上传图片组件增加了可设置质量、宽度、高度三个维度的参数,来校准合适的图片大小和效果。
先附上demo: KICompress
可指定宽高质量,如不传则默认原图指标,宽高设置其一,则按等比例放大缩小。
实现步骤
虽然不是啥深层次的东西,但感觉还是蛮实用的,就包装了一下 (~ ̄▽ ̄)~
创建方法
先封装一下压缩图片的方法compressImg()
,接收一个参数对象,对象有五个属性分别为fileObj图片
、quality质量
、width宽度
、height高度
、callback回调函数
,
先实例化一个image
对象,然后设置src
属性,监听其加载成功或失败事件。
function compressImg (res = {}) {
try {
// 创建image对象
const image = new Image()
// 这里做了个判断,可以直接传入图片地址。
if (typeof(res.fileObj) === "object") {
image.src = window.URL.createObjectURL(res.fileObj)
} else {
image.src = res.fileObj
}: res.fileObj
image.onload = function() {
// ...
}
image.onerror = function() {
res.callback(false) // 失败
}
} catch () {
res.callback(false) // 失败
}
}
复制代码
宽高设置
当图片加载完成后,先保存图片的原始宽高,如果有分别指定宽和高,直接使用参数覆盖。
如果只设置了宽,那么则以指定的宽度为基准,乘原始宽高的比例,获取等比例的高度,反之亦然。
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
}
}
// ...
}
复制代码
图片生成
图片宽高确定后,通过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('image/jpeg', parseFloat(res.quality))
// base64转换为Blob对象
const newFile = convertBase64UrlToBlob(data)
// 执行回调
res.callback(newFile)
}
复制代码
格式转换
我们要将图片转换成文件对象上传到服务器,封装了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' })
}
复制代码
使用
方法封装完成后可以开始调用了,先准备几个要使用的HTML标签。
通过input.file
标签选择图片,监听change事件在获取到图片后使用window.URL.createObjectURL()
将图片对象转为浏览器临时路径,先把原图展示出来,并保存原图对象。
<html>
<div class="compress-img">
<img src="" id="img">
<input type="file" accept="image/*">
</div>
</html>
<script>
let file = null // 文件对象
let imgInput = document.querySelector(".compress-img input") // 获取input标签
// 绑定change事件
imgInput.addEventListener('change', function(e) {
file = e.target.files[0] // 保存图片对象
img.src = window.URL.createObjectURL(file); // 转换浏览器临时路径
})
</script>
复制代码
添加输入框设置要指定的图片宽高及质量,不设置等于保持原有指标,然后添加执行按钮。
<html>
<div class="compress-btn">
<span>图片宽度:</span>
<input type="number" placeholder="图片宽度" id="widthNode">
<span>图片高度:</span>
<input type="number" placeholder="图片高度" id="heightNode">
<span>图片质量:</span>
<input type="text" placeholder="图片质量 1 ~ 0" id="qualityNode">
<br>
<br>
<span class="btn-item" onclick="qualityClick()">压缩图片</span>
<span class="btn-item" onclick="empty()">清空</span>
</div>
</html>
<script>
// 压缩图片
function qualityClick () {
// ...
}
// 清除图片列表
function empty(e) {
// ...
}
</script>
复制代码
执行调用compressImg()
方法,并将生成新的图片插入到页面上进行效果展示。
<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>
复制代码
效果
未处理的图片
设置一半的质量
设置宽度,高度等比例变化(等比例情况下图片不会出现拉伸问题)
设置指定宽高(原始宽高是2481*3508)
最后
已经很久没用过DOM,BOM操作了
一个人竟然可以在没有钱没有事业的同时,还没有时间。