天天看點

微信原圖洩露的隻能是 Exif ,你的隐私不在這!!!

既然要聊到圖檔的 Exif 資訊,那麼就先來了解一下什麼是 Exif ?

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 對象。

但是他們也是有差異的:

1、使用 InputStream 獲得的 ExifInterface 是無法修改的,而直接讀取的圖檔檔案,則是可以修改的。

獲得 ExifInterface 對象之後,就可以對其進行操作。

對于大多數屬性,隻需要視情況使用 <code>getAttributeInt()</code> 、<code>getAttributeDouble()</code> 、<code>getAttribute()</code>(适用于 String)。它們分别表示不同類型的屬性。這些方法接收一個 String 類型的參數,這些參數都以常量的形式,以 TAG_Xxx 為開頭,被标記在 ExifInterface 中。

具體想知道不同的 TAG_Xxx 需要使用什麼方法擷取,可以直接看文檔。

其中注釋就已經标記了該屬性代表的類型。

下面舉個最常見的例子,擷取圖檔的拍攝方向,用于在顯示的時候進行旋轉。

當然,還有一些其它比較重要的資訊,例如謠傳微信暴露的位置資訊,可以通過 <code>getLatLong()</code> 方法擷取到一個 float 的數組,分别表示經度和次元,<code>getAltitude()</code> 擷取拍攝的海拔高度,機關是 米 。還有一些圖檔,如果自帶縮略圖,可以使用 <code>getThumbnail()</code> 方法擷取到。更多操作,詳見代碼文檔,這裡就不一一舉例了。

需要注意的是,ExifInterface 是一個不嚴謹的資料,它不存在任何必須的标記字段,每個标記字段值,都是可選的,是以我們在讀取的時候,一定要考慮到沒有讀取到 Exif 資料的情況,如何處理。缺少 Exif 資料不一定是因為特定的屬性沒有資料,還有可能是某些格式根本不支援 Exif 資訊(例如,PNG 和 WebP )。

ExifInterface 其實是不可信的,它隻能作為一個參考。因為任何程式都可以對它進行修改。

修改 Exif 資訊可以使用 <code>setAttribute()</code> 方法,它接收一個 key-value 的鍵值對。用于标記待修改的 Tag 和最終修改後的值。修改完成之後,還需要調用 <code>saveAttributes()</code> 方法,否者不會将設定的 Exif 資訊寫入到圖檔檔案中。

雖然文檔中,描述 <code>saveAttributes()</code> 方法是一個耗時操作,推薦使用 <code>setAttribute()</code> ,但是實際測試來看,不調用 <code>saveAttributes()</code> ,是不會儲存資料的。這個實際操作起來,在模拟器上會有短暫的卡頓,但是真機上并不存在這樣的情況。

還有一點需要注意,雖然文檔中表明,Exif 資訊是一個弱校驗的資料,但是它對 TAG 的值是有要求的,如果不是它本身定義的值,儲存并不會報錯,但是讀取的時候,會傳回 null 。

既然已經講解清楚 ExifInterface 的使用細節,接下來使用一個 Demo 來展示它具體的操作細節。

首先定義三個按鈕,如下圖:

輸出 Exif 資訊,按鈕邏輯:

讀取 Exif 資訊,按鈕邏輯:

寫入 Exif 資訊,按鈕邏輯:

運作的效果如下:

到這裡基本上就講解清楚 Exif 在 Android 中的所有細節。可以看到實際上 Exif 的資訊并不可信,也并不安全,是以你女友要是拿着你分享的照片說你為什麼這個時間出現在這裡,你應該知道如何圓回去,全是 Exif 的鍋。

本文轉自承香墨影部落格園部落格,原文連結:http://www.cnblogs.com/plokmju/p/7462891.html,如需轉載請自行聯系原作者

繼續閱讀