Android下的EXIF是什么
一.什么是Exif
Exif(ExchangeableImageFile可交换图像文件)是一种图象文件格式,它的数据存储与JPEG格式是完全相同的。实际上Exif格式就是在JPEG格式头部插入了数码照片的信息,包括拍摄时的光圈、快门、白平衡、ISO、焦距、日期时间等各种和拍摄条件以及相机品牌、型号、色彩编码、拍摄时录制的声音以及全球定位系统(GPS)、缩略图等。简单地说,Exif=JPEG+拍摄参数。因此,你可以利用任何可以查看JPEG文件的看图软件浏览Exif格式的照片,但并不是所有的图形程序都能处理Exif信息。
所有的JPEG文件以字符串“0xFFD8”开头,并以字符串“0xFFD9”结束。文件头中有一系列“0xFF??”格式的字符串,称为“标识”,用来标记JPEG文件的信息段。“0xFFD8”表示图像信息开始,“0xFFD9”表示图像信息结束,这两个标识后面没有信息,而其它标识紧跟一些信息字符。
0xFFE0--0xFFEF之间的标识符称为“应用标记”,没有被常规JPEG文件利用,Exif正是利用这些信息串记录拍摄信息如快门速度、光圈值等,甚至可以包括全球定位信息。按照Exif2.1标准对这些标识符的定义,数码相机可以把各种拍摄信息记入数码图像中,应用软件可以读取这些数据,再按照Exif2.1标准,检索出它们的具体含义,一般而言包括以下一些信息:
ImageDescription图像描述、来源.指生成图像的工具
Artist作者有些相机可以输入使用者的名字
Make生产者指产品生产厂家
Model型号指设备型号
Orientation方向有的相机支持,有的不支持
XResolution/YResolutionX/Y方向分辨率本栏目已有专门条目解释此问题。
ResolutionUnit分辨率单位一般为PPI
Software软件显示固件Firmware版本
DateTime日期和时间
YCbCrPositioning色相定位
ExifOffsetExif信息位置,定义Exif在信息在文件中的写入,有些软件不显示。
ExposureTime曝光时间即快门速度
FNumber光圈系数
ExposureProgram曝光程序指程序式自动曝光的设置,各相机不同,可能是SutterPriority(快门优先)、AperturePriority(快门优先)等等。
ISOspeedratings感光度
ExifVersionExif版本
DateTimeOriginal创建时间
DateTimeDigitized数字化时间
ComponentsConfiguration图像构造(多指色彩组合方案)
CompressedBitsPerPixel(BPP)压缩时每像素色彩位指压缩程度
ExposureBiasValue曝光补偿。
MaxApertureValue最大光圈
MeteringMode测光方式,平均式测光、中央重点测光、点测光等。
Lightsource光源指白平衡设置
Flash是否使用闪光灯。
FocalLength焦距,一般显示镜头物理焦距,有些软件可以定义一个系数,从而显示相当于35mm相机的焦距MakerNote(UserComment)作者标记、说明、记录
FlashPixVersionFlashPix版本(个别机型支持)
ColorSpace色域、色彩空间
ExifImageWidth(PixelXDimension)图像宽度指横向像素数
ExifImageLength(PixelYDimension)图像高度指纵向像素数
InteroperabilityIFD通用性扩展项定义指针和TIFF文件相关,具体含义不详
FileSource源文件Compression压缩比。
二.Camera中拍照流程
在AndroidCamera程序开发过程中,要用到Exif相关的知识,如果处理不当,会导致拍摄的JPEG图片无法正常浏览。
在Froyo(Android2.2)源码中的Camera应用是不对Exif信息进行写操作,而只是读操作,对于Exif的写操作是交给Camera硬件抽象层去完成,这是google的设计逻辑。但是不同的Android平台及其相关子平台,再加上不同的Camera应用,相互交替,排列组合,或许会出现这样一种情况:底层没有去写Exif,而上层应用也没有写Exif信息,那么图片的显示信息将会丢失。其中影响最为严重的是Orientation这个参数。
Froyocamera的逻辑是这样的:
在Camera这个Activity中,有一个内部类ImageCapture,其中包含一个重要的方法:
privatevoidcapture(){ //Setrotation. mParameters.setRotation(mLastOrientation); .................... ..................... mCameraDevice.setParameters(mParameters); mCameraDevice.takePicture(mShutterCallback,mRawPictureCallback,mPostViewPictureCallback,newJpegPictureCallback(loc)); }
大致流程是这样的:
1.将拍照时相机的方向添加进Camera.Parameters的实例中;
2.将全部相机拍照参数传给android.hardware.Camera的对象;
3.调用方法takePicture,并设置好非常重要的4个callback;
4.生成Exif数据的事情就由HAL来完成;
5.第4个callback返回数据(这个callback是最重要的,而且是不可缺省的,也就是说前3个callback设置成Null也不会影响拍照功能),见如下代码:
privatefinalclassJpegPictureCallbackimplementsPictureCallback{ publicvoidonPictureTaken(finalbyte[]jpegData,finalandroid.hardware.Cameracamera){ //jpegData为JPEG数据,是由HAL层根据应用传输的各种参数(即Camera.Parameters的实例)以及JPEG压缩算法生成的。 mImageCapture.storeImage(jpegData,camera,mLocation); } }
三.Exif使用方法及代码优化方案
什么地方用到Exif信息呢?我遇到的至少有如下这么几个地方:
1.生成右上角所略图;
2.图片显示应用,例如android自带的gallery3d应用;
3.图片回显;
4.短(彩)信等需要添加camera附件的应用.
看看源码:ImageManager中是这样读取Exif方向参数的。
publicstaticintgetExifOrientation(Stringfilepath){ intdegree=0; ExifInterfaceexif=null; try{ exif=newExifInterface(filepath); }catch(IOExceptionex){ Log.e(TAG,"cannotreadexif",ex); } if(exif!=null){ intorientation=exif.getAttributeInt( ExifInterface.TAG_ORIENTATION,-1); if(orientation!=-1){ //Weonlyrecognizeasubsetoforientationtagvalues. switch(orientation){ caseExifInterface.ORIENTATION_ROTATE_90: degree=90; break; caseExifInterface.ORIENTATION_ROTATE_180: degree=180; break; caseExifInterface.ORIENTATION_ROTATE_270: degree=270; break; } } } returndegree; }
这个方法可以进一步优化,从而对于Exif信息的写入不再依赖底层。那就是比较一下传输给底层的orientation与实际返回的是否相等,不相等就是底层写入Exif信息出错,我们就可以在应用层进行修正。
可以添加一个判断分支如下:(其中EXIF_ORIENTATION是我们缓存的应用传给底层的值)。
elseif(orientation==0&&EXIF_ORIENTATION!=0){ switch(EXIF_ORIENTATION){ case90: orientation=ExifInterface.ORIENTATION_ROTATE_90; degree=90; break; case180: orientation=ExifInterface.ORIENTATION_ROTATE_180; degree=180; break; case270: orientation=ExifInterface.ORIENTATION_ROTATE_270; degree=270; break; } exif.setAttribute(ExifInterface.TAG_ORIENTATION,Integer.toString(orientation)); try{ exif.saveAttributes(); }catch(IOExceptione){ Log.e(TAG,"cannotsaveexif",e); } }
在应用层对于Exif的操作是通过android.media.ExifInterface接口完成的。
通过publicvoidsetAttribute(Stringtag,Stringvalue)来设置,而获取可以通过publicintgetAttributeInt(Stringtag,intdefaultValue)和publicStringgetAttribute(Stringtag)两种方法都可以,getAttributeInt重载方法一第二个参数为我们设置的默认值,如果成功则返回相应Tag的值;特定的整数内容为该方法直接返回值。而重载方法二该方法直接返回结果,如果失败则为null。
以上就是本文的全部内容,希望对大家的学习有所帮助。