接到需求,问前端是否可以压缩图片?因为有的图片太大,传到服务器上再压缩太慢了。意识里没有这么玩过,早上老大丢来一个知乎链接,一看,原来前辈们已经用canvas实现了(为自己的见识羞愧3秒钟,再马上开干)!。
canvas压缩
使用了github上的一个现成库:,不得不膜拜下stomita这位大神。大体的思路是将图片抽样显示在canvas上,然后用通过canvas.toDataURL方法得到base64字符串来实现压缩。比如在input元素触发change事件之后,读取里面的文件进行操作:
var resImg = document.getElementById('resultImage');
mpImg.render(resImg,{ maxWidth: 300,maxHeight: 300,quality: 0.5 });
};
压缩完成会得到
类似这样的图片:
data:image/jpeg 这样的格式已经应用的很多了,很多样式里面的背景图片直接就是这样。
需要说明的是有两点,这里的resImg是一个预览图片,是已经存在于文档中的,如果你不需要预览,而只是创建一个img用来压缩(document.createElement("img")),这会少一个tagName属性。你可以修改源码或者自己加上这个属性。源码中会根据tagName进行判断,不存在的话会报错:
另外这是一个耗时的操作,如果是多张图片进行压缩,不能直接调用,需要稍微变换一下,不然会导致前面的图片没有压缩完成就进入到了后面的图片。
(function(img) {
var mpImg = new MegaPixImage(img);
var resImg = document.createElement("img");
resImg.file = img;
mpImg.render(resImg,{ maxWidth: 500,maxHeight: 500,quality: 1 },function() {
//do some thing
});
})(item);
}
core.previewImage(item);
}
},</pre>
上传处理
1.直接post base64字符串
xhr.open("post",para.base64strUrl,true);
xhr.send(formdata);
},</pre>
比如这里base64strUrl是/home/MUploadImgBase64Str,MVC控制器方法如下:
var path = "~/Content/UploadFiles/mobile/";
var uploadpath = Server.MapPath(path);
if (!Directory.Exists(uploadpath))
{
Directory.CreateDirectory(uploadpath);
}
var saveName = uploadpath + “stoneniqiu” + ".jpg";
img.Save(saveName);
return Json(saveName);
}
}
catch (Exception e)
{
return Json(e.Message);
}
}
几M的图片能压缩到几十k或者几百k,当然,如果宽度、高度和质量设置的太小,图片就会很失真了。这个字符串怎么获取呢?有两个方法,一个是直接读取src:
一个是用canvas转换: } 同一张图片,这两者获取到的字符串大小不一样,但图片质量我是分辨不出什么差别。var ctx = canvas.getContext("2d");
ctx.drawImage(img,img.width,img.height);
var dataURL = canvas.toDataURL("image/jpeg");
return dataURL;
// return dataURL.replace("data:image/png;base64,"");
var base64 = getBase64Image(resImg);
比如一个2M的图片,通过getBase64Image方法读到的字符串大小才64k,而src直接读取到的却是270k,各自生成的图片更小。一下分别是原图(2.2M),base64(48k),src(202k)对应的图片。
getBase64Image通过canvas的toDataURL 获取到更小的base64字符串。
2.也可以在前端转换blob对象,再post到后端
var byteString = atob(dataUrl.split(',')[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab],{ type: 'image/jpeg' });
}
3.不压缩的就直接装到formdata中,send到后台。
formdata.append(para.filebase,file);//这个名字要和mvc后台配合
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress",function (e) {
var percentComplete = Math.round(e.loaded * 100 / e.total);
para.onProgress(percentComplete.toString() + '%');
});
xhr.addEventListener("load",para.url,true);
xhr.send(formdata);
},</pre>
全部的代码:(包含压缩和上传以及demo):