版權聲明:android
本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。數組
每週會統一更新到這裏,若是喜歡,可關注公衆號獲取最新文章。安全
未經容許,不得轉載。微信
最近不少公衆號都推送了關於『微信發送原圖泄露隱私』的傳言。實際上這裏說的泄露,只是發送原圖會攜帶 Exif 信息,而 Exif 信息裏會攜帶一些例如 GPS 定位數據、拍攝時間等等信息。框架
這些信息基本上任何智能手機或者相機,在拍攝照片的時候,都會自動寫入到圖片中。而這樣的圖片只要發送出去,不管是以何種方式,都是會暴露你和圖片相關的部分信息,和微信的關係並不大(不過聽說發朋友圈的時候,圖片都會被壓縮,抹去 Exif 信息)。函數
其實若是比較注重我的信息的話,能夠在手機的設置中,關閉定位服務等隱私相關功能,工具
那麼,本文就來聊聊,在 Android 下,讀取 Exif 信息你須要知道的全部信息。測試
既然要聊到圖片的 Exif 信息,那麼就先來了解一下什麼是 Exif ?gradle
Exif 的全稱是(Exchangeable image file format),它是可交換圖像文件格式。是專門爲數碼相機的照片設定的,能夠記錄數碼照片的屬性信息和拍攝數據。網站
Exif 能夠被附加在 JPEG、TIFF、RIFF 等文件之中,爲其增長有關數碼相機拍攝信息的內容和縮略圖或圖像處理軟件的一些版本信息。
上面是維基百科的解釋,通俗來將,Exif 能夠在圖片上附加一些額外的信息,例如拍攝地點,拍攝方向,拍攝的設備信息,拍攝圖片的時間等等。這些信息並無什麼壞處,例如最經常使用拍攝照片的方向信息,全部的圖片軟件都依賴它的值來肯定圖片在你設備上顯示的方向,這就是你不管手機是倒着拍攝仍是橫着拍攝,最終呈如今手機上都是正的的緣由。
通常圖片處理軟件均可以讀出圖片的 Exif 信息,而且能夠被修改。我隨便找了個在線的查看 Exif 的工具網站,就能夠完整的讀取出我上傳圖片的 Exif 信息,下圖只是 Exif 信息的一部分。
在 Android 中,讀取 Exif 信息,須要使用到 ExifInterface 這個接口,若是你在 Android 中搜索這個類,能夠發如今 android.media 包下,確實有一個 ExifInterface 。
可是從 Android Support 25.1.0 支持庫發佈以後,又添加了一個新的支持庫:ExifInterface 。這是因爲 Android 7.1 引入了對框架 ExifInterface 的重大修改,所以使用此 Support 包,能夠最低支持到 Api 9+。這裏強烈推薦使用 Support 包中的 ExifInterface 。
使用它,須要在 Gradle 中配置依賴,這裏使用最新的 26.+。
其實基本功能都是相似的,對嵌入圖片文件的 Exif 標記進行讀寫的功能,區別在於多包含了 140 多個不一樣的屬性(其中近 100 個是 Android 7.1 中新增的)
接下來的內容都是基於 Support 包中的 ExifInterface ,來分析的,實際上 android.media 包下的 ExifInterface 還它在接口上,仍是略有差別的。
ExifInterface 存在兩個構造函數,能夠傳遞一個圖片文件路徑或者圖片的 InputStream。
上面兩種構造方式,均可以獲取到一個 ExifInterface 對象。
可是他們也是有差別的:
一、使用 InputStream 得到的 ExifInterface 是沒法修改的,而直接讀取的圖片文件,則是能夠修改的。
二、ExifInterface 沒法處理遠程的 InputStream,例如是從 HttpURIConnection 返回的輸入流,因此這裏建議使用 content:// 或者 file:// 這種 Uri 路徑。
得到 ExifInterface 對象以後,就能夠對其進行操做。
對於大多數屬性,只須要視狀況使用 getAttributeInt()
、getAttributeDouble()
、getAttribute()
(適用於 String)。它們分別表示不一樣類型的屬性。這些方法接收一個 String 類型的參數,這些參數都以常量的形式,以 TAG_Xxx 爲開頭,被標記在 ExifInterface 中。
具體想知道不一樣的 TAG_Xxx 須要使用什麼方法獲取,能夠直接看文檔。
其中註釋就已經標記了該屬性表明的類型。
下面舉個最多見的例子,獲取圖片的拍攝方向,用於在顯示的時候進行旋轉。
固然,還有一些其它比較重要的信息,例如謠傳微信暴露的位置信息,能夠經過 getLatLong()
方法獲取到一個 float 的數組,分別表示經度和維度,getAltitude()
獲取拍攝的海拔高度,單位是 米 。還有一些圖片,若是自帶縮略圖,可使用 getThumbnail()
方法獲取到。更多操做,詳見代碼文檔,這裏就不一一舉例了。
須要注意的是,ExifInterface 是一個不嚴謹的數據,它不存在任何須須的標記字段,每一個標記字段值,都是可選的,因此咱們在讀取的時候,必定要考慮到沒有讀取到 Exif 數據的狀況,如何處理。缺乏 Exif 數據不必定是由於特定的屬性沒有數據,還有多是某些格式根本不支持 Exif 信息(例如,PNG 和 WebP )。
ExifInterface 實際上是不可信的,它只能做爲一個參考。由於任何程序均可以對它進行修改。
修改 Exif 信息可使用 setAttribute()
方法,它接收一個 key-value 的鍵值對。用於標記待修改的 Tag 和最終修改後的值。修改完成以後,還須要調用 saveAttributes()
方法,否者不會將設置的 Exif 信息寫入到圖片文件中。
雖然文檔中,描述
saveAttributes()
方法是一個耗時操做,推薦使用setAttribute()
,可是實際測試來看,不調用saveAttributes()
,是不會保存數據的。這個實際操做起來,在模擬器上會有短暫的卡頓,可是真機上並不存在這樣的狀況。
還有一點須要注意,雖然文檔中代表,Exif 信息是一個弱校驗的數據,可是它對 TAG 的值是有要求的,若是不是它自己定義的值,保存並不會報錯,可是讀取的時候,會返回 null 。
既然已經講解清楚 ExifInterface 的使用細節,接下來使用一個 Demo 來展現它具體的操做細節。
首先定義三個按鈕,以下圖:
輸出 Exif 信息,按鈕邏輯:
讀取 Exif 信息,按鈕邏輯:
寫入 Exif 信息,按鈕邏輯:
運行的效果以下:
到這裏基本上就講解清楚 Exif 在 Android 中的全部細節。能夠看到實際上 Exif 的信息並不可信,也並不安全,因此你女朋友要是拿着你分享的照片說你爲何這個時間出如今這裏,你應該知道如何圓回去,全是 Exif 的鍋。