這一篇要說說裁剪、壓縮,這兩個功能都要用到 canvas 的能力,canvas 在 IE9 以上瀏覽器都支援良好,也為 IE9 提供為數不多的可以進行檔案操作的 API。
基礎程式碼
<div id=`box`></div>
const canvas = document.getElementById(`box`)
const ctx = canvas.getContext(`2d`)
如何給 canvas 匯入圖片
通過例項方法 drawImage
可以在canvas 中繪製圖片。
drawImage
接受的第一個引數描述如下:
An element to draw into the context. The specification permits any canvas image source (CanvasImageSource), such as an HTMLImageElement, an HTMLVideoElement, an HTMLCanvasElement or an ImageBitmap.
但是 IE9 中無法傳入一個載入了圖片的 IMG 元素。
換種思路,在 IE9 中做以下相容處理:
先把圖片上傳,然後載入遠端圖片進行處理,但是碰到一些問題:
- 如果本地圖片過大,上傳並下載耗時嚴重
- canvas 由於安全問題無法載入跨域圖片,導致上傳 CDN 的方案無法使用
或者直接上到 CDN (我們用的是七牛),並把上傳後的 key 以及裁剪引數傳給後臺,通過後臺呼叫七牛的裁剪服務和持久化服務,但是問題又來了:
- 增加了後臺服務的依賴,增加了請求數
- 由於七牛在持久化時,需要排隊處理,不保證能實時預覽
- 定時去輪詢新的圖片地址,經常需要耗時很長,並且有可能生成失敗
- 即使通過臨時展示剪裁服務返回回來的地址,也經常會出現持久化服務呼叫失敗的問題,失敗原因資訊很少,除錯很麻煩。
總的來說,這些方案價效比不高!
如何做裁剪
兩種思路:
- 通過 CSS + JS 模擬可以獲取 裁剪長寬 以及 裁剪起始位置,然後將引數輸出給 canvas
- 直接在 canvas 裡面操作
最後,都通過例項方法 drawImage
來進行裁剪。
如何壓縮
github上有一個國人用 javascript 寫的無依賴的本地壓縮庫 localResizeIMG3。
也可以繼續用 canvas 的例項方法 toDataURL
簡單實現
打臉的事情要開始了
利用 flash 製作了一個swf 檔案,在 IE9 中選擇圖片、讀取圖片,並輸出 base64 格式。
本來想把本地圖片地址傳給 swf 檔案,讓它直接讀路徑,但是由於安全問題,會被阻止,所以還得通過 flash 來選擇圖片
雖然被打臉,說幾個好處:
- 可以統一載入 base64 格式的圖片,圖片預覽,獲取圖片長寬,都不用單獨處理 IE9
- 如果需要,可以擴充套件一個讀取圖片大小的功能
- 上傳圖片,可以直接用 xmlhttprequest 上傳 Base64 格式的圖片(這裡用到的七牛 CDN 提供的上傳 Base64 圖片服務),不用後臺配合搞 iframe 上傳方案,或者載入第三方上傳外掛,通過 flash 上傳
實現程式碼參考:https://github.com/yannickcr/…
現實是殘酷的,七牛 CDN 上確實能找到一個古老的上傳 base64 格式圖片的服務,但是由於服務是跨域的,並且要求在請求頭裡面攜帶引數,因此 IE9 中是無法通過 Javascript 實現上傳。
總結
- 如果支援 IE9 及以下瀏覽器,建議本地模擬裁剪,把裁剪引數和原圖傳給後臺,剩下的都交給後臺處理
- 如果支援 IE10 等高階瀏覽器,建議使用本地方案,把裁剪壓縮後的圖片傳到 CDN。