H5图片压缩与上传实例

网友投稿 196 2023-05-22


H5图片压缩与上传实例

接到需求,问前端是否可以压缩图片?因为有的图片太大,传到服务器上再压缩太慢了。意识里没有这么玩过,早上老大丢来一个知乎链接,一看,原来前辈们已经用canvas实现了(为自己的见识羞愧3秒钟,再马上开干)!。

canvas压缩

使用了github上的一个现成库:https://github.com/stomita/ios-imagefile-megapixel,不得不膜拜下stomita这位大神。大体的思路是将图片抽样显示在canvas上,然后用通过canvas.toDataURL方法得到base64字符串来实现压缩。比如在input元素触发change事件之后,读取里面的文件进行操作:

var fileInput = document.getElementById('fileInput');

fileInput.onchange = function() {

var file = fileInput.files[0];

// 创建一个压缩对象,该构造函数接收file或者blob。

var mpImg = new MegaPixImage(file);

// render方法的maxWith,maxHeight,以及quality都决定了压缩图片的质量

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进行判断,不存在的话会报错:

MegaPixImage.prototype.render = function (target, options, callback) {

//....

target.tagName = target.tagName || "IMG"; //加上这一句

var tagName = target.tagName.toLowerCase();

if (tagName === 'img') {

target.src = renderImageToDataURL(this.srcImage, opt, doSquash);

} else if (tagName === 'canvas') {

renderImageToCanvas(this.srcImage, target, opt, doSquash);

}

if (typeof this.onrender === 'function') {

this.onrender(target);

}

if (callback) {

callback();

}

if (this.blob) {

this.blob = null;

URL.revokeObjectURL(this.srcImage.srccBLcWe);

}

};

另外这是一个耗时的操作,如果是多张图片进行压缩,不能直接调用,需要稍微变换一下,不然会导致前面的图片没有压缩完成就进入到了后面的图片。

fileSelected: function () {

var files = $("#fileImage")[0].files;

var count = files.length;

console.log("共有" + count + "个文件");

for (var i = 0; i < count; i++) {var item = files[i];

console.log("原图片大小", item.size);

if (item.size > 1024 * 1024 * 2) {

console.log("图片大于2M,开始进行压缩...");

(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);

}

},

上传处理

1.直接post base64字符串

uploadBase64str: function (base64Str) {

var formdata = new FormData();

formdata.append("base64str", base64Str);

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", function (e) {

para.uploadComplete(xhr.responseText);

});

xhr.addEventListener("error", function (e) {

para.uploadError(e);

});

xhr.open("post", para.base64strUrl, true);

xhr.send(formdata);

},

比如这里base64strUrl是/home/MUploadImgBase64Str,MVC控制器方法如下:

[HttpPost]

public ActionResult MUploadImgBase64Str(string base64str)

{

try

{

var imgData = base64str.Split(',')[1];

//过滤特殊字符即可

string dummyData = imgData.Trim().Replace("%", "").Replace(",", "").Replace(" ", "+");

if (dummyData.Length % 4 > 0)

{

dummyData = dummyData.PadRight(dummyData.Length + 4 - dummyData.Length % 4, '=');

}

byte[] byteArray = Convert.FromBase64String(dummyData);

using (System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray))

{

var img = System.Drawing.Image.FromStream(ms);

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:

var base641 = resImg.src;

一个是用canvas转换:

function getBase64Image(img) {

var canvas = document.createElement("canvas");

canvas.width = img.width;

canvas.height = img.height;

var ctx = canvas.getContext("2d");

ctx.drawImage(img, 0, 0, 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到后端

function dataURItoBlob(dataUrl) {

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到后台。

uploadFile: function (file) {

console.log("开始上传");

var formdata = new FormData();

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", function (e) {

para.uploadComplete(xhr.responseText);

});

xhr.addEventListener("error", function (e) {

para.uploadError(e);

});

xhr.open("post", para.url, true);

xhr.send(formdata);

},

全部的代码:(包含压缩和上传以及demo):

github:https://github.com/stoneniqiu/h5upload/

小结:基本上就是这样了,前端能够压缩图片的话,确实省了流量和时间。 插件是在上一篇的基础上进行改进的。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:C#创建Web应用程序代码实例
下一篇:Java连接sqlserver2008数据库代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~