靈兒
靈兒
  • 发布:2019-04-25 16:36
  • 更新:2020-05-21 13:47
  • 阅读:4567

【报Bug】Hello uni-app 模板中,H5平台图片选择拍照显示会旋转-90°

分类:uni-app

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,微信扫码进入

2019-04-25 16:36 负责人:无 分享
已邀请:
5***@qq.com

5***@qq.com

说下场景,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;  
			}  

这个功能也是刚写完,可能有些地方还有问题,大的方向上是正确的。希望能帮助大家

2***@qq.com

2***@qq.com - ddd

同问题。。

2***@qq.com

2***@qq.com - ddd

解决了吗

  • 靈兒 (作者)

    木有。


    2019-04-28 13:51

fffsfgds

fffsfgds

请问 这个问题解决了么

口区

口区 -

同样的问题

fffsfgds

fffsfgds

这个问题已经解决 稍后会总结一下 然后公布出来 急需的可私聊我 q 二四零3799一八六

5***@qq.com

5***@qq.com

这个是生成画布的时候造成的,需要更改下生成方式吧。。

z***@126.com

z***@126.com

请问解决了吗

5***@qq.com

5***@qq.com

https://www.jianshu.com/p/8afd55beca5a

s***@163.com

s***@163.com

同问题。。

5***@qq.com

5***@qq.com

最后上传图片时,进行判断,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)  
   })  
}
yyer

yyer

如何解决这个问题

花开美时

花开美时 - F2E小助理

这个问题都没有官方出来说明一下?选择确实碰到好多机型都会出现使用uni.chooseImage选择照片之后自动逆时针旋转90度

  • 风残落叶

    一样,app端还有小程序都不知道怎么处理


    2020-07-02 11:21

该问题目前已经被锁定, 无法添加新回复