娜娜佳
娜娜佳
  • 发布:2016-07-15 16:43
  • 更新:2021-01-08 17:06
  • 阅读:25776

图像(头像)选择,截取,压缩,上传的分享

分类:HTML5+

思路:

  1. 通过拍照或者选择一张照片
  2. 将照片作为底,一个正方形容器作为边界。通过移动正方形容器获取所需图形的边界。
  3. 截取图片,并压缩到指定大小。
  4. 上传到服务器。

具体实现:

  1. 获取照片资源
    1.1 从相册选择

    function chooseImgFromAlbums() {  
    plus.gallery.pick(function(file) {  
    changeToLocalUrl(file);  
    }, function(err) {  
    console.log(JSON.stringify(err));  
    }, {  
    filter: 'image',  
    multiple: false  
    });  
    }

    1.2 拍照

    function chooseImgFromPictures() {  
    var cmr = plus.camera.getCamera();  
    
    cmr.captureImage(function(file) {  
    changeToLocalUrl(file);  
    }, function(err) {  
    console.log(JSON.stringify(err));  
    }, {  
    index: '2',  
    });  
    }

    1.3 相册选择和拍照选择返回的路径都是绝对路径,为了让其显示在img里面,我们需要转换为本地路径URL地址。此处打开一张新页面来对图片进行处理

    function changeToLocalUrl(path) {  
    plus.io.resolveLocalFileSystemURL(path, function(entry) {  
    openWindow('uploadImg.html?src='   entry.toLocalURL());  
    });  
    }
  2. 以一个正方形容器截取图片。
    此处,自己写了一些简单的js来做图像截取,这些js修改起来也很方便。
    首先,看一下整个页面:

功能很简单:点击放大,缩小可以放大缩小正方形的区域。用手指移动正方形,来改变正方形所包含的内容。

实现的思路:通过监听正方形的touchstart和touchmove事件,改变它的top,left值。实现移动。

具体代码如下:

var Clip = {  
  size: 12, //这个表示正方形目前的边长,乘上一个基数就是当前的像素值  
  range: {}, //用来控制正方形left和top的极限值,以免移出边界  
  topCss: 0,  //表示当前的top值  
  leftCss: 0,  //表示当前的left值  
  touchX: 0,  //当前的手指所处的X坐标  
  touchY: 0, //当前手指的Y坐标  
  timer: null,  //用来做touchmove的函数节流,以免连续触发touchmove事件导致的效率问题  
  changeBase: function(index) {  //这个函数用来改变正方形的边长,一般还需要设置最大边长和最小边长  
    this.size  = index;  

    $('#clip').css({  
      height: this.size   'rem',  
      width: this.size   'rem',  
      lineHeight: this.size   'rem'  
    });  

    this.changeRange();  //边长改变,将引起当前top, left和range的变化,统一调changeRange的方法来修改  
  },  
  changeRange: function() {  //这个方法用来计算初始top, left以及边界值。其算法收到当前页面布局影响,需要自行修改  
    this.topCss =($('body').height() - baseSize * extraHeight - baseSize * this.size) / 2   baseSize * headerHeight;  
    this.leftCss = ($('body').width() - baseSize * this.size) / 2;  
    this.changeClipStyle(this.leftCss, this.topCss);  

    //极限值,需控制不超出图片区域  
    var minTop = ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2   baseSize * headerHeight;  
    var maxTop = $('body').height() - ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 -   
              baseSize * footerHeght - baseSize * this.size;  

    var minLeft = 0;  
    var maxLeft = $('body').width() - baseSize * this.size;  
    this.range = {  
      minTop: minTop,  
      maxTop: maxTop,  
      minLeft: minLeft,  
      maxLeft: maxLeft  
    };  

  },  
  initEvent: function() {  //事件初始化  
    mui('body').on('tap', '#enlarge', function(e) {  
      Clip.changeBase(1);  
    });  
    mui('body').on('tap', '#reduce', function(e) {  
      Clip.changeBase(-1);  
    })  

    var clip = document.getElementById('clip');  

    //开始接触的时候,记录当前的手指位置  
    clip.addEventListener('touchstart', function(event) {  
      Clip.touchX = event.touches ? event.touches[0].clientX : event.screenX;  
      Clip.touchY = event.touches ? event.touches[0].clientY : event.screenY;  
      event.preventDefault();  
    });  

    //移动后,记录新的位置,设置新的top和left值  
    clip.addEventListener('touchmove', function(event) {  
      //设置20ms的事件  
      if(Clip.timer != null) {  //函数节流  
        return;  
      }  
      Clip.timer = setTimeout(function() {  
        var x = event.touches ? event.touches[0].clientX : event.screenX;  
        var y = event.touches ? event.touches[0].clientY : event.screenY;  

        var disX = x - Clip.touchX;  
        var disY = y - Clip.touchY;  

        var nowLeft = Clip.leftCss   disX;  
        var nowTop = Clip.topCss   disY;  

        if(nowLeft < Clip.range.minLeft) {  
          nowLeft = Clip.range.minLeft;  
        }  
        if(nowLeft > Clip.range.maxLeft) {  
          nowLeft = Clip.range.maxLeft;  
        }  
        if(nowTop < Clip.range.minTop) {  
          nowTop = Clip.range.minTop;  
        }  
        if(nowTop > Clip.range.maxTop) {  
          nowTop = Clip.range.maxTop;  
        }  

        Clip.changeClipStyle(nowLeft, nowTop);  

        Clip.touchX = x;  
        Clip.touchY = y;  
        Clip.timer = null;  
      }, 20);  

    });  

  },  
  //设置新的样式,并改变当前的top和left值  
  changeClipStyle: function(leftCss, topCss) {  
    $('#clip').css({  
      left: leftCss   'px',  
      top: topCss   'px'  
    });  
    Clip.leftCss = leftCss;  
    Clip.topCss = topCss;  
  }  
}
  1. 移动到正方形到合适的区域后,点击完成,就将完成截取图片和压缩图片的功能。
    主要思路是: 调用plus.zip.compressImage函数来完成截取和压缩

3.1. 首先,需要计算出宽高的百分比和离图片左上角的top和left的百分比。同样根据布局不同,计算方式不同。

//获取width和height的百分比  
var widthPix = (Clip.size * baseSize / $('#img').width()).toFixed(2) * 100;  
var heightPix = (Clip.size * baseSize / $('#img').height()).toFixed(2) * 100;  
//获取左上角位置百分比  
var topPix = ((Clip.topCss - Clip.range.minTop) / $('#img').height()).toFixed(2) * 100;  
var leftPix = (Clip.leftCss / $('#img').width()).toFixed(2) * 100;

3.2 截取

//对图片进行裁剪  
plus.zip.compressImage(  
  {  
    src: search.src, //src在这里是第一步Url里的src。也就是本地路径  
    dst: '_doc/a.jpg',  
    overwrite: true,  
    clip: {  
      top: topPix   '%',  
      left: leftPix   '%',  
      width: widthPix   '%',  
      height: heightPix   '%'  
    }  
  },  
  function(e) {  
    resizeImage(e.target); //压缩图片  
  }  
);

3.3 截取图片之后,我们还需要进行压缩。

//再对图片进行压缩为270*270,再上传到服务器  
function resizeImage(src) {  
  plus.zip.compressImage(  
    {  
      src: src,  
      dst: '_doc/a.jpg',  
      overwrite: true,  
      width: '270px', //这里指定了宽度,同样可以修改  
      format: 'jpg',  
      quality: 100  //图片质量不再修改,以免失真  
    },  
    function(e) {  
      plus.nativeUI.closeWaiting();  
      uploadImg(e.target);  //上传图片, e.target存的是本地路径!  
    },  
    function(err) {  
      plus.nativeUI.alert('未知错误!',function() {  
        mui.back();  
      });  
    }  
  );  
}
  1. 上传图片到服务器。上传图片用的是plus.uploader,数据格式符合Multipart/form-data规范,也就是平时input type='file'那样一样

    function uploadImg(src) {  
    var task = plus.uploader.createUpload(ajaxUrl, {  
    method: 'post',   
    blocksize:204800,  
    timeout: 10  
    });  
    
    task.addFile(src, {key: 'headImg'});  
    
    task.addData('type', 'uploadImg');  
    task.addData('userId', );  
    task.addEventListener('statechanged', stateChanged, false);  
    task.start();  
    
    function stateChanged(upload, status) {  
    if ( upload.state == 4 && status == 200 ) {  
      plus.uploader.clear();  //清除上传  
      console.log(upload.responseText);  //服务器返回存在这里  
    }  
    }  
    }

    好了,就这么多,代码比较简单,如果有其他能用的,欢迎修改。源码就不上传了,因为是公司项目的一个子功能,主要代码实现都在这里了。直接用了jQuery和mui。当然用原生写也OK。

34 关注 分享
赵梦欢 Trust ccfto ccclubs 紫苏 郑家好人 水灵退散 草泥马二号 3***@qq.com c***@163.com 奔跑的蘑菇 WinXP ScottVan 4***@qq.com Thyme释念帅 MooGu 前端菜鸟哟 JBoss 爱的哲学 Ste7en QUES f***@163.com 菜鸟PHP c***@live.com 2***@qq.com 5***@qq.com 1***@qq.com 漠 MR不靠谱 s***@163.com 段长发 PHP全栈工程师 飞酒 aaa6a6a66a

要回复文章请先登录注册

希汝君兮

希汝君兮

task.addFile(src, {key: 'headImg'});这个里面的headImg是服务器端接收的图片文件的参数吗?
2017-04-26 18:28
1***@qq.com

1***@qq.com

mark
2017-03-23 00:31
2***@qq.com

2***@qq.com

从相册里获取的路径是绝对路径啊......你上面说从相册和拍照获取的都是相对路径,是不是有问题??
2017-03-21 13:51
2***@qq.com

2***@qq.com

附楼上。我也是看了好久,自己去搞了一下,没弄成功。囧。要是有源码就好。求共享。251028591@qq.com
2016-12-29 18:13
前端菜鸟哟

前端菜鸟哟

求demo,我刚学前端不久,你的代码不少地方看不懂,可以把源码发给我一点点研究吗?120439073@qq.com
2016-12-21 21:40
娜娜佳

娜娜佳 (作者)

回复 easeliyf :
就是一个数值,指明宽高的长度只能以这个为倍数进行放大和缩小
2016-12-13 11:47
MooGu

MooGu

mark~
2016-12-09 11:59
yungehaha

yungehaha

mark
2016-11-01 11:02
easeliyf

easeliyf

Clip所在页面的代码,能完整的分享出来吗
2016-10-31 22:42
easeliyf

easeliyf

baseSize是什么样值呢
2016-10-31 19:25