前言    图片裁剪上传,不仅是一个很贴合用户体验的功能,还能够统一特定图片尺寸,优化网站排版,一箭双雕。
    需求就是那么简单,在浏览器里裁剪图片并上传到服务器。
我第一个想到的方法就是,将图片和裁剪参数(x,y,scale,rotate)一并上传给服务器,服务器来做图片处理,so easy。
      但是,这并不符合潮流发展的方向:  能在前端做的处理,就放前端做吧。  
     与潮流妥协的结果就是,前端越来越复杂。
        一开始我并不认为浏览器能够读取并生成图片。想想看啊,要做点击复制的这样简单的功能,都需要借助 flash 的浏览器,权限哪有那么大。
    参阅各类网站,只要把图片放在本地处理的,基本上都借用了flash。随便抄一个吧,没有api,就算能修改图片,上传路径都不知道怎么改。更关键的是,我对flash一窍不通。
    好在我们的网站已经完全抛弃了ie9以下的浏览器,只兼容现代html5浏览器。(连opera和微软都开始走webkit内核的路线了,潮流就是跟着chrome走)只能寄希望与html5,于是钻研了一番,发现如下流程可行。
    st=>start: 原图片 file 对象e=>end: 上传裁剪后的blob对象op=>operation: 初始化cropper 图片base64预览op1=>operation: 根据cropper裁剪参数绘制canvas(base64)op2=>operation: base64转blob对象st->op->op1->op2->e
以下将对每个环节详解。
    获取原图片 file 对象    每个图片文件处理的开始,都是由onchange事件开始
    确定并上传
初始化cropper             在这里介绍一个非常好用的库 cropper.js
      https://github.com/fengyuanchen/cropper 
     生成遮罩、获取裁剪参数、输出canvas ... 而且绝对轻量级,压缩后的css和js代码只有30kb。他是基于jquery的,引入jquery可能还要再大点。不过现在哪个网站没有在用jquery呢?
     兼容ie9+,移动端体验良好,能够响应触摸缩放,拖动。以下是安卓4.4 原生浏览器中的预览图
function handler(event){    ...    var url = window.url || window.webkiturl , originphotourl;    originphotourl = url.createobjecturl(originphoto);   //base64    $('#preview').cropper({        aspectratio: 1 / 1,                 // 固定裁剪比例1:1,裁剪后的图片为正方形    }).cropper('replace', originphotourl);  // 动态设置图片预览}
绘制canvas              cropper.js 提供了生成canvas的方法 getcroppedcanvas ,可以指定生成画布的大小。 
      或者根据 getdata 获取裁剪信息(包括旋转和缩放)用 ctx.drawimage(image, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) 进行手动绘制。后者自由性高一点,但是既然有现成的方法,那么就直接用好了。
function cropandupload(){    // 此处注意,生成的canvas长宽比应与之前规定的裁剪比例一致    // 否则生成的图片会有失真    var size = {        width:100,        height:100    }    var croppedcanvas = $('#preview').cropper(getcroppedcanvas,size);  // 生成 canvas 对象    var croppedcanvasurl = croppedcanvas.todataurl(originfiletype); // base64    ...}
应当注意的是 width 和 height 的值并不推荐设置成固定值。裁剪框的大小可能是会超过100 100(比如500 500)的,而实际生成的图片却是100 100,这样的后果就是直接将一个500 500的高清图片,压缩成了100 100的失真图片。同样的,裁剪框小于100 100,生成的图片就会模糊。 
    base64 转blob对象     字符串转为二进制?(前端本来是个做页面的,现在也开始操作文件了。自从有了html5,就可以把浏览器当作一个操作系统了)官方并没有出 dataurltoblob 的方法,所以只能自己写一个,转化也挺简单:拆解文件类型,将字符数据转成16进制数据存数组,并用数据初始化一个blob对象。 
    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});}function cropandupload(){    ...    var croppedblob = dataurltoblob(croppedcanvasurl);    croppedblob.name = originfilename; // blob对象没有name    // upload(croppedblob);}
现在就可以像处理fileobject一样处理 这个blob对象了。
     其实在最新的html5标准中是支持 htmlcanvaselement.toblob(callback, mimetype, quality) 的 
    croppedcanvas.toblob(function(croppedblob){    // upload(croppedblob);},originfiletype)
绕了一个弯,不过还是学到了东西。
原文作者来自 maxleap 团队_ux成员:john王
       原文链接: https://blog.maxleap.cn/archives/705
   
 
   