跳到主要内容

通过 Canvas 实现图片压缩

通过 Canvas 实现图片压缩-Base64 格式

在前端要实现图片压缩,我们可以利用 Canvas 对象提供的 toDataURL() 方法,该方法接收 typeencoderOptions 两个可选参数。

其中 type 表示图片格式,默认为 image/png。而 encoderOptions 用于表示图片的质量,在指定图片格式为 image/jpegimage/webp 的情况下,可以从 01 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92,其他参数会被忽略。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>通过 Canvas 实现图片压缩-Base64 格式</title>
</head>
<body>
<input type="file" accept="image/*" onChange="handleChange(event)"/>
<img id="img" />
<script>
function compress(base64, quality, mimeType) {
const MAX_WIDTH = 800;
const canvas = document.createElement("canvas");
const img = document.createElement("img");
img.crossOrigin = "anonymous";
return new Promise((resolve, reject) => {
img.src = base64;
console.log(img);
img.onload = () => {
let targetWidth, targetHeight;
if (img.width > MAX_WIDTH) {
targetWidth = MAX_WIDTH;
targetHeight = (img.height * MAX_WIDTH) / img.width;
} else {
targetWidth = img.width;
targetHeight = img.height;
}
canvas.width = targetWidth;
canvas.height = targetHeight;
let ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
let imageData = canvas.toDataURL(mimeType, quality / 100);
resolve(imageData);
};
});
}
function handleChange(event){
const fileReader = new FileReader();
fileReader.onload =async (e) => {
const compressedDataURL = await compress(
e.target.result,
90,
"image/jpeg"
);
const img = document.getElementById('img');
img.src = compressedDataURL;
}
fileReader.readAsDataURL(event.target.files[0]);
}
</script>
</body>
</html>

通过 Canvas 实现图片压缩-Blob 格式

在前端要实现图片压缩,我们可以利用 Canvas 对象提供的 toDataURL() 方法,该方法接收 typeencoderOptions 两个可选参数。

其中 type 表示图片格式,默认为 image/png。而 encoderOptions 用于表示图片的质量,在指定图片格式为 image/jpegimage/webp 的情况下,可以从 01 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92,其他参数会被忽略。

对于返回的 Data URL 格式的图片数据,为了进一步减少传输的数据量,我们可以把它转换为 Blob 对象

在转换完成后,我们就可以压缩后的图片对应的 Blob 对象封装在 FormData 对象中,然后再通过 AJAX 提交到服务器上

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>通过 Canvas 实现图片压缩-Blob 格式</title>
</head>
<body>
<input type="file" accept="image/*" onChange="handleChange(event)"/>
<img id="img" />
<script>
function compress(base64, quality, mimeType) {
const MAX_WIDTH = 800;
const canvas = document.createElement("canvas");
const img = document.createElement("img");
img.crossOrigin = "anonymous";
return new Promise((resolve, reject) => {
img.src = base64;
img.onload = () => {
let targetWidth, targetHeight;
if (img.width > MAX_WIDTH) {
targetWidth = MAX_WIDTH;
targetHeight = (img.height * MAX_WIDTH) / img.width;
} else {
targetWidth = img.width;
targetHeight = img.height;
}
canvas.width = targetWidth;
canvas.height = targetHeight;
let ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
let imageData = canvas.toDataURL(mimeType, quality / 100);
resolve(imageData);
};
});
}
function dataUrlToBlob(base64, mimeType) {
const reg = /^data:(.*);base64.*/;
mimeType = mimeType || reg.exec(base64)?.[1] || "";
let bytes = window.atob(base64.split(",")[1]);
let ab = new ArrayBuffer(bytes.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], { type: mimeType });
}
function uploadFile(url, blob) {
let formData = new FormData();
let request = new XMLHttpRequest();
formData.append("image", blob);
request.open("POST", url, true);
request.send(formData);
}
function handleChange(event){
const fileReader = new FileReader();
fileReader.onload =async (e) => {
const compressedDataURL = await compress(
e.target.result,
90,
"image/jpeg"
);
const compressedImageBlob = dataUrlToBlob(compressedDataURL);
uploadFile("https://httpbin.org/post", compressedImageBlob);
}
fileReader.readAsDataURL(event.target.files[0]);
}
</script>
</body>
</html>