這篇文章主要為大家詳細介紹了行動端利用H5實現壓縮圖片上傳功能,具有一定的參考價值,有興趣的小夥伴們可以參考一下
之前有同事跟我聊過關於行動端用canvas壓縮圖片後再上傳的功能,最近有了點空閒時間,所以就實踐了一下。 demo效果連結在文章底部貼出。
在做行動端圖片上傳的時候,用戶傳的都是手機本地圖片,而本地圖片一般都相對比較大,拿iphone6來說,平時拍很多圖片都是一兩M的,如果直接這樣上傳,那圖片就太大了,如果用戶用的是行動流量,完全把圖片上傳顯然不是一個好方法。
目前來說,HTML5的各種新API都在行動端的webkit上得到了較好的 實作。根據查看caniuse,本demo裡使用到的FileReader、Blob、Formdata物件都已在大部分行動裝置瀏覽器中實現了實作(safari6.0 、android 3.0 ),所以直接在前端壓縮圖片,已經成了很多移動端圖片上傳的必備功能了。
在行動端壓縮圖片並且上傳主要用到filereader、canvas 以及 formdata 這三個h5的api。邏輯並不難。整個過程就是:
(1)用戶使用input file上傳圖片的時候,用filereader讀取用戶上傳的圖片資料(base64格式)
(2)把圖片資料傳入img對象,然後將img繪製到canvas上,再調用canvas.toDataURL對圖片進行壓縮
# (3)獲取到壓縮後的base64格式圖片數據,轉成二進制塞進formdata,再透過XmlHttpRequest提交formdata 。
如此三步,就完成了圖片的壓縮和上傳。
說起來好像蠻簡單,其實還是有些坑的。接下來就直接用程式碼進行分析:
【一】取得圖片數據
# 先是取得圖片數據,也就是監聽input file的change事件,然後取得到上傳的檔案物件files,將類別數組的files轉成數組,然後進行forEach遍歷。
接著判斷檔案類型,如果不是圖片則不做處理。如果是圖片就實例化一個filereader,以base64格式讀取上傳的文件數據,判斷數據長度,如果大於200KB的圖片就調用compress方法進行壓縮,否則調用upload方法進行上傳。
filechooser.onchange = function () { if (!this.files.length) return; var files = Array.prototype.slice.call(this.files); if (files.length > 9) { alert("最多同时只可上传9张图片"); return; } files.forEach(function (file, i) { if (!/\/(?:jpegpnggif)/i.test(file.type)) return; var reader = new FileReader(); var li = document.createElement("li"); li.innerHTML = "<p class="progress"><span></span></p>"; $(".img-list").append($(li)); reader.onload = function () { var result = this.result; var img = new Image(); img.src = result; //如果图片大小小于200kb,则直接上传 if (result.length <= maxsize) { $(li).css("background-image", "url(" + result + ")"); img = null; upload(result, file.type, $(li)); return; } // 图片加载完毕之后进行压缩,然后上传 if (img.complete) { callback(); } else { img.onload = callback; } function callback() { var data = compress(img); $(li).css("background-image", "url(" + data + ")"); upload(data, file.type, $(li)); img = null; } }; reader.readAsDataURL(file); }) };
【2】壓縮圖片
上面做完圖片資料的取得後,就可以做compress壓縮圖片的方法了。而壓縮圖片並不是直接把圖片繪製到canvas再呼叫一下toDataURL就行的。
在IOS中,canvas繪製圖片是有兩個限制的:
# 首先是圖片的大小,如果圖片的大小超過兩百萬像素,圖片也是無法繪製到canvas上的,呼叫drawImage的時候不會報錯,但是你用toDataURL取得圖片資料的時候取得到的是空的圖片資料。
再者就是canvas的大小有限制,如果canvas的大小大於大概五百萬像素(即寬高乘積)的時候,不僅圖片畫不出來,其他什麼東西也都是畫不出來的。
應對第一種限制,處理辦法就是瓦片繪製了。瓦片繪製,也就是將圖片分割成多塊繪製到canvas上,我程式碼裡的做法是把圖片分割成100萬像素一塊的大小,再繪製到canvas上。
而應對第二種限制,我的處理辦法是對圖片的寬高進行適當壓縮,我代碼裡為了保險起見,設的上限是四百萬像素,如果圖片大於四百萬像素就壓縮到小於四百萬像素。四百萬畫素的圖片應該夠了,算起來寬高都有2000X2000了。
如此一來就解決了IOS上的兩種限制。
除了上面所述的限制,還有兩個坑,一個就是canvas的toDataURL是只能壓縮jpg的,當用戶上傳的圖片是png的話,就需要轉成jpg,也就是統一用canvas.toDataURL("image/jpeg", 0.1) , 類型統一設為jpeg,而壓縮比就自己控制了。
另一個就是如果是png轉jpg,繪製到canvas上的時候,canvas存在透明區域的話,當轉成jpg的時候透明區域會變成黑色,因為canvas的透明像素預設為rgba( 0,0,0,0),所以轉成jpg就變成rgba(0,0,0,1)了,也就是透明背景會變成黑色了。解決方法就 是繪製之前在canvas上舖一層白色的底色。
function compress(img) { var initSize = img.src.length; var width = img.width; var height = img.height; //如果图片大于四百万像素,计算压缩比并将大小压至400万以下 var ratio; if ((ratio = width * height / 4000000)>1) { ratio = Math.sqrt(ratio); width /= ratio; height /= ratio; }else { ratio = 1; } canvas.width = width; canvas.height = height; // 铺底色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); //如果图片像素大于100万则使用瓦片绘制 var count; if ((count = width * height / 1000000) > 1) { count = ~~(Math.sqrt(count)+1); //计算要分成多少块瓦片 // 计算每块瓦片的宽和高 var nw = ~~(width / count); var nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (var i = 0; i < count; i++) { for (var j = 0; j < count; j++) { tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, width, height); } //进行最小压缩 var ndata = canvas.toDataURL("image/jpeg", 0.1); console.log("压缩前:" + initSize); console.log("压缩后:" + ndata.length); console.log("压缩率:" + ~~(100 * (initSize - ndata.length) / initSize) + "%"); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; }
【三】圖片上傳
# 完成圖片壓縮後,就可以塞進formdata裡進行上傳了,先將base64資料轉成字串,再實例化一個ArrayBuffer,然後將字串以8位元整型的格式傳入ArrayBuffer,再透過BlobBuilder或Blob對象,將8位元整型的ArrayBuffer轉成二進位物件blob ,然後把blob物件append到formdata裡,再透過ajax傳送給後台即可。
XmlHttpRequest2中不僅可以發送大數據,還多出了例如取得發送進度的API,我程式碼裡也進行了簡單的實作。
// 图片上传,将base64的图片转成二进制对象,塞进formdata上传 function upload(basestr, type, $li) { var text = window.atob(basestr.split(",")[1]); var buffer = new ArrayBuffer(text.length); var ubuffer = new Uint8Array(buffer); var pecent = 0 , loop = null; for (var i = 0; i < text.length; i++) { ubuffer[i] = text.charCodeAt(i); } var Builder = window.WebKitBlobBuilder window.MozBlobBuilder; var blob; if (Builder) { var builder = new Builder(); builder.append(buffer); blob = builder.getBlob(type); } else { blob = new window.Blob([buffer], {type: type}); } var xhr = new XMLHttpRequest(); var formdata = new FormData(); formdata.append("imagefile", blob); xhr.open("post", "/cupload"); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { console.log("上传成功:" + xhr.responseText); clearInterval(loop); //当收到该消息时上传完毕 $li.find(".progress span").animate({"width": "100%"}, pecent < 95 ? 200 : 0, function () { $(this).html("上传成功"); }); $(".pic-list").append("<a href="" + xhr.responseText + " rel="external nofollow" ">" + xhr.responseText + "<img src="/static/imghwm/default1.png" data-src="" + xhr.responseText + " class="lazy" + xhr.responseText + "" / alt="行動端利用H5實現壓縮圖片上傳的功能" ></a>") } }; //数据发送进度,前50%展示该进度 xhr.upload.addEventListener("progress", function (e) { if (loop) return; pecent = ~~(100 * e.loaded / e.total) / 2; $li.find(".progress span").css("width", pecent + "%"); if (pecent == 50) { mockProgress(); } }, false); //数据后50%用模拟进度 function mockProgress() { if (loop) return; loop = setInterval(function () { pecent++; $li.find(".progress span").css("width", pecent + "%"); if (pecent == 99) { clearInterval(loop); } }, 100) } xhr.send(formdata); }
至此,整个上传的前端图片压缩就完成了,因为是用了formdata提交,所以后台接数据的时候就跟普通form表单提交数据一样处理即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
以上是行動端利用H5實現壓縮圖片上傳的功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文解釋瞭如何使用&lt; audio&gt;元素,包括用於格式選擇的最佳實踐(MP3,OGG Vorbis),文件優化和JavaScript控件用於播放。 它強調使用多個音頻f

本文討論了使用視口元標記來控制移動設備上的頁面縮放,重點是寬度和初始尺度之類的設置,以獲得最佳響應和性能。

本文使用JavaScript詳細介紹了創建Interactive HTML5遊戲。 它涵蓋了遊戲設計,HTML結構,CSS樣式,JavaScript邏輯(包括事件處理和動畫)以及音頻集成。 必需的JavaScript庫(Phaser,Pi

本文討論了使用GeOlocation API管理用戶位置隱私和權限,並強調要求權限,確保數據安全性並遵守隱私法律的最佳實踐。

本文解釋瞭如何創建和驗證HTML5表格。 它詳細介紹了&gt;元素,輸入類型(文本,電子郵件,編號等)和屬性(必需,模式,最小,最大)。 HTML5的優勢比舊方法形成

本文討論了使用HTML5頁面可見性API來檢測頁面可見性,提高用戶體驗並優化資源使用情況。關鍵方麵包括暫停媒體,減少CPU負載以及基於可見性變化管理分析。

本文介紹瞭如何使用HTML5拖放API來創建交互式用戶界面,詳細介紹了使元素可拖動的步驟,處理關鍵事件並通過自定義反饋來增強用戶體驗。它還討論了一個常見的陷阱

本文解釋了HTML5 Websockets API,用於實時雙向客戶服務器通信。 它詳細詳細介紹了客戶端(JavaScript)和服務器端(Python/Flask)的實現,以應對可伸縮性,狀態管理,一個挑戰


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。