Hello uni-app 模板 https://uniapp.dcloud.io/h5/pcguide.html
接口---媒体---图片,在图片页面操作,点击“+”,选择拍照显示的图片会旋转-90°,选择图库显示的图片是正确的
1、型号:iPhone XR ,版本:IOS 12.2,微信版本:V 7.0.3,微信扫码进入
2、型号:Mi Note3,版本:MIUI 10.3,微信版本:V 7.0.4,微信扫码进入
说下场景,uniapp开发移动端h5页面,在选择手机相册图片及拍照图片时,会发生旋转90度问题。废话不多少,直接说思路。
1.判断图片是否旋转,这里的坑是chooseImage返回的是临时路径,而uniapp并没有提供h5中的保存临时文件的api,所以这里用的是ajax请求 返回的临时路径(Blob Url格式的),请求回来的blob二进制数据可以让我们得到图片的大小已经方向等图片属性
2.对旋转图片进行处理 (旋转 压缩) ,这里网上很多网友使用的是exif-js,但我是在网上找了别人的方法,发现也好使,代码会在最后统一粘贴
这一步遇到的坑是,由于最后图片处理后需要上传服务端(OSS),所以我提前把处理旋转得到的base64转成了临时文件的url,但发现转换的url 本地浏览器能打开,但手机上无法显示。只能把这一步转换放在了最后上传处
var imagePathArr = e.tempFilePaths
var promiseArr = []
var resArr = []
for (let i = 0; i < imagePathArr.length; i++) {
let promise = new Promise(function(resolve, reject) {
var obj = {
index: i
}
var url = imagePathArr[i];
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.onload = function() {
if (this.status == 200) {
var blob = this.response;
var imgSize = blob.size / 1024
// alert(imgSize)
const reader = new FileReader();
reader.readAsDataURL(blob);
/* eslint-disable func-names */
// 箭头函数会改变this,所以这里不能用肩头函数
reader.onloadend = function(res) {
// this.result就是转化后的结果
var img_base64 = res.target.result;
if (imgSize > _self.$config.imageSize) { // 需要压缩处理
_self.photoCompress(img_base64, {
quality: 0.5
}, function(tempBase64) {
_self.getOrientation(blob, function(orientation) {
// @param {string} img 图片的base64
// @param {int} dir exif获取的方向信息
// @param {function} next 回调方法,返回校正方向后的base64
if (orientation == 3 || orientation == 6 || orientation == 8) { // 图片发生旋转
_self.getImgData(tempBase64, orientation, function(res1) {
_self.base64ByBlob(res1, function(blobObj) {
var url = window.URL.createObjectURL(blobObj)
obj.url = res1
resolve(obj)
})
})
} else {
obj.url = tempBase64
resolve(obj)
}
});
})
} else {
_self.getOrientation(blob, function(orientation) {
// @param {string} img 图片的base64
// @param {int} dir exif获取的方向信息
// @param {function} next 回调方法,返回校正方向后的base64
if (orientation == 3 || orientation == 6 || orientation == 8) { // 图片发生旋转
_self.getImgData(img_base64, orientation, function(res1) {
_self.base64ByBlob(res1, function(blobObj) {
var url = window.URL.createObjectURL(blobObj)
obj.url = res1
resolve(obj)
})
})
} else {
obj.url = url
resolve(obj)
}
});
}
};
}
}
xhr.send();
})
promiseArr.push(promise);
}
Promise.all(promiseArr).then(res => {
var imgArr = []
for (var i = 0; i < res.length; i++) {
imgArr.push(res[i].url)
_self.imageList.push(res[i].url)
}
_self.$emit('add', {
currentImages: imgArr,
allImages: _self.imageList
})
_self.$emit('input', _self.imageList)
})
//将以base64的图片url数据转换为Blob
convertBase64UrlToBlob(urlData) {
var arr = urlData.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {
type: mime
});
},
/*
压缩图片 三个参数
path:图片地址 base64
obj:一个是文件压缩的后宽度,宽度越小,字节越小
callback:回调函数
*/
photoCompress(path, obj, callback) {
var img = new Image();
img.src = path;
img.onload = function() {
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.7; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
}
},
// base64转blob
base64ByBlob(base64, callback) {
var arr = base64.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
console.log(new Blob([u8arr], {
type: mime
}))
callback(new Blob([u8arr], {
type: mime
}))
},
// 获取图片当前方向
getOrientation(file, callback) {
var reader = new FileReader();
reader.onload = function(event) {
var view = new DataView(event.target.result);
if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
var length = view.byteLength,
offset = 2;
while (offset < length) {
var marker = view.getUint16(offset, false);
offset += 2;
if (marker == 0xFFE1) {
if (view.getUint32(offset += 2, false) != 0x45786966) {
return callback(-1);
}
var little = view.getUint16(offset += 6, false) == 0x4949;
offset += view.getUint32(offset + 4, little);
var tags = view.getUint16(offset, little);
offset += 2;
for (var i = 0; i < tags; i++)
if (view.getUint16(offset + (i * 12), little) == 0x0112)
return callback(view.getUint16(offset + (i * 12) + 8, little));
} else if ((marker & 0xFF00) != 0xFF00) break;
else offset += view.getUint16(offset, false);
}
return callback(-1);
};
reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
},
// @param {string} img 图片的base64
// @param {int} dir exif获取的方向信息
// @param {function} next 回调方法,返回校正方向后的base64
getImgData(img, dir, next) {
var image = new Image();
image.onload = function() {
var degree = 0,
drawWidth, drawHeight, width, height;
drawWidth = this.naturalWidth;
drawHeight = this.naturalHeight;
//以下改变一下图片大小
var maxSide = Math.max(drawWidth, drawHeight);
if (maxSide > 1024) {
var minSide = Math.min(drawWidth, drawHeight);
minSide = minSide / maxSide * 1024;
maxSide = 1024;
if (drawWidth > drawHeight) {
drawWidth = maxSide;
drawHeight = minSide;
} else {
drawWidth = minSide;
drawHeight = maxSide;
}
}
var canvas = document.createElement('canvas');
canvas.width = width = drawWidth;
canvas.height = height = drawHeight;
var context = canvas.getContext('2d');
//判断图片方向,重置canvas大小,确定旋转角度,iphone默认的是home键在右方的横屏拍摄方式
switch (dir) {
//iphone横屏拍摄,此时home键在左侧
case 3:
degree = 180;
drawWidth = -width;
drawHeight = -height;
break;
//iphone竖屏拍摄,此时home键在下方(正常拿手机的方向)
case 6:
canvas.width = height;
canvas.height = width;
degree = 90;
drawWidth = width;
drawHeight = -height;
break;
//iphone竖屏拍摄,此时home键在上方
case 8:
canvas.width = height;
canvas.height = width;
degree = 270;
drawWidth = -width;
drawHeight = height;
break;
}
//使用canvas旋转校正
context.rotate(degree * Math.PI / 180);
context.drawImage(this, 0, 0, drawWidth, drawHeight);
//返回校正图片
next(canvas.toDataURL("image/png"));
}
image.src = img;
}
这个功能也是刚写完,可能有些地方还有问题,大的方向上是正确的。希望能帮助大家
最后上传图片时,进行判断,base64格式的话,先转成Blob URL格式,在进行阿里云oss上传
var filePath = tempFilePaths[_i]
// 判断是否需要base64转换
var reg = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i;
if(reg.test(filePath)){
_this.base64ByBlob(filePath, function(blobObj) {
filePath = window.URL.createObjectURL(blobObj)
})
}
风残落叶
如果是app端怎么解决
2020-06-23 14:53
睡着就睡着了
回复 风残落叶: 同问
2020-12-17 13:45