前端经常有图片上传的需求,这里做一下总结。
对于前端来说,单纯的上传图片还是很简单的,
就可以搞定,你可以增加size属性控制用户一次性能选几张。
采坑开始:
1、部分安卓手机微信直接进图库选取,不能拍照
经排查,安卓微信只认accept="image/*",其他的都不好使,加上这个就好了。。。
2、往往需求不会那么简单。
图片选择后,base64传后台,前端展示用户选取的图片,就需要通过FileReader读取文件,获得base64.
以vue为例代码:
input(class="upload-img", type="file", @change="uploadImg", name="uploadImg", size="1",accept="image/*")
uploadImg(event) {
const target = event.target
if (target && target.files.length > 0) {
utils.loading('上传中')
const type = target.files[0].type
if (type === "image/png" || type === "image/jpeg") {
utils.getBase64(target, (info) => {
if (info && info.result) {
this.src = info.result
this.base64=info.base64
this.getAnswer(this.base64)
}
})
} else {
this.toast('仅支持png、jpg格式');
}
}
},
function getBase64(node, callback) {
let files = node.files;
let file = files[0];
let reader = new FileReader();
reader.onload = () => {
let fileInfo = {
name: file.name,
type: file.type,
size: file.size,
base64: reader.result.split(',')[1],
result: reader.result
};
callback && callback(fileInfo)
}
reader.readAsDataURL(file);
}
3、到这里只是理想的情况,然而事实不是这样滴,部分ios手机拍照后,拿到的base64图片是横向的,这就头疼了,我们需要判断一下进行旋转。
这里用到了exif-js,修改getBase64代码
function getBase64(node, callback) {
let files = node.files;
let file = files[0];
let reader = new FileReader();
reader.onload = (e) => {
let fileInfo = {
name: file.name,
type: file.type,
size: file.size,
base64: reader.result.split(',')[1], //reader.result.split(',')[1],
result: reader.result
};
getPhotoOrientation(file, function (orientation) {
if (orientation != '' && orientation != 1) {
var image = new Image();
image.onload = function() {
var expectWidth = this.naturalWidth;
var expectHeight = this.naturalHeight;
if (this.naturalWidth > this.naturalHeight && this.naturalWidth > 800) {
expectWidth = 800;
expectHeight = expectWidth * this.naturalHeight / this.naturalWidth;
} else if (this.naturalHeight > this.naturalWidth && this.naturalHeight > 1200) {
expectHeight = 1200;
expectWidth = expectHeight * this.naturalWidth / this.naturalHeight;
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = expectWidth;
canvas.height = expectHeight;
ctx.drawImage(image, 0, 0, expectWidth, expectHeight);
var base64 = null;
switch (orientation) {
case 6://需要顺时针(向左)90度旋转
rotateImg(this, 'left', canvas);
break;
case 8://需要逆时针(向右)90度旋转
rotateImg(this, 'right', canvas);
break;
case 3://需要180度旋转
rotateImg(this, 'right', canvas);//转两次
rotateImg(this, 'right', canvas);
break;
}
base64 = canvas.toDataURL("image/jpeg")
console.log("1"+base64);
console.log("2"+base64.split(',')[1])
fileInfo.base64 = base64.split(',')[1]
fileInfo.result = base64
callback && callback(fileInfo)
}
image.src = reader.result;
} else {
callback && callback(fileInfo)
}
})
}
reader.readAsDataURL(file);
}
function getPhotoOrientation(file, callback) {
EXIF.getData(file, function () {
var orient = ''
orient = EXIF.getTag(this, 'Orientation')
callback && callback(orient)
});
}
// 对图片旋转处理
function rotateImg(img, direction, canvas) {
//最小与最大旋转方向,图片旋转4次后回到原方向
var min_step = 0;
var max_step = 3;
//var img = document.getElementById(pid);
if (img == null)return;
//img的高度和宽度不能在img元素隐藏后获取,否则会出错
var height = img.height;
var width = img.width;
var step = 2;
if (step == null) {
step = min_step;
}
if (direction == 'right') {
step++;
//旋转到原位置,即超过最大值
step > max_step && (step = min_step);
} else {
step--;
step < min_step && (step = max_step);
}
//旋转角度以弧度值为参数
var degree = step * 90 * Math.PI / 180;
var ctx = canvas.getContext('2d');
switch (step) {
case 0:
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0);
break;
case 1:
canvas.width = height;
canvas.height = width;
ctx.rotate(degree);
ctx.drawImage(img, 0, -height);
break;
case 2:
canvas.width = width;
canvas.height = height;
ctx.rotate(degree);
ctx.drawImage(img, -width, -height);
break;
case 3:
canvas.width = height;
canvas.height = width;
ctx.rotate(degree);
ctx.drawImage(img, -width, 0);
break;
}
}