实现图片的压缩,上传功能
简言:在前端开发中,我们经常会遇见图片上传等功能,
很多前端工作者 都知道利用input的 file功能实现图片上传的样式
常用的可能是 用一个a标签包裹着input 实现按钮状的上传样式
但是在深层次的上传和压缩功能 却知知甚少
下边我将以个人案例帮助大家了解 上传 压缩等功能
首先 图片压缩的原理是 获取当前图片文件转化成base64格式, 创建image对象把图片的base64赋值上去
获取改图片的实际大小,定义需要压缩后呈现的尺寸 除以当前的图片尺寸 得出 压缩比.
利用压缩比计算出 实际压缩后的图片
(有人会问 我可以直接定义图片的大小啊 比如800*800 还计算干嘛)
答:会变形 失贞 我们希望压缩后的图片比例和之前一样.
最后把计算后的尺寸 利用canvas 绘制出来 并使用canvas.toDataURL 导出 完成压缩
最后再计算出 压缩后的base64地址 生成一个回调完成上传;
不多BB 上代码
按钮样式:给新手看的 大佬跳过
.import_btn {
display: block;
margin: 100px;
width: 50px;
text-align: center;
color: #fff;
border-radius: 5px;
position: relative;
text-decoration: none;
padding: 10px 20px;
background: #e56233;
}
#upload {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
opacity: 0;
}
<a href="javascript:;" class="import_btn"> 上传
<input type="file" id="upload">
</a>
上逻辑:
const ACCEPT = ["image/png", "image/jpg","image/jpeg"]
const MAXSIZE = 1920 * 1080;
const MAXSIZE_STR = '1MB';
function convertImageToBase64(file, callback) {
// 实例化reader对象
let reader = new FileReader(); //FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件
reader.addEventListener("load", function (e) {
const base64Image = e.target.result;
callback && callback(base64Image); //执行回调 把得到base64传递出去
// 使用完成重置reader 释放内存
reader = null;
});
reader.readAsDataURL(file);
};
function compress(base64Image,callback) {
// 创建一个image 对象
const image = new Image();
// 设置最大宽高
let maxW = 1024;
let maxH = 1024;
// load 指图片加载完成 自动执行
image.addEventListener('load', function (e) {
let ratio; //图片的压缩比
let needCompress = false;//是否需要进行压缩
if (maxW < image.naturalWidth) { //naturalWidth 图片的实际宽度
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) {
maxW = image.naturalWidth;
maxh = image.naturalHeight;
}
// 把压缩后的图片绘制出来
const canvas = document.createElement("canvas"); //创建Dom
canvas.setAttribute("id", "_compress_");//添加一个id
canvas.width = maxW;
canvas.height = maxH;
canvas.style.visibility = "hidden";//压缩过程 bu可见
document.body.appendChild(canvas);
// 绘制
const ctx=canvas.getContext("2d");//创建2d绘制
ctx.clearRect(0,0,maxW,maxH);//清理画布上原有的像素 防止图片叠加 坐标
ctx.drawImage(image,0,0,maxW,maxH);//绘制图片 起始坐标 图片大小
// 获取压缩后图片的 base64
const compressImage=canvas.toDataURL("image/jpeg",0.9);
callback&&callback(compressImage);//执行回调函数 传出压缩后的照片
//展示图片(压缩后) 后期可剔除
const _image=new Image();
_image.src=compressImage;
document.body.appendChild(_image);
canvas.remove();
});
//展示 把传递过来的base64(未压缩)路径赋值到新创建的image上
image.src = base64Image;
document.body.appendChild(image);
};
// 回调函数 把压缩后的base64传给后端 实现上传
function uploadToServer(compressImage){
// console.log("aka",compressImage);
}
// 给 input绑定监听事件 获取到上传的图片信息
const upload = document.getElementById('upload');
upload.addEventListener("change", function (e) {
// console.log(e.target.files); 当前文件的信息
// 结构赋值
const [file] = e.target.files;
const { type: fileType, size: fileSize } = file;
/*
* 非空判断
*/
if (!file) {
return
}
/*
*
ES6写法 ACCEPT [上边定义的图片类型] includes:判断有无 .前的数据类型
*/
if (!ACCEPT.includes(fileType)) {
alert('不支持[' + fileType + ']文件类型');
upload.value = '';
return;
}
/*
* 尺寸判断
*/
if (fileSize > MAXSIZE) {
alert(`文件超出${MAXSIZE_STR}!`);
upload.value = '';
return;
}
/*
* 压缩图片
1.图片转为base64
回调+回调+回调
*/
convertImageToBase64(file,(base64Image)=> compress(base64Image,uploadToServer));
})
如果你仍然觉得 看起来有些困难:我在最后 补一段注释:
前言 图片压缩上传是一个相对复杂的功能
* 1.需要一个上传按钮 input的file 格式
2.监听input框的 change事件 上传成功后 通过files 拿到图片的各种信息
3.通过对文件的前置判断,类型 可上传大小 宽高等..
4.图片压缩:
一.首先将获取到的图片转化成base64格式
通过FileReader对象(webAPI 可获取储存在计算机上的文件)
调用他的API readAsDataURL(file)
readAsDataURL() 方法会读取指定的 Blob 或 File 对象。
读取操作完成的时候,readyState 会变成已完成DONE,
并触发 loadend 事件,同时result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。
获取成功后,执行 compress() 回调事件 属于压缩核心;
二.compress属于压缩的核心代码
创建一个图片的Dom new Image
把我们获取到的base64地址 赋值给这个图片 然后加载到页面上
在 监听image .load (图片加载完成的回调);
此时已获取到 当前base64图片的实际大小 尺寸
然后我们对 需要展示的图片占比和实际的图片占比
当图片超出我们需要压缩后的尺寸时 得出压缩比例 radio(实际尺寸/需要压缩的尺寸);
利用压缩比计算出 图片压缩后的尺寸 并使得图片不会变形
三.创建一个canvas 把计算后的尺寸赋值给canvas 并设置该canvas不可见(理解为 压缩过程隐藏)
拿到canvas对象,调用canvas.drawImage绘制出来;并转换成需要呈现的图片格式
const compressImage=canvas.toDataURL("image/jpeg",0.9); (格式,图片质量);
此时已经拿到压缩后的 图片base64
通过callback传递给后端 即可完成上传
四.为了更好的演示 我在案例中分别展示了2张图片(压缩前 压缩后);实际开发中,可将这部分逻辑删除
你get 了啵 T_T