图片上传前旋转压缩处理

本文最后更新于:2023年3月30日 下午

1. 🎬 前情提要

😭 某天在本地开发vue项目时,使用了vue的某个上传图片组件vue-core-image-upload, 偶然发现ios设备拍照上传时,图片莫名其妙被逆时针旋转了90°
😂 what? 什么鬼?ios出现了这个鬼畜的玩意?貌似好多小伙伴都遇到了这个问题!!!有点东西啊~~

2. 🐒 go go go 也必须得解决不是

🤔 嗯?那么怎么解决呢?高能量来了

1️⃣ 既然只有ios会出现这个毛病?你那么将是否是ios作为参数传给后端,后端旋转回图片即可

😁 想得有点多,至于为什么就不说了吧,这个锅还得不想背而背

2️⃣ 既然让后端处理不可能,那就自己来吧(没有js搞不了的),既然是旋转出错了,那是不是只要旋转了我就把它旋转回来了,美不美?

🙈 想得美~~

3️⃣ 怎样找到是否旋转了? —> 神器:exif-js

1
npm i exif-js -S

import { EXIF } from 'exif-js';

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* imagechanged vue图片上传组件前处理逻辑
*
* @param {Obejct} file 图片对象
* @author 沈萬三
* @anotherdate 2018-10-09T14:48:03+080
*/
imagechanged(file) {
let _this = this;
EXIF.getData(file, function() {
EXIF.getAllTags(this);
let orientation = EXIF.getTag(this, 'Orientation');
console.log('旋转数值:' + orientation);
// 修复ios上传图片的时候 被旋转的问题
let newImage;
let canvas = document.createElement('canvas');
// 创建一个reader
let reader = new FileReader();
// 将图片2将转成 base64 格式
reader.readAsDataURL(file);
reader.onloadend = function() {
let img = new Image();
img.src = this.result;
img.onload = function() {
switch (orientation) {
// 需要顺时针(向左)90度旋转
case 6:
newImage = _this.rotateImg(img, 'left', canvas);
break;
// 需要逆时针(向右)90度旋转
case 8:
newImage = _this.rotateImg(img, 'right', canvas);
break;
// 需要180度旋转,// 转两次
case 3:
newImage = _this.rotateImg(img, 'right', canvas);
newImage = _this.rotateImg(img, 'right', canvas);
break;
default:
newImage = _this.rotateImg(img, 'none', canvas);
break;
}
// let newFile = _this.dataURLtoFile(newImage.src, file.name);
// console.log(newFile);
_this.uploadFile(newFile);
return;
}
};
});
// this.uploadFile(file);
}

4️⃣ 可以看到 _this.uploadFile(newFile); 这个表示最后this.rotateImg 后再自己做上传,为什么都旋转呢?正常的可以不用旋转啊?因为Nginx有大小限制必须压缩,为了一个小功能我偷懒了将旋转和压缩放在一起了,实际上不建议这样做,最好是各自做各自的事情(就一个上传头像的小功能算了,不折腾了)

5️⃣ this.rotateImg 什么逻辑?这就是重点了,毫无疑问在以前肯定会找一个flash插件将之旋转?so?选flash插件?我才不要入坑,瞬间想到canvas,一查资料果然可以~😁😁😁 完美

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* rotateImg 旋转图片
*
* @param {Obejct} img 图片file对象
* @param {Number} direction 旋转的参数
* @param {Object} canvas 对象
* @author 沈萬三
* @anotherdate 2018-10-09T14:46:47+080
*/
rotateImg(img, direction, canvas) {
// 最小与最大旋转方向,图片旋转4次后回到原方向
const minStep = 0;
const maxStep = 3;
if (img == null) return;
// img的高度和宽度不能在img元素隐藏后获取,否则会出错
let height = img.height;
let width = img.width;
let step = 2;
if (step === null) {
step = minStep;
}
if (direction === 'right') {
step++;
// 旋转到原位置,即超过最大值
step > maxStep && (step = minStep);
} else if (direction === 'none') {
step = 0;
} else {
step--;
step < minStep && (step = maxStep);
}
// 旋转角度以弧度值为参数
let degree = step * 90 * Math.PI / 180;
let ctx = canvas.getContext('2d');
let newImage = new Image();
let imageData;
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;
}
imageData = canvas.toDataURL('Image/jpeg', 0.1);
newImage.src = imageData;
return newImage;
}

🦁 哟哟哟~~ 浪起来~~~ 完美! 点击上传,啪!报错了?叫你高兴得太早,嘚瑟吧?什么原因? this.rotateImg返回的是一个<img src="xxx">难道post formdata不应该是一个file对象so是不是应该将之转换成file对象?怎么转?查资料了是可以的?但是怎么将<img src="xxx">转成file对象?首先想到的是base64,有其他方法,但是我首先想到的是他,不能浪费时间了就是他!因为new FileReader() 出来的src就是base64,还想啥想?

1
2
// 👇 请把下面这行注释打开
// let newFile = _this.dataURLtoFile(newImage.src, file.name);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* dataURLtoFile base64转换成file对象
*
* @param {String} dataUrl 图片url
* @param {String} fileName 文件名称
* @author 沈萬三
* @anotherdate 2018-10-09T14:45:05+080
*/
dataURLtoFile(dataUrl, fileName) {
// 将base64转换为文件
let arr = dataUrl.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], fileName, {
type: mime
});
}

🐬 到此为止真的是完美解决了哦,意不意外!惊不惊喜!刺不刺激!


🌾 温馨提示:遇到问题不要怕,一步一步分析,不要想着一下解决,一步一步来会快很多,一个问题一个问题解决最后就真的解决了!!!


图片上传前旋转压缩处理
https://seven3.site/js/图片上传前旋转压缩处理/
作者
Seven3s
发布于
2018年10月9日
许可协议