图片压缩上传
前两天在项目中遇到一个需求,需要做图片压缩上传。本着没接触过且没有做过的原则,我先是在网上搜索了,了解了两种图片压缩的格式blob、Base64两种格式,当然不确定还有没有其他的方法,不过对比了一下这两种方式差不多区别不大。
看看效果图
逻辑步骤
1、调用 FileReader 的 reader.readAsDataURL(img),在其onload事件中, 将用户选择的图片读入 img 对象。
2、在img对象的 onload 事件中, 通过 canvas 的 canvas.getContext('2d') 的 drawImage 方法, 将 Image 改变大小绘制到canvas上。
3、 通过 canvas.toDataURL(file.tpye, 1), 将图片变成base64字符串。
3、 通过 canvas.toBlob(file.tpye, 1), 将图片变成blob字符串。
下面我们来看代码
<form class="form form-vertical" method="post" id="new-feedback-form" enctype="multipart/form-data">
<input type="file" id="images-input" name="images[]" accept=".jpg,.jpeg,.png,.gif,.svg" multiple="multiple" onchange="loadFile(event)">
<div id="uploaded-image" class="uploaded">
</div>
<div class="col-12 d-flex justify-content-end mt-1">
<button class="btn btn-primary mr-1 mb-1 block-element" onclick="submitNewFeedback()">Submit</button>
<button type="reset" class="btn btn-light-secondary mr-1 mb-1">Reset</button>
</div>
</form>
这里还存在一个小问题就是,直接用formdata来提交数据的话,我们得需要把原本files的数据给替换了,但是又不能直接进行赋值,会报错说是属性只读的情况。这时我们得需要点小改动了,来展示。
var blobFFile = []
var loadFile = async function (event) {
var output = document.getElementById('uploaded-image');
var imgHtml = '';
blobFFile = [];
for (file of event.target.files) {
console.log(file,'‘原始图');
// 调用异步函数进行压缩
// const compressedImage = await compressImg(file);
const compressedImage = await compressFileBlob(file);
console.log(compressedImage,'压缩后的')
blobFFile.push(compressedImage)
// 构建HTML字符串
imgHtml += '<div class="uploaded-image"><img src="' + compressedImage.data + '"></div>';
}
// console.log(blobFFile,88888)
const imagesInput = document.getElementById('images-input')
// 创建一个新的 DataTransfer 对象
const dataTransfer = new DataTransfer();
// 将 blobFFile 数组中的文件添加到 DataTransfer 对象中
// base64
// blobFFile.forEach(file => {
// dataTransfer.items.add(file);
// });
blobFFile.forEach(file => {
dataTransfer.items.add(file.file);
});
// 将 DataTransfer 对象中的文件列表设置到文件输入元素中
imagesInput.files = dataTransfer.files;
console.log(imagesInput.files)
// 更新页面
output.innerHTML = imgHtml;
// 使用XMLHttpRequest或者Fetch API上传到服务器
// const xhr = new XMLHttpRequest();
// xhr.open('POST', '/upload-endpoint', true);
// xhr.onreadystatechange = function () {
// if (xhr.readyState === 4 && xhr.status === 200) {
// // 处理服务器响应
// console.log(xhr.responseText);
// }
// };
// xhr.send(formData);
};
这时我们通过 DataTransfer 这个对象来进行替换就替换成功,在当时写的时候也是查了好半天,后面还是leader 发给我看的呢,哈哈哈
这是转换为 Base64
function dataURLtoFile(dataurl, filename) {
const arr = dataurl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
// 这是压缩成Base64
function compressImg(file) {
return new Promise((resolve, reject) => {
let formData = new FormData();
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (ev) {
try {
let img = new Image();
img.src = ev.target.result;
img.onload = function (ev) {
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.height = targetHeight;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0, canvas.width, canvas.height);
let data = "";
if (file.size <= 628288) {
data = canvas.toDataURL(file.type);
formData.append("file", file);
resolve({ file, data });
} else {
data = canvas.toDataURL(file.type,0.9);
let paper = dataURLtoFile(data, file.name);
formData.append("file", paper, data)
resolve({ file: paper, data });
}
};
} catch (error) {
reject(error);
}
};
});
}
blob
async function compressFileBlob(file) {
return new Promise((resolve) => {
const img = new Image();
const reader = new FileReader();
reader.onload = function (e) {
img.src = e.target.result;
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 300; // 设置压缩后的宽度
canvas.height = (img.height / img.width) * canvas.width;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
// 创建新的 File 对象
const compressedFile = new File([blob], file.name, {
type: file.type,
lastModified: Date.now(),
});
const compressedData = URL.createObjectURL(compressedFile);
// 将压缩后的文件返回
resolve({ data: compressedData, file: compressedFile });});
}, file.type, 0.9);
};
};
reader.readAsDataURL(file);
});
}
认识一下
目前正在疯狂学习前端知识,想要成为更牛批的前端工程师,因此喜欢记录并分享自己的学习笔记。我所发表的只是自己所知道的知识,算不上绝对正确,通过网上查找资料所写只知道这个方法可行,但也许代码中存在些许bug,我也不得而知,有大佬知道的可以指点指点。