问题
在通信体验活动
这个项目中需要用到手机上传照片,在ios低版本手机上会出现上传图片旋转的问题,因此需要对低版本上传的照片根据旋转的角度再次旋转回来。
方法
在判断角度中使用到exif信息查看器
- 首先在项目中引入exif-js-min
import exifmin from '../assets/exif-js-min'
- 获取版本信息,对ios大于13.4的系统不做图片旋转
逆时针四个方向的数字,是6、1、3、8,在ios低与13.4个高于13.4的系统中出现的是相同的,只是低于13.4的会旋转。
// 获取版本信息
getVersion (name) {
var arr = navigator.userAgent.split(' ');
var chromeVersion = '';
let result = 0;
const reg = new RegExp(name, 'i')
for(var i=0;i < arr.length;i++){
if(reg.test(arr[i]))
chromeVersion = arr[i]
}
if(chromeVersion){
result = chromeVersion.split('/')[1].split('.');
} else {
result = ['0', '0', '0'];
}
return result
},
- 对旋转的图片进行角度旋转
- 在低版本上 6:逆时针旋转的90度,需要顺时针旋转90度
- 1没有旋转
- 8顺时针旋转了90度,需要逆时针旋转90度
- 3方向倒了,旋转了180度,需要顺时针或者逆时针旋转180度
//旋转图片函数
rotateImgFun(objectURL,fileName){
let img = new Image();
img.onload = () => {
let width = img.width;
let height = img.height;
let orientation;
exifmin.getData(img).then(data => {
orientation = data.orientation || 1;
if (this.getVersion('safari')[0] >= 605 ) {
const safariVersion = this.getVersion('version')
if (safariVersion[0] > 13 && safariVersion[1] > 1) {
orientation = -1
}
} else {
// 判断 ios 版本进行处理
// 针对 ios 版本大于 13.4的系统不做图片旋转
const isIos = navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?) like mac os/)
if (isIos) {
let version = isIos[1]
version = version.split('_')
if (version[0] > 13 || (version[0] >= 13 && version[1] >= 4)) {
orientation = -1
}
}
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
ctx.save();
switch (orientation) {
case 6:
canvas.width = height;
canvas.height = width;
//90 graus
ctx.translate(height / 2, width / 2);
ctx.rotate((90 * Math.PI) / 180);
ctx.translate(-width / 2, -height / 2);
break;
case 8:
canvas.height = width;
canvas.width = height;
//-90 graus
ctx.translate(height / 2, width / 2);
ctx.rotate((-90 * Math.PI) / 180);
ctx.translate(-width / 2, -height / 2);
break;
case 3:
canvas.width = width;
canvas.height = height;
//180 graus
ctx.translate(width / 2, height / 2);
ctx.rotate((180 * Math.PI) / 180);
ctx.translate(-width / 2, -height / 2);
break;
//备份(可能出现的其他情况)
case 2:
canvas.width = width;
canvas.height = height;
// horizontal flip
ctx.translate(width, 0);
ctx.scale(-1, 1);
break;
case 4:
canvas.width = width;
canvas.height = height;
// vertical flip
ctx.translate(0, height);
ctx.scale(1, -1);
break;
case 5:
// vertical flip + 90 rotate right
canvas.height = width;
canvas.width = height;
ctx.rotate(0.5 * Math.PI);
ctx.scale(1, -1);
break;
case 7:
// horizontal flip + 90 rotate right
canvas.height = width;
canvas.width = height;
ctx.rotate(0.5 * Math.PI);
ctx.translate(width, -height);
ctx.scale(-1, 1);
break;
default:
canvas.width = width;
canvas.height = height;
}
ctx.drawImage(img, 0, 0, width, height);
ctx.restore();
let base64 = canvas.toDataURL();
console.log('base',base64);
document.getElementById('img').setAttribute('src',base64)
});
}
img.src = objectURL
},
- exif-js-min.js
/* eslint-disable */
const Exif = {};
Exif.getData = (img) => new Promise((reslove, reject) => {
let obj = {};
getImageData(img).then(data => {
obj.arrayBuffer = data;
obj.orientation = getOrientation(data);
reslove(obj)
}).catch(error => {
reject(error)
})
})
// 这里的获取exif要将图片转ArrayBuffer对象,这里假设获取了图片的baes64
// 步骤一
// base64转ArrayBuffer对象
function getImageData(img) {
let data = null;
return new Promise((reslove, reject) => {
if (img.src) {
if (/^data\:/i.test(img.src)) { // Data URI
data = base64ToArrayBuffer(img.src);
reslove(data)
} else if (/^blob\:/i.test(img.src)) { // Object URL
var fileReader = new FileReader();
fileReader.onload = function (e) {
data = e.target.result;
reslove(data)
};
objectURLToBlob(img.src, function (blob) {
fileReader.readAsArrayBuffer(blob);
});
} else {
var http = new XMLHttpRequest();
http.onload = function () {
if (this.status == 200 || this.status === 0) {
data = http.response
reslove(data)
} else {
throw "Could not load image";
}
http = null;
};
http.open("GET", img.src, true);
http.responseType = "arraybuffer";
http.send(null);
}
} else {
reject('img error')
}
})
}
function objectURLToBlob(url, callback) {
var http = new XMLHttpRequest();
http.open("GET", url, true);
http.responseType = "blob";
http.onload = function (e) {
if (this.status == 200 || this.status === 0) {
callback(this.response);
}
};
http.send();
}
function base64ToArrayBuffer(base64) {
base64 = base64.replace(/^data\:([^\;]+)\;base64,/gmi, '');
var binary = atob(base64);
var len = binary.length;
var buffer = new ArrayBuffer(len);
var view = new Uint8Array(buffer);
for (var i = 0; i < len; i++) {
view[i] = binary.charCodeAt(i);
}
return buffer;
}
// 步骤二,Unicode码转字符串
// ArrayBuffer对象 Unicode码转字符串
function getStringFromCharCode(dataView, start, length) {
var str = '';
var i;
for (i = start, length += start; i < length; i++) {
str += String.fromCharCode(dataView.getUint8(i));
}
return str;
}
// 步骤三,获取jpg图片的exif的角度(在ios体现最明显)
function getOrientation(arrayBuffer) {
var dataView = new DataView(arrayBuffer);
var length = dataView.byteLength;
var orientation;
var exifIDCode;
var tiffOffset;
var firstIFDOffset;
var littleEndian;
var endianness;
var app1Start;
var ifdStart;
var offset;
var i;
// Only handle JPEG image (start by 0xFFD8)
if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
offset = 2;
while (offset < length) {
if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
app1Start = offset;
break;
}
offset++;
}
}
if (app1Start) {
exifIDCode = app1Start + 4;
tiffOffset = app1Start + 10;
if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
endianness = dataView.getUint16(tiffOffset);
littleEndian = endianness === 0x4949;
if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
if (firstIFDOffset >= 0x00000008) {
ifdStart = tiffOffset + firstIFDOffset;
}
}
}
}
}
if (ifdStart) {
length = dataView.getUint16(ifdStart, littleEndian);
for (i = 0; i < length; i++) {
offset = ifdStart + i * 12 + 2;
if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {
// 8 is the offset of the current tag's value
offset += 8;
// Get the original orientation value
orientation = dataView.getUint16(offset, littleEndian);
// Override the orientation with its default value for Safari (#120)
// if (IS_SAFARI_OR_UIWEBVIEW) {
// dataView.setUint16(offset, 1, littleEndian);
// }
break;
}
}
}
return orientation;
}
export default Exif