微信原图到底在救人,还是在泄露隐私?取决于你怎么用!

@ Jefferson Palomique

一. 序

最近又看到有人在讨论,微信原图泄露隐私的事情。起因好像是有人在社交媒体上发布了一张照片,然后被网友定位到具体的生活范围,甚至直接定位到居住的小区,楼层门牌号等信息,想想还是很可怕的。

在这个事件中的「网友定位」过程,其实很大一部分信息来自照片内容本身泄露的信息。各种警匪片大家应该也看过,专业人士可以通过一张照片分析出很多有用的信息,例如从窗户阳光的晒入角度,就可以分析出房间的朝向,有一些镜面的反光,也可以分析拍照环境的更多信息等等。

但这里说到微信原图暴露的信息,其实就是我们拍照时,在照片中携带的 Exif 信息 。这个 Exif 信息是相机在拍照时,专门记录的一些属性信息和拍摄数据。例如 GPS 定位数据、拍摄时间、拍摄时相机的方向等。

Exif 信息只是拍摄图片文件的固有信息,不光微信原图分享,其实你通过任何形式,将源文件分享出去,都是会携带这些信息。但其中 GPS 涉及到定位,而定位信息又是一个在某些人看来,比较「敏感」的信息。

为什么说是某些人呢?图片携带的定位信息,暴露出去确实可能会造成困扰,但是某些时刻,这又是可以救命的,例如《 民警巧用图片定位,解救被骗 CX 组织受害人 》之类的新闻,我想大家应该也看过。另外也有很多人反映,不使用原图会导致接收到的图片模糊( 被压缩 ),这也是一部分人偏爱发送「原图」的原因。

一边确实有隐私保护的需求,另一边也有发送无损原图的需要。 微信是怎么解决的呢? 在发送图片的时候,提供了一个「原图」的选项,将是否发送图片源文件的选择权,交到了用户自己的手里。值得一提的是,微信发送图片,为了传输效率以及隐私的考虑,默认是发送压缩后的图片的,在压缩的过程中,会清理 EXIF 信息,所以如果你找不到「原图」的选项,那么就说明这里只支持发送「压缩图」,例如微信朋友圈。

到这就清晰了, 所谓微信原图泄露的隐私,只是图片在拍摄时存入的固有信息 EXIF,而只要通过处理 EXIF 信息就会被抹去。所以如果想对方接收到 EXIF 信息,就发送原图,反之则可以通过压缩处理一下再发送

本来到这里就算完了,不过作为一个技术向的公众号,我们再继续科普一下照片 EXIF 信息以及在 Android 开发时如何读取和修改它。

二. 图片的 EXIF

2.1 什么是 Exif?

Exif( Exchangeable image file format )表示 可交换图像文件格式 ,是专门记录数码相机拍照时的一些参数,例如定位信息、拍摄设备方向、曝光、色彩等信息,并将这些信息写入图片文件中,以保证在传输时保留这些信息。

Exif 可以被附加到 JPEG、TIFF、RIFF 等文件中,简单来说,图片文件中有一块特殊的区域,可以存放一些额外的 Exif 信息,以保证我们在使用图片时更方便。

这本身没什么坏处,除了 GPS 定位信息会让我们敏感之外,其他信息更多的是为了辅助我们使用。例如前面提到的拍摄照片时,设备的方向信息,就可以保证无论我们拍照时,手机的方向是侧着的或者是倒着的,拍照后在相册中预览时,永远保持正着的原因。

一般的图片处理软件,都可以读取出图片的 Exif 信息,并且支持修改。随便找一个在线查看 Exif 信息的工具网站,就可以查看到我上传图片的 Exif 信息。

图片的 Exif 信息,没有任何的保护,我们可以对其任意的修改。但是这些信息你也看到了,没有修改的意义,通常就是压缩时直接抹去。

2.2 压缩会损失 Exif

压缩会损失掉 Exif 信息,这也就是为什么在不发送原图的时候,接收者是读取不到 Exif 信息的。这很好理解,以现在图片手机摄像头支持的像素来说,一张大画幅的照片,随随便便就是上十 MB 甚至几十 MB,这对发送的网络和存储都是有压力的,所以通常 App 的做法是在发送前,本地做一次图片压缩。

前面提到,Exif 信息会记录拍照时,拍照设备持握的方向,例如有时我们会将手机倒过来拍全身照。这照片在相册展示时,永远都是正确的方向,我不会得到一个头朝下的照片。

如果压缩会导致 Exif 丢失,为什么压缩后的图片,在显示时依然可以保证显示方向的正确?

这就要说到图片压缩时的策略,我们就拿 Android 下比较出名的开源图片压缩库 Luban 举例,Github 上很多图片压缩库都是借鉴或者引用它来实现的。

在 Luban 的 Engine.java 文件中,可以找到相关的代码,逻辑很简单,就是在压缩前,先将图片按照 Exif 中记录的方向,旋转后再进行处理。

这也就是为什么图片压缩时,虽然抹去了 Exif 信息,但是图片显示的方向依然是正确的原因。

2.3 压缩后保留 Exif 信息

保留 Exif 信息这种需求,我确实想不到有什么场景需要在压缩后,保留此信息的。

但是如果有必要的话,最简单的处理方式,就是在压缩前,将图片的 Exif 读取存储,压缩后再写入图片中。

那么这就又涉及到,我们如何编码读取和写入图片的 Exif 信息。

三. 操作 Exif 信息

3.1 使用 ExifInterface

在 Android 中,需要 ExifInterface 来读取 Exif 信息,如果你直接在 AS 中搜索这个类,可以发现在 android.media 包下,确实有一个 ExifInterface ,但是我不建议使用它。

自从 Android Support 25.1.0 开始,又添加了一个新的支持库: ExifInterface 。这是由于 Android 7.1 对 ExifInterface 做了重大修改,因此建议使用此 Support 包,它最低支持到 Api 9+。

随着 AndroidX 的发布,对 ExifInterface 也做了迁移支持,只不过现在的版本还是 Beta01。

使用方式并没有什么太大的差异,完全取决于你项目的要求,这里举例就使用最新的 28.+ 了

api "com.android.support:exifiinterface:28.+"

Support 包和 android.media 中的 ExifInterface 基本操作,都是类似的,都提供了对指定图片的 Exif 信息进行读写的功能,区别在于 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 。

对 Exif 的使用,这里就不单独举例了,有兴趣可以看看我之前的文章《 Android 读取 Exif 示例

四. 小结时刻

到这里你应该就清楚了,微信原图泄露的只是照相机 App 在拍照时,对图片写入的固有信息,并没有什么太多的秘密,这些信息在图片压缩时就会被抹去。

最后再总结一下:

  1. 图片在拍照时,会写入 Exif 信息到图片文件中,直接发送文件会保留此信息。

  2. 99% 的图片压缩,都会抹去 Exif 信息。

  3. Android 下读取 Exif 信息,可以使用 ExifInterface。

本文对你有帮助吗? 留言、转发、点好看 是最大的支持,谢谢!

联机圆桌 」:point_left:推荐我的知识星球,一年 50 个优质问题,上桌联机学习。

公众号后台回复成长『 成长 』,将会得到我准备的学习资料。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章