版权声明: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 的锅。