您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)如何實(shí)現(xiàn)H5實(shí)現(xiàn)圖片壓縮與上傳,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
接到需求,問(wèn)前端是否可以壓縮圖片?因?yàn)橛械膱D片太大,傳到服務(wù)器上再壓縮太慢了。意識(shí)里沒(méi)有這么玩過(guò),早上老大丟來(lái)一個(gè)知乎鏈接,一看,原來(lái)前輩們已經(jīng)用canvas實(shí)現(xiàn)了(為自己的見(jiàn)識(shí)羞愧3秒鐘,再馬上開干)!。
canvas壓縮
使用了github上的一個(gè)現(xiàn)成庫(kù):https://github.com/stomita/ios-imagefile-megapixel,不得不膜拜下stomita這位大神。大體的思路是將圖片抽樣顯示在canvas上,然后用通過(guò)canvas.toDataURL方法得到base64字符串來(lái)實(shí)現(xiàn)壓縮。比如在input元素觸發(fā)change事件之后,讀取里面的文件進(jìn)行操作:
var fileInput = document.getElementById('fileInput'); fileInput.onchange = function() { var file = fileInput.files[0]; // 創(chuàng)建一個(gè)壓縮對(duì)象,該構(gòu)造函數(shù)接收f(shuō)ile或者blob。 var mpImg = new MegaPixImage(file); // render方法的maxWith,maxHeight,以及quality都決定了壓縮圖片的質(zhì)量 var resImg = document.getElementById('resultImage'); mpImg.render(resImg, { maxWidth: 300, maxHeight: 300, quality: 0.5 }); }; 壓縮完成會(huì)得到
類似這樣的圖片:
data:image/jpeg 這樣的格式已經(jīng)應(yīng)用的很多了,很多樣式里面的背景圖片直接就是這樣。
需要說(shuō)明的是有兩點(diǎn),這里的resImg是一個(gè)預(yù)覽圖片,是已經(jīng)存在于文檔中的,如果你不需要預(yù)覽,而只是創(chuàng)建一個(gè)img用來(lái)壓縮(document.createElement("img")),這會(huì)少一個(gè)tagName屬性。你可以修改源碼或者自己加上這個(gè)屬性。源碼中會(huì)根據(jù)tagName進(jìn)行判斷,不存在的話會(huì)報(bào)錯(cuò):
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.src); } };
另外這是一個(gè)耗時(shí)的操作,如果是多張圖片進(jìn)行壓縮,不能直接調(diào)用,需要稍微變換一下,不然會(huì)導(dǎo)致前面的圖片沒(méi)有壓縮完成就進(jìn)入到了后面的圖片。
fileSelected: function () { var files = $("#fileImage")[0].files; var count = files.length; console.log("共有" + count + "個(gè)文件"); for (var i = 0; i < count; i++) {var item = files[i]; console.log("原圖片大小", item.size); if (item.size > 1024 * 1024 * 2) { console.log("圖片大于2M,開始進(jìn)行壓縮..."); (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]; //過(guò)濾特殊字符即可 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,當(dāng)然,如果寬度、高度和質(zhì)量設(shè)置的太小,圖片就會(huì)很失真了。這個(gè)字符串怎么獲取呢?有兩個(gè)方法,一個(gè)是直接讀取src:
var base641 = resImg.src;
一個(gè)是用canvas轉(zhuǎn)換:
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);
同一張圖片,這兩者獲取到的字符串大小不一樣,但圖片質(zhì)量我是分辨不出什么差別。
比如一個(gè)2M的圖片,通過(guò)getBase64Image方法讀到的字符串大小才64k,而src直接讀取到的卻是270k,各自生成的圖片更小。一下分別是原圖(2.2M),base64(48k),src(202k)對(duì)應(yīng)的圖片。
getBase64Image通過(guò)canvas的toDataURL 獲取到更小的base64字符串。
2.也可以在前端轉(zhuǎn)換blob對(duì)象,再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到后臺(tái)。
uploadFile: function (file) { console.log("開始上傳"); var formdata = new FormData(); formdata.append(para.filebase, file);//這個(gè)名字要和mvc后臺(tái)配合 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); },
關(guān)于如何實(shí)現(xiàn)H5實(shí)現(xiàn)圖片壓縮與上傳就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。