微信原圖到底在救人,還是在泄露隱私?取決于你怎么用!
一. 序
最近又看到有人在討論,微信原圖泄露隱私的事情。起因好像是有人在社交媒體上發(fā)布了一張照片,然后被網友定位到具體的生活范圍,甚至直接定位到居住的小區(qū),樓層門牌號等信息,想想還是很可怕的。
在這個事件中的「網友定位」過程,其實很大一部分信息來自照片內容本身泄露的信息。各種警匪片大家應該也看過,專業(yè)人士可以通過一張照片分析出很多有用的信息,例如從窗戶陽光的曬入角度,就可以分析出房間的朝向,有一些鏡面的反光,也可以分析拍照環(huán)境的更多信息等等。
但這里說到微信原圖暴露的信息,其實就是我們拍照時,在照片中攜帶的 Exif 信息。這個 Exif 信息是相機在拍照時,專門記錄的一些屬性信息和拍攝數據。例如 GPS 定位數據、拍攝時間、拍攝時相機的方向等。
Exif 信息只是拍攝圖片文件的固有信息,不光微信原圖分享,其實你通過任何形式,將源文件分享出去,都是會攜帶這些信息。但其中 GPS 涉及到定位,而定位信息又是一個在某些人看來,比較「敏感」的信息。
為什么說是某些人呢?圖片攜帶的定位信息,暴露出去確實可能會造成困擾,但是某些時刻,這又是可以救命的,例如《民警巧用圖片定位,解救被騙 CX 組織受害人》之類的新聞,我想大家應該也看過。另外也有很多人反映,不使用原圖會導致接收到的圖片模糊(被壓縮),這也是一部分人偏愛發(fā)送「原圖」的原因。
一邊確實有隱私保護的需求,另一邊也有發(fā)送無損原圖的需要。微信是怎么解決的呢?在發(fā)送圖片的時候,提供了一個「原圖」的選項,將是否發(fā)送圖片源文件的選擇權,交到了用戶自己的手里。值得一提的是,微信發(fā)送圖片,為了傳輸效率以及隱私的考慮,默認是發(fā)送壓縮后的圖片的,在壓縮的過程中,會清理 EXIF 信息,所以如果你找不到「原圖」的選項,那么就說明這里只支持發(fā)送「壓縮圖」,例如微信朋友圈。
到這就清晰了,所謂微信原圖泄露的隱私,只是圖片在拍攝時存入的固有信息 EXIF,而只要通過處理 EXIF 信息就會被抹去。所以如果想對方接收到 EXIF 信息,就發(fā)送原圖,反之則可以通過壓縮處理一下再發(fā)送。
本來到這里就算完了,不過作為一個技術向的公眾號,我們再繼續(xù)科普一下照片 EXIF 信息以及在 Android 開發(fā)時如何讀取和修改它。
二. 圖片的 EXIF
2.1 什么是 Exif?
Exif(Exchangeable image file format)表示可交換圖像文件格式,是專門記錄數碼相機拍照時的一些參數,例如定位信息、拍攝設備方向、曝光、色彩等信息,并將這些信息寫入圖片文件中,以保證在傳輸時保留這些信息。
Exif 可以被附加到 JPEG、TIFF、RIFF 等文件中,簡單來說,圖片文件中有一塊特殊的區(qū)域,可以存放一些額外的 Exif 信息,以保證我們在使用圖片時更方便。
這本身沒什么壞處,除了 GPS 定位信息會讓我們敏感之外,其他信息更多的是為了輔助我們使用。例如前面提到的拍攝照片時,設備的方向信息,就可以保證無論我們拍照時,手機的方向是側著的或者是倒著的,拍照后在相冊中預覽時,永遠保持正著的原因。
一般的圖片處理軟件,都可以讀取出圖片的 Exif 信息,并且支持修改。隨便找一個在線查看 Exif 信息的工具網站,就可以查看到我上傳圖片的 Exif 信息。
圖片的 Exif 信息,沒有任何的保護,我們可以對其任意的修改。但是這些信息你也看到了,沒有修改的意義,通常就是壓縮時直接抹去。
2.2 壓縮會損失 Exif
壓縮會損失掉 Exif 信息,這也就是為什么在不發(fā)送原圖的時候,接收者是讀取不到 Exif 信息的。這很好理解,以現在圖片手機攝像頭支持的像素來說,一張大畫幅的照片,隨隨便便就是上十 MB 甚至幾十 MB,這對發(fā)送的網絡和存儲都是有壓力的,所以通常 App 的做法是在發(fā)送前,本地做一次圖片壓縮。
前面提到,Exif 信息會記錄拍照時,拍照設備持握的方向,例如有時我們會將手機倒過來拍全身照。這照片在相冊展示時,永遠都是正確的方向,我不會得到一個頭朝下的照片。
如果壓縮會導致 Exif 丟失,為什么壓縮后的圖片,在顯示時依然可以保證顯示方向的正確?
這就要說到圖片壓縮時的策略,我們就拿 Android 下比較出名的開源圖片壓縮庫 Luban 舉例,Github 上很多圖片壓縮庫都是借鑒或者引用它來實現的。
在 Luban 的 Engine.java 文件中,可以找到相關的代碼,邏輯很簡單,就是在壓縮前,先將圖片按照 Exif 中記錄的方向,旋轉后再進行處理。
這也就是為什么圖片壓縮時,雖然抹去了 Exif 信息,但是圖片顯示的方向依然是正確的原因。
2.3 壓縮后保留 Exif 信息
保留 Exif 信息這種需求,我確實想不到有什么場景需要在壓縮后,保留此信息的。
但是如果有必要的話,最簡單的處理方式,就是在壓縮前,將圖片的 Exif 讀取存儲,壓縮后再寫入圖片中。
那么這就又涉及到,我們如何編碼讀取和寫入圖片的 Exif 信息。
三. 操作 Exif 信息
3.1 使用 ExifInterface
在 Android 中,需要 ExifInterface 來讀取 Exif 信息,如果你直接在 AS 中搜索這個類,可以發(fā)現在 android.media 包下,確實有一個 ExifInterface,但是我不建議使用它。
自從 Android Support 25.1.0 開始,又添加了一個新的支持庫:ExifInterface。這是由于 Android 7.1 對 ExifInterface 做了重大修改,因此建議使用此 Support 包,它最低支持到 Api 9+。
隨著 AndroidX 的發(fā)布,對 ExifInterface 也做了遷移支持,只不過現在的版本還是 Beta01。
使用方式并沒有什么太大的差異,完全取決于你項目的要求,這里舉例就使用最新的 28.+ 了
- api "com.android.support:exifiinterface:28.+"
Support 包和 android.media 中的 ExifInterface 基本操作,都是類似的,都提供了對指定圖片的 Exif 信息進行讀寫的功能,區(qū)別在于 Support 包中包含了 140 多個不同的屬性,而其中近 100 個是 android 7.1 中新增的。
3.2 獲取 ExifInterface
ExifInterface 存在兩個構造函數,可以傳遞一個圖片文件路徑或者圖片的 InputStream。
上面兩種構造方式,都可以獲取到一個 ExifInterface 對象。它們之間有些差異:
1、使用 InputStream 獲得的 ExifInterface 無法被修改,而直接讀取的圖片文件,則可以修改。
2、ExifInterface 無法處理遠端的 InputStream,例如是從 HttpURIConnection 返回的輸入流,所以這里建議使用 content:// 或者file:// 這種 Uri 路徑。
3.3 讀取 Exif 信息
獲得 ExifInterface 對象之后,就可以對其進行操作。
大多數的 Exif 屬性,只需要視情況使用 getAttributeInt() 、getAttributeDouble()、getAttribute()(適用于 String)。它們分別表示不同類型的屬性。這些方法接收一個 String 類型的參數,這些參數都以常量的形式,以 TAG_Xxx 為開頭,被標記在 ExifInterface 中。
具體想知道不同的 TAG_Xxx 需要使用什么方法獲取,可以直接看文檔。
其中注釋就已經標記了該屬性代表的類型。
下面舉個最常見的例子,獲取圖片的拍攝方向,用于在顯示的時候進行旋轉。
當然,還有一些其它比較重要的信息,例如謠傳微信原圖暴露的位置信息,可以通過 getLatLong() 方法獲取到一個 float 的數組,分別表示經度和維度,getAltitude() 獲取拍攝的海拔高度,單位是 米 。還有一些圖片,如果自帶縮略圖,可以使用 getThumbnail() 方法獲取到。更多操作,詳見代碼文檔,這里就不一一舉例了。
需要注意的是,Exif 是一個不嚴謹的數據,它不存在任何必須的標記字段,每個標記字段值,都是可選的,所以我們在讀取的時候,一定要考慮讀取時的異常處理。
3.4 寫入 Exif 信息
ExifInterface 其實是不可信的,它只能作為一個參考。因為任何程序都可以對它進行修改。
修改 Exif 信息可以使用 setAttribute() 方法,它接收一個 key-value 的鍵值對。用于標記待修改的 Tag 和最終修改后的值。在修改完成之后,還需調用saveAttributes() 方法,否者不會將設置的 Exif 信息寫入到圖片文件中。
還有一點需要注意,雖然文檔中表明,Exif 信息是一個弱校驗的數據,但是它對 TAG 的值是有要求的,如果不是它本身定義的值,保存并不會報錯,但是讀取的時候,會返回 null 。
四. 小結時刻
到這里你應該就清楚了,微信原圖泄露的只是照相機 App 在拍照時,對圖片寫入的固有信息,并沒有什么太多的秘密,這些信息在圖片壓縮時就會被抹去。
最后再總結一下:
圖片在拍照時,會寫入 Exif 信息到圖片文件中,直接發(fā)送文件會保留此信息。
99% 的圖片壓縮,都會抹去 Exif 信息。
Android 下讀取 Exif 信息,可以使用 ExifInterface。
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉載請通過微信公眾號聯系作者獲取授權】