最近在處理移動端選擇圖片實時預覽並上傳時遇到一個問題:上傳前圖片預覽正常,但上傳到服務器上的圖片展現到頁面上時,有時會出現圖片翻轉的問題,通常是翻轉 90 度。後經一翻研究找到了問題所在,特在此記錄一下。前端
接上面提到的問題,通過一些測試,發現:若是選取的圖片是在橫屏狀態下拍攝的,則上傳後不會出現圖片翻轉的問題;反之,若是是在豎屏狀態下拍攝的,上傳後就會出現圖片翻轉的問題。git
首先,圖片在本地預覽時正常,並且前端最後提交到後端的數據是用 FormData
來封裝處理的,用 FormData
能夠保證提交的數據和一般的表單提交沒有什麼區別,對後端來講是透明的,後端的處理邏輯不用修改就能夠處理帶文件的 Ajax 提交。所以,我猜測問題可能出在了後端。github
可是後端也沒有作什麼特殊的處理,怎麼展現的時候圖片就翻轉了呢?npm
OK,前面提到過這個問題和手機的拍照模式有關,豎屏下拍的照片會重現這個問題,橫屏下的則不會。難道這兩種模式下拍攝的照片不同?照片中保存的數據不同?,這不禁的使我想到了 [Exif][] 這個名詞,雖然我對它不是十分了解,可是印象中它是用來保存照片的一些元數據信息的,也許和它有關。編程
簡單的一搜索發現:Exif[orientation]有一篇關於它的詳細的介紹,此處不展開細講。簡單來講就是它有 8 個值,用來表示照片拍攝時相機旋轉的狀態,並且咱們能夠經過編程的方式讀取它。咱們日常用電腦來查看手機拍攝的照片時也會偶爾出現圖片翻轉的狀況,其緣由也是照片查看軟件沒有根據這個值將照片自動翻轉。canvas
通過搜索,在 SO 上找到了相關的問題。其思路就是讀取照片的 Exif 信息,判斷 Orientation 的值,而後將圖片進行相應的旋轉。問題已肯定,後端同窗很快就將這個問題給修復了,而且添加到了他們的公共模塊中。後端
你覺得問題就這樣解決了,其時並無。服務器
過了幾天,公司購置了幾臺全新的測試機,測試同窗將系統在一臺三星的機子上一測,又發現新問題了:選擇完圖片進行本地預覽時,發現圖片翻轉了!但上傳後再展現又是正常的。WTF!app
此次沒得說了,問題確定出在了前端預覽上。可是以前在安卓和 iOS 的設備上測試都是正常的呀,難道和機型有關?問了一下測試,得知這臺三星用的是 Android 5.0 的系統,好先進有木有!這難道是 5.0 中引入的一個問題?別想這些了,反正咱們也不可能在系統層面去修復這個問題,仍是想一想如何去兼容 5.0 吧。性能
當時想到了兩種方法,一種是選擇圖片後先上傳到服務器,再展現上傳的圖片進行預覽。這種方法的優勢是兼容性好,前端處理相對簡單;缺點是後端要提供圖片上傳的接口,而且若是用戶在保存以前更換圖片並不會刪除以前上傳的圖片。移動端的微博配圖就是用的這種方法。
另外一種方法是在本地進行圖片翻轉。咱們可使用 FileReader
API 來讀取圖片,以後像後端那樣分析 Exif 信息,旋轉圖片。這種作法的優勢是,預覽操做徹底在本地完成,不會產生沒必要要的文件上傳。缺點是 FileReader
在 Android 4.1 及以上的機型纔可使用,加上前端處理文件數據可能稍顯複雜,另外性能也是個問題。
可是最終咱們選擇了第二種方案。緣由是咱們以前的照片預覽就是用的 FileReader
API,不須要考慮低版本安卓的兼容性,這和項目的實際狀況有關。另外一個緣由是咱們認爲也許有前人已經遇到過這種問題,也許已經有了比較好的處理這個問題的功能模塊。後經搜索,找到了一個 fix-orientation
模塊,能夠經過 npm i fix-orientation --save
使用,具體的用法能夠參考項目的文檔。後來,掃了一眼它的代碼,發現它是用 canvas 來實現圖片的旋轉,並不會對正常的圖片進操做,性能問題不大,iOS 上秒開,安卓設備上稍長,能夠添加 loading 效果緩解一下。
至此,問題完美解決。
另外,像 fix-orientation
這樣小而美的模塊有不少,你們平時能夠多關注一下。