一、概述
在Android2.2中,Camera的应用程序并不支持将GPS信息写入到JPEG文件中,但如果要实现这个功能,有如下两种方式:
1、修改底层camera驱动。在拍照时,一般都是使用硬件去进行JPEG编码,这样就需要修改JPEG编码器,使其可以将GPS信息写入JPEG文件的头部,即EXIF部分。这种方式使用与手机驱动开发者。
2、修改camera应用程序。Camera应用程序本身不支持该功能,但是android系统中提供了支持该功能的类—— ExifInterface。本文介绍如何使用该类进行GPS信息的写入。这种方法的不足在于,每次写入GPS功能,都会把原有的JPEG文件读出,修改 了Exif header部分后再写入文件。
二、实现GPS写入功能
首先来看看文件ImageManager.java,该文件位于:
/package/apps/Camera/src/com/android/camera/
该文件中,有个addImage()函数,其定义为:
public static Uri addImage(ContentResolver cr, String title, long dateTaken, Location location, String directory, String filename, Bitmap source, byte[] jpegData, int[] degree) { 。。。。。。 String filePath = directory + "/" + filename; 。。。。。。 if (location != null) { values.put(Images.Media.LATITUDE, location.getLatitude()); values.put(Images.Media.LONGITUDE, location.getLongitude()); } } return cr.insert(STORAGE_URI, values); }
public static Uri addImage(ContentResolver cr, String title, long dateTaken, Location location, String directory, String filename, Bitmap source, byte[] jpegData, int[] degree) { 。。。。。。 String filePath = directory + "/" + filename; 。。。。。。 if (location != null) { values.put(Images.Media.LATITUDE, location.getLatitude()); values.put(Images.Media.LONGITUDE, location.getLongitude()); ExifInterface exif = null; try { exif = new ExifInterface(filePath); } catch (IOException ex) { Log.e(TAG, "cannot read exif", ex); } exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, Double.toString(location.getLatitude())); exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, Double.toString(location.getLongitude())); try{ if(exif != null) exif.saveAttributes(); } catch (IOException ex) { Log.e(TAG, "Fail to exif.saveAttributes()."); } } return cr.insert(STORAGE_URI, values); }
三、分析GPS写入功能的实现
首先看看类ExifInterface的构造函数,其位于:
/framework/base/media/java/android/media/ ExifInterface.java
其具体实现为:
public ExifInterface(String filename) throws IOException { mFilename = filename; loadAttributes(); }
private void loadAttributes() throws IOException { // format of string passed from native C code: // "attrCnt attr1=valueLen value1attr2=value2Len value2..." // example: // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO" mAttributes = new HashMap<String, String>(); String attrStr; synchronized (sLock) { attrStr = getAttributesNative(mFilename); } …… }
该函数从文件中读取Exif信息,并将其写入mAttributes中。函数
getAttributesNative(mFilename),调用了JNI接口,其定义位于:/external/jhead/main.c
static JNINativeMethod methods[] = { {"saveAttributesNative", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)saveAttributes }, {"getAttributesNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAttributes }, {"appendThumbnailNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)appendThumbnail }, {"commitChangesNative", "(Ljava/lang/String;)V", (void*)commitChanges }, {"getThumbnailNative", "(Ljava/lang/String;)[B", (void*)getThumbnail }, };
public void setAttribute(String tag, String value) { mAttributes.put(tag, value); }
向mAttributes写入对应的项,比如经度和纬度信息。
最重要的函数saveAttributes(),它也是调用JNI接口。它负责将所有的Exif项写入到JPEG文件中。由于时间关系,就不做介绍了,具体代码请大家自己看,有问题的话,一起讨论。