项目场景:
前端展示图片的时候,不压缩展示,但是上传后端接口需要压缩,要求是200kb
如果图片大小在200kb以内就不压缩,如果大于200kb就压缩,压缩的时候我希望压缩比例最大为图片/200kb,最小压缩比例为0.8(不能)
问题描述
提示:这里描述项目中遇到的问题:
- 如何计算base图片文件大小
- 如何压缩
// 计算图片大小
const calculateSize = (base64Str: string) => {
const base64Data = base64Str.split(",")[1] || "";
const padding = (base64Data.match(/=/g) || []).length;
return (base64Data.length * 3) / 4 - padding;
};
// 压缩图片方法
const compressImage = (
base64: string,
quality: number,
callback: any
) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx: any = canvas.getContext("2d");
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
canvas.toBlob(
(blob: any) => {
const reader = new FileReader();
reader.onload = () => callback(reader.result);
reader.readAsDataURL(blob);
},
"image/jpeg",
quality
);
};
img.src = base64;
};
// 判断是否需要压缩,并确定压缩比例
const currentSize = calculateSize(base64String);
console.log("原始大小:", currentSize);
if (currentSize > 200 * 1024) {
let quality = (200 * 1024) / currentSize;
quality = Math.max(0.8, quality);
compressImage(
base64String,
quality,
(compressedBase64: string) => {
compressPhoto.value = compressedBase64;
}
);
} else {
compressPhoto.value = base64String;
}
计算图片大小-详解
const calculateSize = (base64Str: string) => {
const base64Data = base64Str.split(",")[1] || "";
const padding = (base64Data.match(/=/g) || []).length;
return (base64Data.length * 3) / 4 - padding;
};
这段代码定义了一个名为 calculateSize
的函数,用于计算 Base64 编码字符串所表示的数据大小(以字节为单位)。以下是详细的解释:
-
函数签名:
const calculateSize = (base64Str: string) => { ... }
: 定义了一个箭头函数calculateSize
,它接受一个参数base64Str
,该参数是一个 Base64 编码的字符串。
-
提取 Base64 数据部分:
const base64Data = base64Str.split(",")[1] || ""
:- 这行代码将传入的 Base64 字符串按照逗号
,
分割成数组。 - 通常 Base64 编码的字符串前面会有一个 MIME 类型前缀,例如
data:image/png;base64,
。通过.split(",")[1]
可以获取到实际的 Base64 编码数据部分。 - 如果没有逗号分隔的内容,则返回空字符串
""
。
- 这行代码将传入的 Base64 字符串按照逗号
-
计算填充字符的数量:
const padding = (base64Data.match(/=/g) || []).length
:- 使用正则表达式
/=/g
查找所有等于号=
,这些等于号是 Base64 编码中的填充字符。 - 如果没有找到任何等于号,则返回空数组
[]
,然后计算其长度。 - 填充字符用于确保 Base64 编码后的字符串长度是 4 的倍数。
- 使用正则表达式
-
计算原始数据的大小:
return (base64Data.length * 3) / 4 - padding
:- Base64 编码将每 3 个字节的二进制数据转换为 4 个字符,因此
(base64Data.length * 3) / 4
计算出原始数据的字节数。 - 减去
padding
是因为填充字符并不表示实际的数据,所以需要从总字节数中减去。
- Base64 编码将每 3 个字节的二进制数据转换为 4 个字符,因此
总结来说,这个函数的作用是根据 Base64 编码字符串计算出它所表示的原始数据的大小(以字节为单位),并返回这个大小值。
canvas.toBlob-详解
canvas.toBlob(
(blob: any) => {
const reader = new FileReader();
reader.onload = () => callback(reader.result);
reader.readAsDataURL(blob);
},
"image/jpeg",
quality
);
这段代码使用了 HTML5 的 <canvas>
元素的 toBlob
方法,将 canvas 上绘制的内容转换为一个 Blob 对象,并通过 FileReader 将其读取为 Base64 编码的数据 URL。以下是详细的解释:
1. canvas.toBlob
- 方法签名:
canvas.toBlob(callback, type, quality)
- 参数:
callback
: 当 Blob 对象创建完成后调用的回调函数。type
: 指定生成的 Blob 对象的 MIME 类型(例如"image/jpeg"
)。quality
: 图像的质量(仅对 JPEG 和 WebP 格式有效),范围是 0 到 1。
2. 回调函数
(blob: any) => {
const reader = new FileReader();
reader.onload = () => callback(reader.result);
reader.readAsDataURL(blob);
}
2.1 创建 FileReader
实例
const reader = new FileReader();
- 创建一个新的
FileReader
实例,用于读取文件或 Blob 对象。
- 创建一个新的
2.2 设置 onload
事件处理程序
reader.onload = () => callback(reader.result);
- 当
FileReader
完成读取操作时触发onload
事件。 reader.result
包含读取的结果,即 Base64 编码的字符串。- 调用外部传入的
callback
函数,并将reader.result
作为参数传递给它。
- 当
2.3 读取 Blob 为 Data URL
reader.readAsDataURL(blob);
- 使用
readAsDataURL
方法将 Blob 对象读取为 Base64 编码的数据 URL。 - 这个方法会触发
onload
事件,当读取完成时执行相应的回调。
- 使用
总结
这段代码的作用是将 canvas 上的内容转换为指定类型的图像(如 JPEG),并将其编码为 Base64 数据 URL。具体步骤如下:
- 使用
canvas.toBlob
方法将 canvas 内容转换为 Blob 对象。 - 使用
FileReader
读取 Blob 对象并将其转换为 Base64 编码的字符串。 - 当读取完成时,调用外部传入的
callback
函数,并将 Base64 编码的字符串作为参数传递给它。
这种方式常用于将 canvas 上绘制的图像保存为文件、上传到服务器或在页面中直接显示。