移动端部分安卓手机(三星,小米)竖拍上传图片预览的时候发生旋转问题

移动端web 页面通过 input type= file 拍照的时候,部分手机图片出现量旋转了90度的问题,出现问题的机型为小米和三星,手机竖着拍的时候出现这种旋转的问题,横拍出来的照片是正常的,结合网上的解决办法总结如下:

主要是用 Orientation 这个参数

这个参数并不是所有的图片都有,不过通过手机拍出来的图片都是带有这个参数的,

旋转角度 参数值
0 1
顺时针90 6
逆时针90 8
180 3

参数为1 的时候显示正常,有问题的机型是竖拍的时候参数为6,(在实测中发现iPhone 6s ios 9系统上发现也是竖排参数为6,但是该手机的预览结果是正常的,这个原因暂时没有深究还)

想要拿到 Orientation 这个参数,可以通过exif.js 库来获取,github地址为:https://github.com/exif-js/exif-js

由于项目是vue 所以就使用 yarn add exif-js --save 来安装

exif.js获取Orientation的代码为:

EXIF.getData(file, function() { var Orientation = EXIF.getTag(this, 'Orientation'); });

该项目要求上传的图片能实现预览压缩,因此使用fileReader.readAsDataURL(file)来实现,

旋转用的是canvas 的rotate()方法实现的,(将上传的图片先用canvas绘制下来,绘制的过程中将需要旋转的转过来,然后在转化成base64来预览,以及传参给后端)

ctx.rotate(angle),

rotate方法的参数为旋转弧度,需要将角度转化为弧度:degress * Math.PI / 180,

压缩:手机拍出来的照片太大,而且使用 base64 编码的照片会比原照片大,那么上传的时候进行压缩就非常有必要的。现在的手机像素这么高,拍出来的照片宽高都有几千像素,用 canvas 来渲染这照片的速度会相对比较慢。

因此第一步需要先对上传照片的宽高做限制,判断宽度或高度是否超出哪个范围,则等比压缩其宽高。

var ratio = width / height;
if(imgWidth > imgHeight && imgWidth > xx){
imgWidth = xx;
imgHeight = Math.ceil(xx / ratio);
}else if(imgWidth < imgHeight && imgHeight > yy){
imgWidth = Math.ceil(yy * ratio);
imgHeight = yy;
}

解下来就是通过 canvas.toDataURL() 方法来压缩照片质量

canvas.toDataURL("image/jpeg", 1);

toDataURL() 方法返回一个包含图片展示的 data URI 。使用两个参数,第一个参数为图片格式,默认为 image/png。第二个参数为压缩质量,在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。

附上VUE项目中的完整代码为:

 

<template>
  <div class="photo">
    <h1>发现身边的投资机会</h1>
    <div class="photo-input">
      <input class="photo-file" type="file" name="upload" accept="image/*"  mutiple="mutiple" @change="fileImg">
      <div class="photo-button">
        <img class="photo-logo" src="../../assets/photo-w.png" alt="">
        <span>拍照识财</span>
      </div>
    </div>
    <div v-if="text">图片上传中...</div>
    <!--<img :src="imgBase64" alt="" id="preview">-->
  </div>
</template>

<script>
import axios from 'axios'
import { EXIF } from 'exif-js'

export default {
  name: 'photo',
  mounted(){

  },
  data () {
    return {
      imgBase64: '',
      text:false
    }
  },
  created () {
    localStorage.clear()
    window.aa = ''
    window.localStorage.clear()
    // localStorage.clear()
  },
  methods: {
    fileImg (e) {
      let that = this
      // localStorage.setItem('imgbase', reader.result)
      console.log(e.target.files[0])
      let Orientation
      let file = e.target.files[0]


      // this.imgPreview(e.target.files[0])
      if(file){
        EXIF.getData(file, function(){
          // var a = EXIF.pretty(this)
          // alert(a[14])
          Orientation = EXIF.getTag(this, "Orientation")
          // alert(Orientation)
        });
      }



      let reader = new FileReader()

      let img = new Image()

      reader.readAsDataURL(e.target.files[0])

      let canvas = document.createElement('canvas')
      let ctx = canvas.getContext('2d')

      reader.onload = (ev) => {
        // alert("图片转base64:"+reader.result)
        // this.imgBase64 = reader.result
        img.src = ev.target.result
        img.onload = function () {
          var imgWidth = this.width
          var imgHeight = this.height

          console.log(this.width)
          console.log(this.height)
          // alert(this.width)
          // alert(this.height)
          let ratio = imgWidth / imgHeight
          if (imgWidth > imgHeight && imgWidth > 600) {
            imgWidth = 400
            imgHeight = Math.ceil(400 / ratio)
          } else if (imgWidth < imgHeight && imgHeight > 900) {
            imgWidth = Math.ceil(200 * ratio)
            imgHeight = 200
          }


          canvas.width = imgWidth
          canvas.height = imgHeight

          if (Orientation && Orientation != 1) {
            switch (Orientation) {
              case 6:
                canvas.width = imgHeight
                canvas.height = imgWidth
                ctx.rotate(Math.PI / 2)
                ctx.drawImage(this, 0, -imgHeight, imgWidth, imgHeight);
                break;
              case 3:
                ctx.rotate(Math.PI);
                ctx.drawImage(this, -imgWidth, -imgHeight, imgWidth, imgHeight);
                break;
              case 8:     // 旋转-90度
                canvas.width = imgHeight;
                canvas.height = imgWidth;
                ctx.rotate(3 * Math.PI / 2);
                ctx.drawImage(this, -imgWidth, 0, imgWidth, imgHeight);
                break;
            }
          } else {
            ctx.drawImage(this, 0, 0, imgWidth, imgHeight);
          }
          this.imgBase64 = canvas.toDataURL("image/jpeg", 0.9)
          // console.log(this.imgBase64)
          window.aa = this.imgBase64
          // console.log(window.aa)
          var len = this.imgBase64.length
          var size = len - (len / 8) * 2
          console.log(size)
          // alert(size)
          that.$router.push('/result/industry')

          // reader.onload = (ev) => {
          //   // alert("图片转base64:"+reader.result)
          //   this.imgBase64 = reader.result
          //   try {
          //     // localStorage.setItem('imgBase64', reader.result)
          //     window.aa = reader.result
          //   } catch (error) {
          //     // console.log("存储localstorage失败"+error)
          //
          //   }

          // try {
          //   // localStorage.setItem('imgBase64', reader.result)
          //   // window.aa = reader.result
          // } catch (error) {
          //   console.log("存储localstorage失败"+error)
          // }
          // alert('base64全局存储完成')
          // this.$router.push('/result/industry')
          // alert('push完成')
        }
      }

    },
    imgPreview(file){
      // let _this = this
      let Orientation
      console.log(file)
      //去获取拍照时的信息,解决拍出来的照片旋转问题
      EXIF.getData(file, function(){
        var a = EXIF.pretty(this)
        // alert(a[14])
        // alert(a[Orientation])
        console.log(a)
        Orientation = EXIF.getTag(this, "Orientation")
        // alert(EXIF.getTag(this, "Orientation"))
        alert(Orientation)

      });
      console.log(Orientation)


    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.photo{
  background: #fff;
  padding:20px;
}
.photo h1{
  display: block;
  font-size:20px;
  padding:10px 0;
}
.photo-input{
  display: block;
  position: relative;
  height:80px;
  margin:50px 0;
}
.photo-file{
  display:block;
  width:100%;
  height:50px;
  position: absolute;
  z-index:2;
  opacity: 0;
}
.photo-button{
  display: flex;
  position: absolute;
  top: 0;
  background: #4CAF50;
  width: 80%;
  border-radius: 50px;
  height: 50px;
  left: 10%;
  align-items: center;
  justify-content: center;
}
.photo-button img{
  display: block;
  width:34px;
}
.photo-button span{
  display: block;
  font-size:16px;
  color:#fff;
  padding:0 8px;
}
</style>

  

参考链接为:https://www.imweb.io/topic/59559c01ad7fa941029740aa

 

 

 

posted @ 2019-01-23 17:38  柠檬可乐  阅读(1096)  评论(0编辑  收藏  举报