寒假比赛总结(一) - 解决HTML移动端竖拍照片旋转90度的问题

前言

在这次寒假比赛中遇到了许多坑,有些坑堪称奇葩,比如说下面这个比较神奇的坑:HTML5中类型为file的input元素在上传图片,展示出来后,某些手机竖拍的照片会逆时针旋转90度的问题。

概述

发现这个bug大概在一周前,因为我们这个比赛项目需要用户上传图片,并能在发布之前预览。在预览的时候发现竖着拍的照片居然都旋转了90度!于是Google之,发现基本上所有机型手机的相机都存在这个问题(我当时用于测试的手机是小米Note3 MIUI 9,期间也尝试过iPhone、iPad等机型,均发现此问题)。导致旋转90度的原因大概是HTML自动将旋转角减去了90度。

解决问题

用到的工具/库

要解决这个问题,首先需要读取照片的旋转角度(Orientation),而EXIF.JS可以读出照片的旋转角度:

http://lenconda.top/images/18020201.png


我拿了一张用小米Note3的相机拍摄的照片测试,根据EXIF.JS读出的信息得出这张图片的方向角度是90度。

思路

其实用EXIF.JS读出来是一堆tags,从tags中找到Orientation的值,如果图片的方向是90度,那么Orientation的值就为6。
所以,我们只需要在拿到图片之后放进EXIF.JS里判断一下Orientation的值是否为6,如果为6,那么就将图片绘制到一个隐藏的Canvas里,再使用Canvas的rotate API进行旋转,最后再将修改好的图片输出。

步骤

  • 在Webpack项目中安装EXIF.JS:
npm install exif-js --save
  • 在项目中引入EXIF.JS:
import EXIF from 'exif-js'
  • 读出图片旋转角:
const _this = this
EXIF.getData($IMG_SRC, () => {
    if (EXIF.getAllTags($IMG_SRC).Orientation == 6) {
        Utils.rotateImg($IMG_SRC, _this) //如果Orientation为6,就交给Utils中的rotateImg方法
    } else {
        _this.imgList.push($IMG_SRC) //如果假,就不做处理
    }
})
  • Utils中的图片处理方法
rotateImg: (imgSrc, vue) => {
    function getObjectURL (object) {
      return (window.URL) ? window.URL.createObjectURL(object) : window.webkitURL.createObjectURL(object)
    }
    function dataURLtoBlob (dataurl) {
      var arr = dataurl.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 });
    }
    var canvas = document.createElement('canvas') //新建一个Canvas元素,隐藏起来,不appendChild
    var context = canvas.getContext('2d')
    var image = new Image() //新建一个Image对象,拿到IMG_SRC,绘制到Canvas中
    var testSrc
    image.src = imgSrc
    image.onload = () => {
      var imgRealWidth = image.width
      var imgRealHeight = image.height
      canvas.width = imgRealHeight
      canvas.height = imgRealWidth
      context.rotate(90 * Math.PI / 180) //顺时针旋转90度
      context.drawImage(image, 0, -imgRealHeight)
      var result = canvas.toDataURL('image/png')
      var blobObj = dataURLtoBlob(result)
      var file = new File([blobObj], `${Date.now()}.png`, {type: 'image/png'}) //输出修改好的图片
      var pushSrc = getObjectURL(file)
      testSrc = getObjectURL(file) //拿到图片的Blob URL,推到数组中
      vue.imgList.push(pushSrc)
    }
  }

结果

经过好几天的折腾,这个问题终于被解决了,只不过处理的过程有点缓慢,容易影响用户体验。

总结

这个Bug也不知道是手机设备厂商的锅还是HTML5的锅,感觉问题比较棘手,虽然最后解决了,但是还是觉得毒性很强。🌚

将最新的文章发送到你的邮箱

展示评论