一、簡介
圖片的壓縮與上傳,是APP裡一個很常用的功能。我們來年看 ChiTuStore 是怎樣做的。相關檔案 App/Module/User/UserInfo.html,App/Module/User/UserInfo.ts
二、HTML佈局
HTML 檔案中,有如下二句,第一句就是上圖所看到的圖片,其中的 class 表示該圖片以圓形來顯示,並且靠右。第二句是一個 Input 控制元件,其型別為 file ,是用來上傳檔案的。值得注意的是 style,這的作用是讓該控制元件與圖片重疊,並且透明(opacity:0),accept="image/*" 的作用是隻上傳圖片。
<img data-bind="attr:{src:userInfo.HeadImageUrl}" class="img-circle pull-right" style="width:70px;height:70px;"> <input type="file" style="position:absolute;top:0px;left:0px;opacity:0;width:100%;height:90px;" accept="image/*">
三、圖片的壓縮
傳統 WEB 的做法,都是把圖片直接上傳到服務端,然後在服務端進行壓縮。但現在,在H5 中,是可以對圖片進行壓縮再上傳的。我們來看一下 JS 程式碼,其中的 ImageFileResize 就是用來處理圖片的壓縮的。
page.viewChanged.add(() => { var e = page.nodes().content.querySelector('[type="file"]'); var imageFileResize = new ImageFileResize(<HTMLInputElement>e, { maxWidth: 100, maxHeight: 100 }); imageFileResize.imageResized = (urls: string[], thumbs1: string[], thumbs2: string[]) => { model.userInfo.HeadImageUrl(thumbs1[0]); member.setUserInfo(mapping.toJS(model.userInfo)); } ko.applyBindings(model, page.node()); })
我們現在來看一下 ImageFileResize 中的關鍵程式碼,這段程式碼的作用是用來把 <input type="file"/> 選取的檔案,進行壓縮的。其中有幾個關鍵的物件、函式,是 H5 中的 API,FileReader,createObjectURL,Image。
這幾個物件、函式的具體用法,在這裡就不展開說了,網上搜一下就可以找到答案了。
var reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = (ev: Event) => { var blob = new Blob([event.target['result']]); window['URL'] = window['URL'] || window['webkitURL']; var blobURL = window['URL'].createObjectURL(blob); // and get it's URL var image = new Image(); image.src = blobURL; image.onload = () => { var url = this.resizeMe(image, max_width, max_height); var thumb = this.resizeMe(image, this.thumb2.maxWidth, this.thumb2.maxHeight); result.resolve({ index: index, url: url, data: url, thumb: thumb }); } }
下面我們再來看一下 resizeMe 函式,這個函式的把的圖片(HTMLImageElement),轉換為了 base64 的字串,其中一個重要的物件就是 canvas,它也是 H5 中的物件。通過它可以把圖片轉換為 base64 字串。
private resizeMe(img: HTMLImageElement, max_width: number, max_height: number) { var canvas = document.createElement('canvas'); var width: number = img.width; var height: number = img.height; // calculate the width and height, constraining the proportions if (width > height) { if (width > max_width) { height = Math.round(height *= max_width / width); width = max_width; } } else { if (height > max_height) { width = Math.round(width *= max_height / height); height = max_height; } } canvas.width = width; canvas.height = height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); return canvas.toDataURL("image/jpeg", 0.7); }
四、服務端的儲存
服務的儲存有兩種方法
1、把 base64 字串轉換為二進位制流,然後再儲存為圖片檔案。
2、直接把 base64 儲存資料庫。在這個專案,是把它儲存到 MongoDB 資料庫。
五、瀏覽器的坑
即然是通過瀏覽器進行壓縮上傳,那麼就無法避免會有坑。
1、在 QQ 瀏覽器中,不起作用。據說是不支援 canvas 。
2、在 APP 的混合開發中,在錘子 T2 的手機也不起作用。
六、小結
儘管在本地壓縮、預覽圖片有著很好的使用者體驗,但是相容性差,如果是 APP 的開發,還是呼叫原生的介面吧。如果瀏覽器的 WEB APP 專案,還是得考慮相容性。不支援 canvas 的瀏覽器,使用傳統的方法來上傳圖片。
程式碼已經開源在 github,感興趣的朋友可以自行下載。https://github.com/ansiboy/ChiTuStore