這裏有兩張圖片,它們表面看上去是一模一樣的,但實際上各自所佔用的內存大小相差了180倍。
可以看到右邊的圖片是22.3MB,而左側的圖片只有127KB,但是實際上這兩張圖片的大小都是22.3MB。
最近在開發中遇到這樣的一個需求,需要把用户上傳的圖片先進行一次壓縮,然後再保存到服務器,這裏我們除了優先考慮壓縮圖片的大小外,還要顧及圖片壓縮後的清晰度問題。
經過對比,圖片並沒有明顯的失真情況,下面給大家分享一下,我的解決方法:
這裏我採用element的文件上傳控件來上傳圖片
<el-upload
class="avatar-uploader"
:action="GLOBAL.serverFileUrl"
name="file"
drag
:show-file-list="false"
:on-change="beforeAvatarUpload"
>
<i class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
定義了三個事件方法
//圖片上傳之前處理事件
beforeAvatarUpload(file) {
console.log(file);
const isJpgPng =
file.raw.type === "image/jpeg" || file.raw.type === "image/png";
if (!isJpgPng ) {
this.GLOBAL.messageEvent("error","上傳頭像圖片只能是 JPG/PNG 格式!");
} else {
this.compressImg(file.raw);
}
return isJpgPng;
},
compressImg(file) {
let that = this;
// ?通過FormData構造函數創建一個空對象
let formData = new FormData();
let reader = new FileReader();
// ?將讀取到的文件編碼成DataURL
reader.readAsDataURL(file);
// ?壓縮圖片
reader.onload = function(ev) {
try {
// ?讀取圖片來獲得上傳圖片的寬高
let img = new Image();
img.src = ev.target.result;
img.onload = function(ev) {
// ?將圖片繪製到canvas畫布上進行壓縮
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
let imgwidth = img.width;
let imgHeight = img.height;
// ?按比例縮放後圖片寬高;
let targetwidth = imgwidth;
let targetHeight = imgHeight;
// ?/如果原圖寬大於最大寬度
if (targetWidth > targetHeight) {
// ?原圖寬高比例
let scale = targetHeight / 1280;
targetHeight = 1280;
targetWidth' = targetwidth / scale;
} else {
// ?原圖寬高比例
let scale = targetWidth / 1280;
targetWidth = 1280;
targetHeight = targetHeight / scale;
}
// ?縮放後高度仍然大於最大高度繼續按比例縮小
canvas.width = targetwidth; //canvas的寬=圖片的寬
canvas.height = targetHeight; //canvas的高=圖片的高
context.clearRect(0,0, canvas.width, canvas.height);
context.drawImage(this, 0, 0, canvas.width, canvas.height);
let data = "":
// ?如果圖片小於0.6Mb,不進行壓縮,並返回二進制流
if (file.size <= 628288) {
data = canvas.toDataURL("image/jpeg");
formData.append("file", file);
that.handleChange(file);
}
// ?如果圖片大於e.6Mb,進行壓縮,並返回二進制流
else {
// todo 壓縮文件大小比例
data = canvas.toDataURL("image/jpeg",0.4);
let paper = that.GLOBAL.dataURLtoFile(data, file.name);
formData.append("file", paper);
that.handleChange(paper);
}
};
} catch (error) {
console.log("出現錯誤",error);
}
};
},
// todo 調用上傳接口 文件提交給後台
handleChange(file) (
let formData = new FormData( );
formData.append("file",file.raw || file);
console.log(formData);
brandServices.uploadFile(formData).then(res => {
if (res.data.errno === 0) {
this.imgUrl = res.data.data;
this.dialogImageUrl = URL.createObjectURL(file);
this.GLOBAL.messageEvent("success",res.data.message);
} else {
this.GLOBAL .messageEvent("error",res .data.message);
}
});
}
總結:
先進行圖片上傳前的驗證;接着再對圖片實現壓縮的操作;最後就可以把文件流提交給後台。
具體的思路是:通過FormData構造函數創建一個空對象,將圖片繪製到canvas畫布上,然後再進行壓縮。用户上傳的文件超過一定的大小後就可以執行壓縮的操作,當然如果圖片太小的話,我們就沒必要再壓了。建議採用寬高等比例的方式來壓縮,不然可能會出現圖片變形的情況。