背景:
最近项目需求需要使用到base64的图片格式,需要用户手机端上传压缩处理,所以打算写一个图片选择、压缩、转换的方法(需要压缩到指定大小)。
思路:
1) 调用 FileReader的 reader.readAsDataURL(img)方法, reader.readAsDataURL(file);读取图片信息。
2) 在reader.onload的事件中,新建Image对象,并将reader.result的值赋给img.src,在img.onload中判断尺寸大小,并且根据 [ exif-js ](https://github.com/exif-js/exif-js) 判断图片角度是否需要校正
实现代码
/**
* 图片转换base64(压缩、方向旋转)
* @param {blob} file文件对象
* @param {func} callBack 成功回调函数,参数为压缩后的二进制文件流
* @param {object} params 压缩文件参数 {可以根据 isBase64 == true 返回 base64格式, 否则返回 blob 格式内容
*/
function imageCompression(
file,
callBack = () => {},
params = {
width: 500,
LIMIT_SIZE: 4 * 1024 * 2014,
isBase64: true,
}
) {
let compressCount = 0;
const { width, LIMIT_SIZE, isBase64 } = params;
const orientation = EXIF.getTag(file, "Orientation") || 1;
// 图片压缩出错函数
const errorFn = (e) => {
console.error("图片压缩出问题了", e);
callBack(file);
};
if (!window.FileReader) {
console.error("浏览器不支持 window.FileReader 方法哦");
callBack(file);
} else {
try {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
let img = new Image();
img.src = reader.result;
img.onload = function () {
try {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const canvasWidth = width;
const canvasHeight = canvasWidth / (img.width / img.height);
canvas.width = canvasWidth;
canvas.height = canvasHeight;
let angle = 0;
switch (orientation) {
case 1:
break;
case 6:
angle = (90 * Math.PI) / 180;
canvas.width = canvasHeight;
canvas.height = canvasWidth;
context.rotate(angle);
context.translate(0, -canvas.width);
break;
case 8:
angle = (270 * Math.PI) / 180;
canvas.width = canvasHeight;
canvas.height = canvasWidth;
context.rotate(angle);
context.translate(-canvas.height, 0);
break;
case 3:
angle = (180 * Math.PI) / 180;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.rotate(angle);
context.translate(-canvas.width, -canvas.height);
break;
default:
break;
}
context.drawImage(img, 0, 0, canvasWidth, canvasHeight);
context.setTransform(1, 0, 0, 1, 0, 0);
canvas.toBlob(
(blob) => {
if (blob.size > LIMIT_SIZE) {
compressCount += 1;
imageCompression(blob, callBack);
} else {
compressCount = 0;
if (isBase64) {
conversion(blob, callBack);
} else {
callBack(blob);
}
}
},
"image/jpeg",
0.9 - compressCount * 0.1
);
} catch (error) {
errorFn(error);
}
};
};
reader.onerror = (error) => {
errorFn(error);
};
} catch (error) {
errorFn(error);
}
// 转为base64
function conversion(blob, callback) {
let reader = new FileReader();
reader.onload = function (e) {
callback(e.target.result);
};
reader.readAsDataURL(blob);
}
}
}
效果图