这段时间在工作中碰到一个需要在h5裁剪图像,然后直传阿里云的需求。图中遇到了一些小问题,分享出来大家都看看。

h5裁剪图像:cropper.js是一个神器啊关于用法,网上可以收罗出大量的帖子,这里我就不多说了,大致原理就是利用canvas裁剪图像然后生成base64的图像(canvas.toDataURL('image/jpeg'))。

转换Blob对象:接下来就是重点了,上传图片我们比较传统的做法就是将 canvas.toDataURL('image/jpeg')  传到后台,然后后台再生成图片传到阿里云。

这样就显得比较繁琐了,怎么将 canvas.toDataURL('image/jpeg')直接传到阿里云?这就懵逼了。这里不得不提到js的另一个东西,Blob对象。

file对象大家都不陌生了,那这个blob又是个什么鬼呢?而实际上 file 对象只是 blob 对象的一个更具体的版本,blob 存储着大量的二进制数据,并且 blob 的 size 和 type 属性,都会被 file 对象所继承。

所以, 在大多数情况下,blob 对象和 file 对象可以用在同一个地方,例如,可以使用 FileReader 借口从 blob 读取数据,也可以使用 URL.createObjectURL() 从 blob 创建一个新的 URL 对象。

这里我先用了canvas一个最简单的办法,创建blob。canvas.toBlob(callback,type,quality);我们可以直接把上传图片的方法写到回调里面,type:类型(图片:‘image/jpeg’),quality:图片质量(0-1).

当然这么高级的方法肯定会涉及到兼容性问题。那我们就回到blob对象的问题上来吧。在chrome早先版本和目前的android中,至少是andrid5.1之前的浏览器,包括微信浏览器等,都不支持blob的构造方法,需要使用BlobBuilder。

var file=new Blob( [array.buffer], {type : "image/jpeg"});//会存在兼容性问题。这个blob的构造方法,在ios手机浏览器是支持的,但是在android手机浏览器不行。

桌面版的chrome浏览器解决了这个blob bug, 但是android手机还是有这个问题,会返回一个type error,因为android浏览器不支持这个构造方法。你必须使用老版本的BlobBuilder API.

解决办法:

 //首先要将dataURL转换为Uint8Array对象:

               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 u8arr ;
}
// 接下来的事情就好办多了,来一发兼容性blob写法:
try{
var jpeg = new Blob( [array], {type : "image/jpeg"});
}
catch(e){
// TypeError old chrome and FF
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
if(e.name == 'TypeError' && window.BlobBuilder){
var bb = new BlobBuilder();
bb.append([array.buffer]);
var jpeg = bb.getBlob("image/jpeg");
}
else if(e.name == "InvalidStateError"){
// InvalidStateError (tested on FF13 WinXP)
var jpeg = new Blob( [array.buffer], {type : "image/jpeg"});
}
else{
// We're screwed, blob constructor unsupported entirely
}
}

  

上传到阿里云:
我查了一下阿里云的web直传的Js示例代码,感觉写的有点复杂,还是用ajax来解决这个问题吧,还是先上代码再来大致讲一下这个问题吧。
  Utils.ajax({
url: url1,//url1是先向后台请求上传阿里云的一些参数接口
success: function (res) {
if (res.errorCode == 0) {
var ossData=new FormData();
ossData.append("OSSAccessKeyId",res.data.accessId);//Bucket 拥有者的Access Key Id。
ossData.append("policy",res.data.policy);//policy规定了请求的表单域的合法性
ossData.append("Signature",res.data.signature);//根据Access Key Secret和policy计算的签名信息,OSS验证该签名信息从而验证该Post请求的合法性
//---以上都是阿里的认证策略
ossData.append("key",res.data.dir+'/'+res.data.filename+'.jpg');//文件名字,可设置路径
ossData.append("success_action_status",'200');// 让服务端返回200,不然,默认会返回204
ossData.append('file', jpeg);//需要上传的文件 file 这个
//接下来就是上传阿里云了的代码了
//ossData.append("callback",callbackbody);//回调,非必选,可以在policy中自定义
$.ajax({
url : res.data.host, //上传阿里地址
data : ossData,
processData: false,//默认true,设置为 false,不需要进行序列化处理
cache: false,//设置为false将不会从浏览器缓存中加载请求信息
async: false,//发送同步请求
contentType: false,//避免服务器不能正常解析文件---------具体的可以查下这些参数的含义
//dataType: 'JSON',//不涉及跨域 写json即可
type : 'post',
success : function(callbackHost, request) {}, //callbackHost:success,request中就是 回调的一些信息,包括状态码什么的
error : function() {
alert("图片上传出错!")
}
});
}
}
});

  

其实Utils.ajax和$.ajax都是一样的,为了区分我这样写的,Utils.ajax的请求是为了得到后台的验证。上传阿里云的一些证书啊,验证码什么的。$.ajax就是上传到阿里云的请求。值得注意点是:

ossData.append('file', jpeg);//需要上传的文件 file 这个jpeg就是我们前面创建的blob。一般上传到阿里云成功后如果不返回任何东西,就不要写入dataType了。

过程大概就是这样,参考了几个人的文章推荐给大家:https://www.cnblogs.com/flicat/p/5337054.html       TypeArray、ArrayBuffer、Blob、File、DataURL、canvas的相互转换

http://blog.csdn.net/u012811805/article/details/53885008  移动端UC浏览器不支持Blob的解决方案

https://www.cnblogs.com/mottled/p/6979536.html              阿里OSS ajax方式 web直传

            
05-16 05:20