zoukankan      html  css  js  c++  java
  • 移动端上传照片 预览+Draw on Canvas's Demo(解决 iOS 等设备照片旋转 90 度的 bug)

    背景:

    本人的一个移动端H5项目,需求如下:

      需求一:手机相册选取或拍摄照片后在页面上预览

      需求二:然后绘制在canvas画布上

    这里,我们先看一个demo(http://jsfiddle.net/q3011893/83qfqpk8/embedded/

      需求一drawTempPhoto方法

      需求二drawPhoto方法

    操作步骤:

    1、点击选择文件,拍摄一张照片,此时"预览:"文字下会显示你刚才拍摄的照片;

    2、再点击"draw on Canvas",该按钮下的画布会绘制你刚才拍摄的照片。

    正常的结果:

    --------------------------------------------------------------------------------------------------------

    正文:

    1、让input file支持拍照+相册选取
     
      1. <input accept="image/*" type="file" id="file" />
      2. //有一些特殊的安卓机还需要加上 capture="camera" 属性才能支持拍照

    2、需求一预览功能使用html5提供的新API:FileReader

    介绍:

    FileReader接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。

     

    API文档:

    https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader

     

    兼容性:

    主流浏览器都支持。除了IE有点问题,详情看下图:

     

     

     

     

     

     

     

     

     

     

     

     

        使用方法(使用drawTempPhoto方法实现需求一):

    1. //绘制照片
    2. function drawTempPhoto() {
    3.  
    4.     //检验是否为图像文件
    5.     var file = document.getElementById("file").files[0];
    6.     if (!/image/w+/.test(file.type)) {
    7.         alert("看清楚哦,这个需要图片!");
    8.         return false;
    9.     }
    10.     var reader = new FileReader();
    11.     //将文件以Data URL形式读入页面
    12.     reader.readAsDataURL(file);
    13.     reader.onload = function (e) {
    14.  
    15.         //预览效果
    16.         var img = $("#photo")[0];
    17.         //加载图片,此处的this.result为base64格式
    18.         img.src = this.result;
    19.  
    20.     }
    21.  
    22. }

      注:

      

      在本人的三星note5的手机中,需求一会出现照片预览逆时针旋转90度的bug(其实用下面介绍的的exif.js方法,可以知道iOS和三星所拍的照片Orientation值都是6,而前者做了预览的修正,后者则直接显示了出来,导致了旋转)。

     

       解决方案:

       判断是否为三星手机设备,然后把预览的图片顺时针旋转90度恢复正常(例如可以用canvas技术模拟预览效果)。

      于是修改的drawTempPhoto方法如下【line:21-27】:

    1. //绘制照片
    2.     function drawTempPhoto() {
    3.  
    4.         //检验是否为图像文件
    5.         var file = document.getElementById("file").files[0];
    6.         if (!/image/w+/.test(file.type)) {
    7.             alert("看清楚哦,这个需要图片!");
    8.             return false;
    9.         }
    10.         var reader = new FileReader();
    11.         //将文件以Data URL形式读入页面
    12.         reader.readAsDataURL(file);
    13.         reader.onload = function (e) {
    14.  
    15.             //预览效果
    16.             var img = $("#photo")[0];
    17.             //加载图片,此处的this.result为base64格式
    18.             img.src = this.result;
    19.             img.onload = function(){
    20.  
    21.                 //获取照片的拍摄方向
    22.                 var orient = getPhotoOrientation(img);
    23.                 alert("orient1:" + orient);
    24.                 //判断是否是三星手机
    25.             // if (isSamsung) {
    26.                       // 做旋转的适配……
    27.                 // }
    28.  
    29.             };
    30.  
    31.         }
    32.  
    33.     }
    3、需求二绘制到Canvas,使用exif.js解决iOS(包括三星note5)等一些手机照片旋转90度的bug

      在iOS上,表现如下:

      可见,在iOS上第一张图正常,而第二张图逆时针旋转了90度,而其他的安卓两步都是正常的显示

      那我们来看看exif.js是什么?

      介绍:

      Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。

     

      兼容性:

      EXIF 数据主要来自拍摄的照片,多用于移动端开发,PC 端也会用到,此插件兼容主流浏览器,IE10 以下不支持。

     

      下载地址:

          https://github.com/exif-js/exif-js

     

      这里我们知道了exif.js其实是获取一张拍摄照片的元信息的,进而获取它最初的拍照方向,这很可能跟iOS图片旋转的bug有关。

     

      而exif.js提供的一张照片的Orientation属性如下

      

      解决方案:

      1、我首先引入exif.js

    1.   <script src="./js/exif.js"></script>

     

      2、然后封装成getPhotoOrientation方法:

    1. //获取照片的元信息(拍摄方向)
    2. function getPhotoOrientation(img){
    3.     var orient;
    4.     EXIF.getData(img, function () {
    5.         orient = EXIF.getTag(this, 'Orientation');
    6.     });
    7.     return orient;
    8. }

      3、分别在操作步骤一选择图片和操作步骤二draw on Canvas,Alert照片的Orientation值,本人的测试机有限,请见谅,结果如下:

    手机型号

    Orientation值

    iphone 6S

    6

    小米4S

    undefined

    华为荣耀4A

    1

    PC

    undefined

      可以看到,小米4S和PC都是undefined,表示图片没有拍摄方向或者根本没记录,华为荣耀4A是1,表示的是正确的方向,以上都没问题。但iphone 6S为6!所以之所以出现了图片的旋转,是因为它本身的Orientation就不正常!!

     

      因此解决这个bug的思路是:获取到照片拍摄的方向,对ios照片进行角度旋转修正。

     

      修改后的demo(http://jsfiddle.net/q3011893/k3z5ev26/embedded/

     

      除了上面引入的exif.js和添加的getPhotoOrientation方法,我又修改了drawPhoto方法:

      ①旧drawPhoto方法:

    1. //绘制照片
    2. function drawPhoto(photo, x, y, w, h) {
    3.  
    4.     var canvas = document.getElementById("canvas");
    5.     if (canvas.getContext) {
    6.         var ctx = canvas.getContext("2d");
    7.  
    8.         //draw on Canvas
    9.         var img = new Image();
    10.         img.onload = function () {
    11.  
    12.             var canvas_w = Number(ctx.canvas.width);
    13.             var canvas_h = Number(ctx.canvas.height);
    14.  
    15.             // 执行Canvas的drawImage语句
    16.             ctx.drawImage(img, x, y, w, h);
    17.  
    18.         }
    19.         img.src = photo.src; // 设置图片源地址
    20.     }
    21. }

      ②新drawPhoto方法【line:4-6,19-30】:

    1. //绘制照片
    2. function drawPhoto(photo, x, y, w, h) {
    3.  
    4.     //获取照片的拍摄方向
    5.     var orient = getPhotoOrientation(photo);
    6.     alert("orient2:"+orient);
    7.  
    8.     var canvas = document.getElementById("canvas");
    9.     if (canvas.getContext) {
    10.         var ctx = canvas.getContext("2d");
    11.  
    12.         //draw on Canvas
    13.         var img = new Image();
    14.         img.onload = function () {
    15.  
    16.             var canvas_w = Number(ctx.canvas.width);
    17.             var canvas_h = Number(ctx.canvas.height);
    18.  
    19.             //判断图片拍摄方向是否旋转了90度
    20.             if (orient == 6) {
    21.                 ctx.save();//保存状态
    22.                 ctx.translate(canvas_w / 2, canvas_h / 2);//设置画布上的(0,0)位置,也就是旋转的中心点
    23.                 ctx.rotate(90 * Math.PI / 180);//把画布旋转90度
    24.                 // 执行Canvas的drawImage语句
    25.                 ctx.drawImage(img, Number(y) - canvas_h / 2, Number(x) - canvas_w / 2, h, w);//把图片绘制在画布translate之前的中心点,
    26.                 ctx.restore();//恢复状态
    27.             } else {
    28.                 // 执行Canvas的drawImage语句
    29.                 ctx.drawImage(img, x, y, w, h);
    30.             }
    31.  
    32.         }
    33.         img.src = photo.src; // 设置图片源地址
    34.     }
    35. }

      运行结果如下:

          

     

       完美~

  • 相关阅读:
    plsql和tsql常用函数比对
    全面对比T-SQL与PL/SQL
    SQL/T-SQL/PLSQL
    Oracle数据库中的数据出错的解决办法
    2008-03-18 22:58 oracle基础知识小结
    Oracle SQL性能优化
    Oracle存储过程基本语法
    jenkins权限配置不对导致jenkins无法登陆
    jenkins关闭和重启
    Jenkins的安装(最为简单的安装方法)
  • 原文地址:https://www.cnblogs.com/xjnotxj/p/5576073.html
Copyright © 2011-2022 走看看