由于开发过程中需要对图片进行处理,需要对图片获取尽可能详细的信息,比如图片的Exif通常包含一些照片拍摄修改的时间,分辨率,大小,经纬度等信息,突然一天新增了一个需求:需要获取图片是前置摄像头拍摄还是后置摄像头拍摄的。得知需求后查询了一众资料,两大搜索Google,百度,Android Developer官方文档,MediaStore中关于Image的类属性、方法,Exif等元数据解析等等,均未看到有标记前后置摄像头的属性,于是反馈,后被告知一加6拍摄的照片有相应字段,于是乎单独拿出来分析了。
不可能的需求?
已知需求:获取图片是前置摄像头拍摄还是后置摄像头拍摄的
尝试方法:
- 两大搜索(Google,Baidu)
- Android Developer官方文档以及MediaStore中关于Image的类属性、方法
- MetaData数据分析
尝试结果:
- 失败
- 失败
图片的MetaData数据分析
什么是图片的Metadata?摘一段Wiki的解释
1 | Photographs |
Wiki对Exif的解释-https://zh.wikipedia.org/wiki/EXIF
Wiki对XMP的解释-https://zh.wikipedia.org/wiki/XMP
如果你需要查看一张图片的MetaData信息,在不下载任何程序的情况下,当然是放网站上识别了,如:http://metapicz.com/#landing
现在我有一张图使用魅族6 Note拍摄,如下:
将其使用网站识别的结果如下:
可以看出,除了基本的Exif信息,就没有其余的多余信息了,同时还测试了一加5T,vivo,华为,三星,小米等几部手机,都一样没有,贴个一加5T的,其他的就不贴了,如下:
将其使用网站识别的结果如下:
网站显示没有XMP数据,但是你如果信以为真,那你就错了,网站展示的XMP数据只是对标准XMP数据而言,但是对于非标准XMP数据,网站是不识别的。下面我不使用很专业的分析工具,我们使用PhotoShop,它用来分析图片MetaData很是方便。
具体步骤
- 将图片使用PhotoShop打开
- 使用快捷键
CTRL+ALT+SHFIT+I
打开MetaData面板 - 点击
原始数据
下面分别是魅族拍摄的照片的元数据和一加5T拍摄的照片的元数据
魅族6 Note 前置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
魅族6 Note 后置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
OnePlus 5T 前置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
OnePlus 5T 后置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
可以看出,一加自己定义了一个XML
标签,并且使用该标签写入了自己的数据,其中<OPMedia:LensFacing>Back</OPMedia:LensFacing>
便是我们寻找的,键LensFacing
对应的值为Back
,表明这张图片使用后置摄像头拍摄,那么是不是所有的机型都有写入这个信息呢?下面是其他机型拍摄的照片的元数据:
OnePlus 6 前置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
OnePlus 6 后置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
vivo X9 前置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
vivo X9 后置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
Pixel 2 前置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
Pixel 2 后置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
红米 5 Plus 前置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
红米 5 Plus 后置:
1 | <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c142 79.160924, 2017/07/13-01:06:39 "> |
一加可行
由上面的结果可知,目前只有一加在自定义属性中添加了LensFacing
用来标记前后置摄像头,其余机型均为有相应字段用来标记前后置摄像头,所以在编码时只针对一加进行编码就行,若后续有其他机型也增加了标记字段,则进行补充编码即可。
编码进行时
由于时间紧迫,加上重复造轮子过于复杂和耗时,我选择了metadata-extractor这个库,具体使用与示例请参照对应wiki及源码,这里贴个简陋的Demo的MainActivity
1 | package com.kaithmy.metadatademo |
突发情况?
程序在其他手机上跑的好好的,突然在魅族6 Note上突然崩溃了,报错信息如下:
1 | E/AndroidRuntime: FATAL EXCEPTION: main |
接口类方法getValue
找不到?,吓得我赶紧点进去看了看
1 | // ================================================================================================= |
其中getValue()
和getOptions()
继承自接口XMPProperty
1 | // ================================================================================================= |
明明有啊,这不坑爹嘛这是!难道是混淆了?于是在混淆配置文件中添加了-keep class com.adobe.xmp.** { *; }
,结果还是没用。查看一下生成的apk中的dex里有没有
是有的,那为什么会找不到呢?看了看错误中的/system/framework/framework.jar
,立即将framework.jar
从手机中导了出来,但是里面居然是空的,只有个文件夹META-INF
中包含一个MANIFEST.MF
文件,那么问题也不在这里。仔细想了想,会不会是因为是魅族改过framework层呢,或者说是手机被root过而受了影响呢?于是乎借了一部root过的Nexus 5装上了验证Demo进行测试,结果是能正常运行并展示结果,由此排除了受root而导致的接口方法找不到。
结语
基于以上验证结果,浅显地认为是魅族的ROM导致的吧ㄟ( ▔, ▔ )ㄏ
v1.5.2