• 移动端图片操作(二)——预览、旋转、合成


    在上一节中已经提到了预览,预览可以通过data: URL格式或URL对象。

    var file = upload.files[0];
    //URL对象
    var url = URL.createObjectURL(file);
    var img = new Image();
    img.style.width = '100%';
    img.src = url;
    img.onload = function(e) {
      window.URL.revokeObjectURL(this.src); //销毁
    }
    //data:URL格式
    var img = new Image();
    img.style.width = '100%';
    var reader = new FileReader();
    reader.onload = function() {
      img.src = this.result;
    };
    reader.readAsDataURL(file);

    一切都很顺利,但其实有很多的坑,需要慢慢讲来。先从前面做的一个小功能说起。

    这个小功能就是将两张图片合成起来,组成一张新的图片

    一、技术实现

    1)上传的控件就用“input[type=file]”实现

    Android的webview不支持此控件,怪不得按钮怎么按都按不动,后面只得用客户端提供的接口做上传

    期间发现UC浏览器会自动将上传控件包装成三个按钮的样子,只需设置为“opacity:0;”即可。

    2)使用“FileReader”,通过方法readAsDataURL获取data URL格式的图片内容,赋值给image。

    IOS在上传图片或拍照的时候,显示出来的宽高是反的,这个时候我们增加了一步旋转的操作,让用户自己来控制。

    在给image赋src值的同时,赋“crossOrigin”的值,用于后面的图片跨域

    3)将图片画在“canvas”上,旋转其实也就是转这个canvas。通过计算坐标和角度实现旋转

    4)将旋转后的“canvas”与剩下的两张文字图片,通过一个新的“canvas”合并到一起。

    在将两个“canvas”画在一起后,发现通过webview上传的图片,不能使用“toDataURL()”方法了,这是因为画布被污染,第一个画布中的图片是跨域的。

    5)最后将data URL格式的内容上传到服务器中保存。

    总共开发时间是3天,在这个过程中有过几次技术推翻重做或者逻辑重整,兼容性方面也还有很大问题,包括图片的宽高的自适应等,还很不完善。

    下图是最终效果,挑了张松狮的写真照:

    二、预览

    原先我在做的时候,第2步和第3布是合在一起的,也就是图片显示出来的时候,已经校准好位置。

    只是在实现的过程中碰到了很多麻烦,并且时间仓促,BUG修复起来比较费时,只得分两步。

    先说说原先的过程

    1)IOS图片上传或拍照,宽高相反

    我用的是Android手机,刚开始并没有发现这个问题,后面别人帮忙测试的时候,才发现了这个重大问题,接下来就是折腾这个事儿,想要自动校正方向。

    1. 通过exif.js获取图片元数据,通过获取“Orientation”属性判断方向【我的Android机中这个属性为undefined,IOS有值】,总共有8个值

     

    左边是说明,右边是展示。表格中带“*”的是指翻转过来了。

    接下来就是做计算,网上有很多计算方式,对于“>IOS7”的系统,计算逻辑可以参考下localResizeIMG插件195行

    顺便说下,这个插件使用到了gulp的开发方式,如果要调试就要配置相关代码,可以参考《前端自动化构建工具gulp记录

    插件中还大量使用了Promises/A+规范,关于这个规范可以参考《JavaScript中Promises/A+规范的实现

    exif.getData(typeof file === 'object' ? file : img, function() {
      orientation = exif.getTag(this, "Orientation");
      //计算逻辑....
    });

    2. “<=IOS7”系统的计算方式略有不同。IOS6中图片拍照上传会被压扁(当照片超过2M时),这是IOS6的BUG,较大的图片可能会发生。

    计算逻辑也可以参考localResizeIMG插件165行。要解决这个BUG需要引入megapix-image.js

    require(['megapix-image'], function(MegaPixImage) {
      var mpImg = new MegaPixImage(img);
      //计算逻辑
    });

     

    2)将画布“canvas”通过方法“toDataURL”,变成data URL格式

    1. 在手机QQ浏览器中,canvas对象使用toDataURL方法获取不到任何数据,需要引用jpeg-encoder.js解决。

    var cvs = document.createElement('canvas');
    var ctx = cvs.getContext("2d");
    ctx.drawImage(theImg, 0, 0);
    var theImgData = ctx.getImageData(0, 0, cvs.width, cvs.height);
    // Encode the image and get a URI back, toRaw is false by default
    var jpegURI = encoder.encode(theImgData, quality);

    在开发的时候方向自动旋转花了很多时间。碰到各种问题,例如“orientation”属性获取不到、自动旋转的角度不对。

    后面贪简单,就找了个canvasResize插件,虽然会自动校正,但是图片有点模糊,而且图片的宽高不容易控制。效果不尽如意,只好分两步做。

    最终的过程

    1)添加旋转页面

    先计算起始坐标点X与Y,简单点就是宽度和高度各除以2,再通过canvas的“translate”,再用“rotate”计算角度。在“drawImage”的时候X和Y点变成负数,移位过去。

    var xpos = canvas_width / 2;
    var ypos = canvas_height / 2;
    ctx.translate(xpos, ypos);
    ctx.rotate(angle * Math.PI / 180);
    ctx.drawImage(rotate_img, -width / 2, -height / 2, width, height);

    三、合成

    在上图中点击确认就会自动合成。

    1)图片宽高自适应

    画布的宽高只做了简单的比率,画布的宽度除以图片的宽度,我把头部的图片和底部的图片宽度都做的相同,下图所示:

     

    var multiple = width / header.width;//画布宽度除以图片宽度
    
    var header_height = header.height * multiple;//顶部图片
    var footer_height = footer.height * multiple;//底部图片
    var footer_y = canvas_height - footer_height;

    2)将顶部与底部图片、与上一个旋转后的canvas画一起在第二个画布上

    ctx.drawImage(rotate_canvas, 0, 0, width, height);
    ctx.drawImage(header, 0, 25, width, header_height);
    ctx.drawImage(footer, 0, footer_y, width, footer_height);

    这里碰到了一个画布污染的问题。上面的“rotate_canvas”,图片的获取有两种,一个是通过“file”控件上传的,另一个是在webview提供的接口上传的。

    两个唯一的不同是跨域,第二个接口返回的是另外一个域名中的图片。图片跨域了,那么rotate_canvas也算是跨域了。

    跨域的话,会影响“toDataURL()”方法。这个时候就需要img图片跨域。

    1. 图片设置crossOrigin属性,这是一个HTML5属性,兼容性不是很好,测试了几台Android机,有的行,有的不行。“crossOrigin”属性设置要在“src”之前,否则IOS不可使用

    rotate_img.crossOrigin = "Anonymous";

    2. 服务器需要设置,可以正确响应 Access-Control-Allow-Origin 头。

    调试的时候,如果服务器还没配置,可以用Fiddler模拟响应头。

    a. 先找到filter选项

     

    b. 设置请求头

     

    c. 设置响应头,注意与请求头中的内容要一模一样,少个“http”都不行

    参考资料:

    H5拍照应用开发经历的那些坑儿

    图片自动旋转的前端实现方案

    JPEG Rotation and EXIF Orientation

    利用exif.js解决ios手机上传竖拍照片旋转90度问题

    Html5 create thumbnail

  • 相关阅读:
    SQL Server, Timeout expired.all pooled connections were in use and max pool size was reached
    javascript 事件调用顺序
    Best Practices for Speeding Up Your Web Site
    C语言程序设计 使用VC6绿色版
    破解SQL Prompt 3.9的几步操作
    Master page Path (MasterPage 路径)
    几个小型数据库的比较
    CSS+DIV 完美实现垂直居中的方法
    由Response.Redirect引发的"Thread was being aborted. "异常的处理方法
    Adsutil.vbs 在脚本攻击中的妙用
  • 原文地址:https://www.cnblogs.com/strick/p/5183570.html
Copyright © 2020-2023  润新知