微信小程序上传照片后旋转问题解决

Posted on 2019-09-11 |    

前言

又是好久好久好久没更新了,太懒了

这次记录一下在做mini项目中遇到的一个问题,当时没时间解决,mini结束后还是打算看看这个问题。

问题说明

当时是这样的,微信小程序在上传照片后,会有一定概率旋转,查阅了资料之后,发现是和图片中携带的exif信息中的orientation这个参数有关。

这里有一个关于EXIF 和 Orientation 相关的传送门:
使用 JavaScript 读取 JPEG 文件 EXIF 信息中的 Orientation 值

当时是让想让后端进行解析并旋转的,不过后端说有时候能拿到这个信息,有时候拿不到,这个是可能小程序在上传时设置是否压缩有关,如果压缩了,会将exif信息给删除。

后面由于图片上传到服务器前也需要预览,所以在后端进行旋转是不合适的。

前端旋转的话看了一下,小程序中通过getImageInfo这个接口中可以获得orientation 的信息,喜大普奔,那我们只要知道旋转的角度,再旋转回来即可。

解决方案

小程序 orientation 参数

小程序 orientation 参数情况如下所示:

小程序图片旋转关键代码

图片的旋转处理这里用到了canvas

在wxml文件中添加canvas元素,这里id我就设置的为canvas

1
<canvas canvas-id="canvas" style="width:{{imageWidth}}px;height:{{imageHeight}}px;position:absolute;top:200%" ></canvas>

这里具体讲一下旋转180度的情况

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
wx.getImageInfo({
src: tempFilePaths[0],
success:(res)=>{
//获得exif中的orientation信息
if(res.orientation=="up"){
this.setData({
chosenImage: tempFilePaths[0],
})
}else{
let canvasContext = wx.createCanvasContext('canvas')
switch (res.orientation) {
case ("down"):
var width = res.width;
var height = res.height
//需要旋转180度
this.setData({
imageWidth: width,
imageHeight: height,
})
canvasContext.translate(width / 2, height / 2)
canvasContext.rotate(180 * Math.PI / 180)
canvasContext.drawImage(tempFilePaths[0], -width / 2, -height / 2, width, height);
break;
canvasContext.draw()
this.drawImage()
}
}
})

三步走:

1、这里通过translate将原点设置为图像中心
2、通过rotate进行旋转相应的角度,这里rotate是以刚刚设置的原点为中心进行旋转的
3、通过drawImage绘制图片

这样图片就旋转好了吗?
当然还没有,这只是在canvas上完成了旋转,需要将canvas生成图片

【注】由于canvas的绘制(draw())需要一定的时间,所以这里设置了一个定时器,这里设置了2秒,如果没有这个定时器,可能会发生图片并没有绘制结束就转为图片的情况,那图片可能就是空白的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
drawImage:function(path) {
var that = this;
setTimeout(()=>{
// 将生成的canvas图片,转为真实图片
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: 'canvas',
success(res) {
let shareImg = res.tempFilePath;
that.setData({
chosenImage: res.tempFilePath,
})
},
fail: function (res) {
}
})
}, 2000)
}

【注】有关canvas的旋转,你需要了解一下canvas的坐标系的问题,一开始没有先看这方面的内容,想当然了,导致绘制出来的东西是空白的,后面了解了之后发现就是坐标系没弄清楚,导致设定绘制的图片时,坐标系的值弄错了,画到了画布外面,导致空白,这里给一个传送门,大家可以看这篇文章:
canvas 图像旋转与翻转姿势解锁

旋转90度和旋转270度同理,这里不再赘述

贴一下完整代码

当然,可能还有镜像翻转的情况,这里比较懒,就没弄了,也是差不多的。

1
2
3
4
5
6
7
8
9
10
11
12
<view class="container" style="">
<view>
<button bindtap="chooseImage">上传</button>

</view>
<view style="">
<image src="{{chosenImage}}" mode="widthFix" bindtap="" style="width:300px;"></image>
</view>

<canvas canvas-id="canvas" style="width:{{imageWidth}}px;height:{{imageHeight}}px;position:absolute;top:200%" ></canvas>

</view>
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
chooseImage:function(){
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
// tempFilePath可以作为img标签的src属性显示图片
const tempFilePaths = res.tempFilePaths
wx.getImageInfo({
src: tempFilePaths[0],
success:(res)=>{
//获得exif中的orientation信息
if(res.orientation=="up"){
this.setData({
chosenImage: tempFilePaths[0],
})
}else{
let canvasContext = wx.createCanvasContext('canvas')
console.log(res.orientation)
switch (res.orientation) {
case ("down"):
var width = res.width;
var height = res.height
//需要旋转180度
this.setData({
imageWidth: width,
imageHeight: height,
})
canvasContext.translate(width / 2, height / 2)
canvasContext.rotate(180 * Math.PI / 180)
canvasContext.drawImage(tempFilePaths[0], -width / 2, -height / 2, width, height);
break;
case ("left"):
var width = res.width;
var height = res.height;
canvasContext.translate(height / 2, width / 2)
this.setData({
imageWidth: height,
imageHeight: width,
})
//顺时针旋转270度
canvasContext.rotate(270 * Math.PI / 180)
canvasContext.drawImage(tempFilePaths[0], - width / 2, - height / 2, width , height);
break;
case ("right"):
var width = res.width;
var height = res.height;
this.setData({
imageWidth: height,
imageHeight: width,
})
canvasContext.translate(height / 2, width / 2)
//顺时针旋转90度
canvasContext.rotate(90 * Math.PI / 180)
canvasContext.drawImage(tempFilePaths[0], - width / 2, - height / 2, width, height);
break;
}
canvasContext.draw()
this.drawImage()
}

}
})

}
})
},
drawImage:function(path) {
var that = this;
setTimeout(()=>{
// 将生成的canvas图片,转为真实图片
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: 'canvas',
success(res) {
let shareImg = res.tempFilePath;
that.setData({
chosenImage: res.tempFilePath,
})
},
fail: function (res) {
}
})
}, 2000)
}