头像上传二三事
之前注册功能还留了一个小尾巴:完善图像上传功能。之前只是简单的input上传,没有图片做任何处理。
以下说的就是如何将图片进行裁剪得到需要的尺寸并上传。(参考文献:http://www.open-open.com/lib/view/open1464825507226.html)
并将这些功能进行了简单的封装 (https://github.com/zhangdongming1989/upload_helper)
1.图片DataUri
看到这个需求不由得想到了之前看到的dataUri。dataUri实际上就是一个规定格式字符串。这个字符串实际就是是用base64编码后的图片数据。
比如这就是一个datauri图片
data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge 8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1h LnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g 77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7
把这一段粘贴到浏览器地址栏就会出现一张小图片。
这样做的好处是可以直接把datauri加到css或者html中,而不用再单独传一个图片——减少http请求。但是也有问题,base64要比二进制编码大1/3。在处理图片的过程中会多次涉及datauri,但是最终没有用它做传输格式,因为我们的后台存的都是单独的图片文件。
2.实现流程
uploadHelper=function(event,imgSize,returnType,callback)
这个是暴露的程序入口,需要放到文件input的onchange监听事件回调中。第一个event就是这个change事件,之后的参数是图片尺寸,输出类型,完成回调。
下面是一个例子,其中dataUri是一个img标签
var oFile=document.querySelector('#file-input'); var oDataUri=document.querySelector('dataUri'); oFile.onchange=function (event) { uploadHelper(event,{width:100,height:100},'dataUri',function (dataURI) { document.querySelector('#dataUri').src=dataURI; }); };
下面按照数据流来说明处理过程,这一系列过程中存在大量异步回调,所以数据流和程序编写顺序有些区别。
用event.target.file[0]拿到文件之后调用
function compressImage(file,size,callback)
这个方法是resize图片的主程序,然而这个方法没什么实际内容。其中会调用方法
fileToDataUrl(file,function (dataUrl)
这个方法的作用是将file转换成dataUri,当然这一步并不是必需的。
转换成datauri之后就到了压缩的核心方法
function compressDataUrl(dataURL,size,callback)
这个方法的思路是创建一个图片实例,将之前得到的datauri赋给它的img.src,然后使用canvas的图片重绘方法
ctx.drawImage(img,cutL,cutT,cutW,cutH,0,0,canvas.width,canvas.height);
参考文献:http://www.w3school.com.cn/tags/canvas_drawimage.asp
关于drawImage,首先这个方法是不是在canvas上,而是在canvas的上下文(context)上的一个方法。
其次,这个方法的参数比较多,因为这个方法需要让你指定用哪个图片作为源文件(img),之后四个cut开头的参数是让用户指定原图上绘制的起始坐标(cutL,cutT),然后
指定取原图多长多宽进行绘制(cutW,cutH)。之后是在canvas画布的哪个坐标开始绘制(0,0)最后是指定画布上新图像的宽高。其中除了0,0 以及我们指定的新图片大小以外都 需要进行计算。计算的思路是:既然指定了新图片的长宽,那么要想让新图片不发生长 或者宽的拉伸/压缩,需要保证原图宽高比和新图一致,如果不一致就裁剪掉。裁剪的时候默 认是左右对称裁剪,取得中间部分。
绘制结束之后将canvas转成datauri格式。值得一提的是,对于某一格式,图片大小基本是和尺寸相关的,100*100的图片只有5k左右大小
如果你需要将文件作为表单的一项上传,也许你还需要转成blob文件。实际上,对于有input=file表单(请求格式:multipart/form-data),
其中的文件(非字符串)上传都是用的blob格式。转化可以使用方法
function dataUriToBlob(dataUri)
这个方法做的事情就是把dataUri的字符串分隔解析,因为datauri除了数据还有文件格式。
最后创建blob文件。
3.后台接收
在这之后有一个问题困扰了我许久:blob文件后台怎么转成原来的格式(比如jpg)?
在我面对收到的blob文件一脸懵逼的许久之后,请教了老张,老张很自然的打开了blob文件所在的文件夹,然后我看到了图片预览。。。(至少ubuntu下是可以看的)
这时候我才知道,实际上是不用转格式的,我差的只是一个后缀。(比如.jpg)
然后稍微改了下multer的设置就可以了。