之前做支付宝H5项目的时候做过input选图旋转问题,最近又有一个类似的项目,故整理下供以后查阅。
首先说明,本文只针对于因为受限制于环境问题,页面为h5且上传不得不使用原生input控件的情况,情况允许的话尽量使用平台原生能力或sdk等,比如wx-js-sdk。
文件限制
单一的文件限制可以使用accept属性:
// 仅限定类型
<input type="file" id="input" accept="image/*" />
// 限定格式
<input type="file" id="input" accept="image/gif, image/jpeg" />
需要注意的是,accept仅支持一种类型文件的多个格式,多类型的仅以第一个类型为准,下面是一个错误的栗子:
// 下面这个例子点击input仅能选择图片,后面的video被自动忽略
<input type="file" id="input" accept="image/*, video/*" />
多文件类型在选择后再进行判定:
let files = document.getElementById("input").files[0];
let fileArr = files.name.split('.')
// 某些文件名中会出现"."号,要确保取到最后一个才是文件扩展名
let fileType = fileArr[fileArr.length - 1]
获取到扩展名后即可使用正则等方法进行判定,如果不是需要的格式可以弹窗提醒。
移动端图片常见扩展名:jpg(jpeg),png,gif
移动端视频常见扩展名:MP4(mpeg4),mov(ios录屏格式)
移动端音频常见扩展名:mp3,aac(Android录音格式),m4a(ios录音格式)
图片预览处理
图片旋转问题本来是ios才有的,但是现在越来越多的Android手机也开始出现这样的问题,理解起来也不难,摄像头成像依靠感光元件成像,感光元件的方向是固定的(一般是横向),但是拍照的方向是不确定的,为了修正图片的方向问题,会在照片的exif信息中记录旋转的方向,在显示的时候将其转回正常的视角。浏览器大多是不支持通过读取exif来旋转图片的(新版chrome可以自动调整地址栏为图片的图片显示,但是页面中的background及image还是需要手动进行校正),所以需要我们手动来把图片转回来,否则会使用户产生选择的时候明明是正的图片到了网页中就被旋转了的错觉。
使用exif.js判断旋转方向以及使用canvas回正图片的示例代码:
<script src="https://cdn.jsdelivr.net/npm/exif-js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let files = document.getElementById("input").files[0];
EXIF.getData(files, function() {
let Orientation = EXIF.getTag(this, 'Orientation')
if (!Orientation || Orientation < 3) {
// 不需要处理
} else {
// 做旋转处理
rotateImage(files, Orientation)
}
})
function rotateImage(file, Orientation) {
let img = new Image()
img.src = this.getFileURL(file)
// 确保图片加载完成
img.onload = () => {
let expectWidth = img.naturalWidth;
let expectHeight = img.naturalHeight;
// 判断图片宽大于高,并且宽大于800的话让图片宽度为800,相应等比改变图片高度
if (img.naturalWidth > img.naturalHeight && img.naturalWidth > 800) {
expectWidth = 800;
expectHeight = expectWidth * img.naturalHeight / img.naturalWidth;
} else if (img.naturalHeight > img.naturalWidth && img.naturalHeight > 1200) {
// 判断图片高大于宽,并且高大于1200的话让图片高度为1200,相应等比改变图片高度
expectHeight = 1200;
expectWidth = expectHeight * img.naturalWidth / img.naturalHeight;
}
// 创建画布设置画布宽高
let canvas = document.createElement('canvas');
let ctx = canvas.getContext("2d");
switch (Orientation) {
case 6: //需要顺时针(向左)90度旋转
canvas.width = expectHeight;
canvas.height = expectWidth;
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(img, 0, 0 - expectHeight, expectWidth, expectHeight);
break;
case 8: //需要逆时针(向右)90度旋转
canvas.width = expectHeight;
canvas.height = expectWidth;
ctx.rotate(-90 * Math.PI / 180);
ctx.drawImage(img, 0 - expectWidth, 0, expectWidth, expectHeight);
break;
case 3: //需要180度旋转
canvas.width = expectWidth;
canvas.height = expectHeight;
ctx.rotate(180 * Math.PI / 180);
ctx.drawImage(img, 0, 0, expectWidth, expectHeight);
break;
}
// 导出base64供页面显示
let base64 = canvas.toDataURL("image/jpeg", 0.8);
}
}
</script>