canvas壓縮圖片
A. 前端把圖片壓縮轉換成base64編碼把值賜予input='hidden' 之後提交給後台. HTML5,PHP,Javascript,canvas
缺點你無法直接驗證傳來的base64數據的完整性,比如大小,文件頭之類的,還需要自己來實現。
B. js壓縮圖片 到固定像素以內,500k為例
本文旨在探究js壓縮圖片的兩種方式: 改變圖片長寬 , 改變圖片質量 ,和結合了以上兩者的 最終方案 。
首先,閱讀本文需要知道canvas的兩個方法
這兩個方法具體的說明可以在MDN上查看,關於圖片壓縮,也有很多現成的博客可以直接用。但是那些博客都有個問題,並沒有關心之後圖片的壓縮質量。
我試著用一個現成的例子去跑了一下,一個1.7M的圖片壓縮到了23k,堪稱像素級毀滅性破壞。
假如一張大圖可能包含著很多文字等關鍵信息,必須上傳之後使用方能清晰辨認。所以要壓縮之後質量盡可能接近500k的。500k像素以內,就是若一張圖寬度為1024,則高度不能超過500。因為圖片有其他的信息,也是要佔大小的。即不得大於 1024*500 。
所以,根據需求,上傳圖片不能超過500k的情況下盡可能保留圖片的清晰度。當然如果可以的情況下用上面提到的 canvas.toDataURL 設置壓縮程度為0.9,0.8試試看,圖片質量可以接受,大小會有大幅度的縮小。
如果不壓縮,靠調整圖片長寬去控制上傳大小呢?
原理很簡單,就是靠不斷地縮小限定的最大寬高,直到最終長寬的積小於規定的大小。
這種方法有可能最後得出的圖片的大小會略大於規定大小,原因上文也提到過了,如果想使用這種方法,可自行再調整一下。
上面的方法有個問題,就是改變了圖片的原始長寬。如果一個圖的長寬足夠大,壓縮圖片質量,糊一點但是內容看得清也是ok的嘛。所以,跟上面同理,我們可以不斷調整圖片的質量設定直到大小合適,那麼,如何在圖片上傳之前知道圖片的大小呢?
首先,需要知道的一點是,壓縮之後拿到的base64字元串會轉成blob對象,然後傳給服務端。
可以查閱文檔,blob對象有個屬性是size
這個size就是上傳之後實際的文件大小。
參照上面的思路,可以每次改變 canvas.toDataURL('image/' + fileType, level); level的值,去調整壓縮圖片質量,然後用blob對象的size去驗證是否滿足500k以內的需求。
關於 canvas.toDataURL 的level到底是怎麼計算的,MDN文檔里也沒說,寫了個循環一次減少0.1的level壓縮了幾個圖片
用加減乘除算了一下,沒找到規律,數學不好放棄了(這個東西好像也不是能觀察出來的,看結果跟初始大小沒啥關系)。
這里要注意的是,有可能遇到超大圖片,0.1的level可能不足以壓縮到500k,所以小於0.1的時候,改變level遞減的差值繼續壓縮下去
在開始接收到圖片的時候給一個loading增加用戶的耐心好了,loading萬歲~
其實單純的壓縮質量遇到稍大的圖片,會導致頁面高頻計算,然後頁面基本就用不了了- -。有嘗試過用iphone的一個屏幕截圖(10M左右),壓的時候稍過一會,整個手機都在發燙,只能殺進程。
所以,若對長度沒有特殊的限制,可以做一個縮放,去加快壓縮的進度,提高能壓縮的圖片大小上限。
頁面到了ios上還是不行- -,可以看到最後圖片level為0.001,最長邊為764。
問題還是循環次數還是過多,計算頻率太高。從圖中可看出,對於大圖來說,初始設定的level和圖片尺寸過於寬松,可以優化一下初始level和尺寸。
有的時候還會遇到一張圖片無論如何也壓不到500k,就是上一次和這次的壓縮後大小沒有變化,這種情況需要拋錯,不讓循環繼續。
大圖片的等待時間稍長,可以給用戶先預覽一個base64的圖片增加等待耐心,方法名為 getImgBase64 ,這里都一並給出了
解決的隱患:上面這個方案會出現我需要一個500k的照片,壓到了520k之後,再壓了一次。有時候這最後的一次會特別誇張,直接將圖片弄到了幾十k。
參考了: https://github.com/WangYuLue/image-conversion
這個庫裡面有個方法 compressAccurately ,這個方法可以比較精準地壓縮。偷偷翻了一下源碼。
其實上一個方案的痛點就在於,如何在每一個壓縮循環里處理尺寸和壓縮比例。
總結
如有紕漏,歡迎指正
C. 上傳圖片時文件過大怎麼辦
可以使用photoshop軟體將圖片的品質調低,就可以將圖片文件大小變小。具體的設置方法如下:
一、打開photoshop軟體界面,點擊左上角的文件選擇打開按鈕。
D. 圖片拍照上傳解決方案
微信內置瀏覽器,和一些主流瀏覽器支持調用攝像頭,但也有很多不支持調用攝像頭,僅支持相冊。
如果是WebView中,就需要客戶端支持了,android和ios的許可權也是問題。
formData 簡介
簡單的說就是:通過formData,我們可以用ajax方式來發送表單數據;以前上傳圖片是需要用form表單提交的。
我們知道瀏覽器默認顯示的文件上傳按鈕是很醜的,通常UI都會對上傳按鈕進行設計。有以下幾種方案來寫樣式。
弊端:
坑
通過ref獲取上傳按鈕。
ref方式
event.target方式
坑:
FileReader 簡介
通過 readAsDataURL() ,在讀取操作完成後,result屬性中將包含一個data:URL格式的字元串以表示所讀取文件的內容。
base64字元串
兼容性
我在safari中測試,發現是支持的。
URL.createObjectURL 簡介
通過URL.createObjectURL()創建一個URL對象,這個URL對象表示指定的file對象或Blob對象。
兼容性
張鑫旭的文章: HTML5 file API加canvas實現圖片前端JS壓縮並上傳
張鑫旭的文章: 理解DOMString、Document、FormData、Blob、File、ArrayBuffer數據類型
使用Camera API
張鑫旭