移动端(ios、android)上传图片遇到的兼容问题

最近接了一个需求,需要做上传,框架用多了,本来以为这些东西拿过来直接用就行,但是在开发过程中发现了一些问题:

一、安卓手机上传图片没有拍照选项、ios没有拍照选择相册功能

1、按照以下方式写安卓手机没有拍照选项,只能传图片

1
<input type="file" name="pic" id="pic" accept="image/gif, image/jpeg" />

2、按照以下方式写ios手机正常,有选择图片和拍照上传功能,安卓手机大部分没有问题,但是安卓10版本没有拍照上传功能

1
<input type="file" id="choose" accept="image/*"  multiple>

3、按照以下方式写ios手机直接唤起拍照功能,没有选择图片上传功能,(安卓10版本预计可以拍照上传)

1
<input type="file" id="choose" accept="image/*" capture="camera" multiple>

accept表示打开的系统文件目录
capture表示的是系统所捕获的默认设备,
camera:照相机;camcorder:摄像机;microphone:录音;
其中还有一个属性multiple,支持多选,当支持多选时,multiple优先级高于capture,所以只用写成:

二、优化上传图片增加图片上传压缩功能

用canvas压缩图片的原理就是读取图片的文件,然后把图片画在画布上,再用canvas自带的一个接口:

1
canvas.toDataURL(type,encoderOptions);

第二个参数encoderOptions决定了图片压缩的程度,可以在0-1中选择一个值,当然推荐不要低于0.5,因为这样保存后的图片质量不太好。
这个方法执行完后会返回一个值,就是图片的base64格式的字符串,这个字符串就可以上传到服务端。

三、移动端IOS系统手机拍照图片Canvas压缩上传后图片旋转的bug

网上大部分是说exfe.js来读取图片信息,我们上传的图片里面是有很多信息的
这里我们需要拿到Orientation的值有1,3,6,8之类的,分别代表0°,180°,顺时针90°,逆时针90°
Orientation
图片原文

1
2
3
4
5
6
7
8
9
10
11
//获取照片方向角属性,用户旋转控制

EXIF.getData(file, function() {

EXIF.getAllTags(this);

Orientation = EXIF.getTag(this, 'Orientation');

console.log(Orientation);

});

但是,这里正常是我拿到角度之后绘制图片按照角度回正,大部分机器是没有问题的,安卓手机测试了下,什么角度拍照Orientation都为1,IOS的Orientation都是按照角度返回的,但是在IOS13.4版本以后,带有角度上传的图片也不会旋转,所以需要版本号判断IOS13.4以后不做回正处理

1
2
3
4
5
let iosVersion = UserAgent.str.match(/CPU iPhone OS (.*?) like Mac OS/);
if(UserAgent.env.ios && iosVersion && compareVersion([13,4],iosVersion[1].split('_'))<0){
callback(-5);
return
}
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
const canvas = document.createElement('canvas');
canvas.width = width = drawWidth;
canvas.height = height = drawHeight;
const context = canvas.getContext('2d');
//判断图片方向,重置canvas大小,确定旋转角度,iphone默认的是home键在右方的横屏拍摄方式
switch (dir) {
//iphone横屏拍摄,此时home键在左侧
case 3:
degree = 180;
startX = - width;
startY = - height;
drawWidth = width;
drawHeight = height;
break;
//iphone竖屏拍摄,此时home键在下方(正常拿手机的方向)
case 6:
canvas.width = height;
canvas.height = width;
degree = 90;
startY = - height;
drawWidth = width;
drawHeight = height;
break;
//iphone竖屏拍摄,此时home键在上方
case 8:
canvas.width = height;
canvas.height = width;
degree = 270;
startX = - height;
drawWidth = width;
drawHeight = height;
break;
default:
}
//使用canvas旋转校正
context.rotate(degree * Math.PI / 180);
//canvas rotate旋转角度是根据原点(0,0)开始旋转的,所以绘制的起始坐标需要改变,并不是一直从0,0绘制
context.drawImage(this, startX, startY, drawWidth, drawHeight);

四、前端上传图片利用canvas水印合成

大体步骤:

用户使用input file上传图片的时候,利用 FileReader ,读取 blob对象 ,或者是 file对象 ,将图片转化为 data uri (base64格式)的形式。
使用 canvas ,在页面上新建一个画布,利用 canvas 提供的API,将图片画入这个画布当中。
利用 canvas.toDataURL() ,进行图片的压缩,得到图片的 data uri 的值,用来上传。
获取到压缩后的base64格式图片数据,转成二进制塞入formdata,再通过XmlHttpRequest提交formdata。

参照文章
参照文章
参照文章水印合成