在上一节中已经提到了预览,预览能够经过data: URL格式或URL对象。javascript
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);
一切都很顺利,但其实有不少的坑,须要慢慢讲来。先从前面作的一个小功能提及。html
这个小功能就是将两张图片合成起来,组成一张新的图片。前端
1)上传的控件就用“input[type=file]”实现html5
Android的webview不支持此控件,怪不得按钮怎么按都按不动,后面只得用客户端提供的接口作上传java
期间发现UC浏览器会自动将上传控件包装成三个按钮的样子,只需设置为“opacity:0;”便可。ios
2)使用“FileReader”,经过方法readAsDataURL获取data URL格式的图片内容,赋值给image。git
IOS在上传图片或拍照的时候,显示出来的宽高是反的,这个时候咱们增长了一步旋转的操做,让用户本身来控制。github
在给image赋src值的同时,赋“crossOrigin”的值,用于后面的图片跨域web
3)将图片画在“canvas”上,旋转其实也就是转这个canvas。经过计算坐标和角度实现旋转gulp
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”都不行
参考资料: